Remove various 'static bounds
Currently using an unreliable hack - assuming type name is unique D:
This commit is contained in:
parent
4f9956631e
commit
21a29dc6b5
3 changed files with 31 additions and 16 deletions
|
@ -1,6 +1,5 @@
|
|||
use crate::make_schema::MakeSchema;
|
||||
use crate::make_schema::{MakeSchema, SchemaTypeId};
|
||||
use crate::schema::*;
|
||||
use core::any::TypeId;
|
||||
use std::collections::BTreeMap as Map;
|
||||
use std::collections::BTreeSet as Set;
|
||||
use std::iter::FromIterator;
|
||||
|
@ -8,7 +7,7 @@ use std::iter::FromIterator;
|
|||
#[derive(Debug, Default)]
|
||||
pub struct SchemaGenerator {
|
||||
names: Set<String>,
|
||||
definitions: Map<TypeId, (String, Schema)>,
|
||||
definitions: Map<SchemaTypeId, (String, Schema)>,
|
||||
}
|
||||
|
||||
impl SchemaGenerator {
|
||||
|
@ -18,23 +17,24 @@ impl SchemaGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn subschema_for<T: MakeSchema + 'static>(&mut self) -> Schema {
|
||||
pub fn subschema_for<T: ?Sized + MakeSchema>(&mut self) -> Schema {
|
||||
if !T::generates_ref_schema() {
|
||||
return T::make_schema(self);
|
||||
}
|
||||
|
||||
let type_id = TypeId::of::<T>();
|
||||
let type_id = T::schema_type_id();
|
||||
// TODO is there a nicer way to do this?
|
||||
if !self.definitions.contains_key(&type_id) {
|
||||
let name = self.make_unique_name::<T>();
|
||||
self.names.insert(name.clone());
|
||||
// insert into definitions BEFORE calling make_schema to avoid infinite recursion
|
||||
let dummy = Schema::Bool(false);
|
||||
self.definitions.insert(type_id, (name.clone(), dummy));
|
||||
self.definitions
|
||||
.insert(type_id.clone(), (name.clone(), dummy));
|
||||
|
||||
let schema = T::make_schema(self);
|
||||
self.definitions
|
||||
.entry(type_id)
|
||||
.entry(type_id.clone())
|
||||
.and_modify(|(_, s)| *s = schema);
|
||||
}
|
||||
let ref name = self.definitions.get(&type_id).unwrap().0;
|
||||
|
@ -52,7 +52,7 @@ impl SchemaGenerator {
|
|||
Map::from_iter(self.definitions.into_iter().map(|(_, v)| v))
|
||||
}
|
||||
|
||||
pub fn root_schema_for<T: MakeSchema>(&mut self) -> Schema {
|
||||
pub fn root_schema_for<T: ?Sized + MakeSchema>(&mut self) -> Schema {
|
||||
let schema = T::make_schema(self);
|
||||
if let Schema::Object(mut o) = schema {
|
||||
o.schema = Some("http://json-schema.org/draft-07/schema#".to_owned());
|
||||
|
@ -63,7 +63,7 @@ impl SchemaGenerator {
|
|||
schema
|
||||
}
|
||||
|
||||
pub fn into_root_schema_for<T: MakeSchema>(mut self) -> Schema {
|
||||
pub fn into_root_schema_for<T: ?Sized + MakeSchema>(mut self) -> Schema {
|
||||
let schema = T::make_schema(&mut self);
|
||||
if let Schema::Object(mut o) = schema {
|
||||
o.schema = Some("http://json-schema.org/draft-07/schema#".to_owned());
|
||||
|
@ -74,7 +74,7 @@ impl SchemaGenerator {
|
|||
schema
|
||||
}
|
||||
|
||||
fn make_unique_name<T: MakeSchema>(&mut self) -> String {
|
||||
fn make_unique_name<T: ?Sized + MakeSchema>(&mut self) -> String {
|
||||
let base_name = T::schema_name();
|
||||
// TODO remove namespace, remove special chars
|
||||
if self.names.contains(&base_name) {
|
||||
|
|
|
@ -35,7 +35,8 @@ struct User {
|
|||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let schema = <&str>::make_schema();
|
||||
let gen = generator::SchemaGenerator::new();
|
||||
let schema = gen.into_root_schema_for::<str>();
|
||||
let json = serde_json::to_string(&schema)?;
|
||||
println!("{}", json);
|
||||
|
||||
|
|
|
@ -3,12 +3,26 @@ use crate::schema::*;
|
|||
use serde_json::json;
|
||||
use std::collections::BTreeMap as Map;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct SchemaTypeId(&'static str);
|
||||
|
||||
pub trait MakeSchema {
|
||||
fn schema_type_id() -> SchemaTypeId {
|
||||
// FIXME schema name might not be unique!
|
||||
SchemaTypeId(core::any::type_name::<Self>())
|
||||
}
|
||||
|
||||
fn schema_name() -> String {
|
||||
// TODO this requires nightly
|
||||
// It's probably worth removing the default implemenation,
|
||||
// then make every impl in this file set an explicit name
|
||||
// Or maybe hide it under feature flag?
|
||||
core::any::type_name::<Self>().to_owned()
|
||||
}
|
||||
|
||||
fn generates_ref_schema() -> bool {
|
||||
// TODO default this to true as it's safer
|
||||
// But this would mean every impl in this file needs to override it :(
|
||||
false
|
||||
}
|
||||
|
||||
|
@ -93,7 +107,7 @@ impl<T> MakeSchema for [T; 0] {
|
|||
macro_rules! array_impls {
|
||||
($($len:tt)+) => {
|
||||
$(
|
||||
impl<T: MakeSchema + 'static> MakeSchema for [T; $len]
|
||||
impl<T: MakeSchema> MakeSchema for [T; $len]
|
||||
{
|
||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
let mut extra_properties = Map::new();
|
||||
|
@ -124,7 +138,7 @@ macro_rules! seq_impl {
|
|||
($($desc:tt)+) => {
|
||||
impl $($desc)+
|
||||
where
|
||||
T: MakeSchema + 'static,
|
||||
T: MakeSchema,
|
||||
{
|
||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema
|
||||
{
|
||||
|
@ -152,7 +166,7 @@ macro_rules! map_impl {
|
|||
impl $($desc)+
|
||||
where
|
||||
K: Into<String>,
|
||||
T: MakeSchema + 'static,
|
||||
T: MakeSchema,
|
||||
{
|
||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema
|
||||
{
|
||||
|
@ -176,7 +190,7 @@ map_impl!(<K, T: Eq + core::hash::Hash, H: core::hash::BuildHasher> MakeSchema f
|
|||
|
||||
////////// OPTION //////////
|
||||
|
||||
impl<T: MakeSchema + 'static> MakeSchema for Option<T> {
|
||||
impl<T: MakeSchema> MakeSchema for Option<T> {
|
||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
match gen.subschema_for::<T>() {
|
||||
Schema::Bool(true) => true.into(),
|
||||
|
@ -196,7 +210,7 @@ macro_rules! deref_impl {
|
|||
($($desc:tt)+) => {
|
||||
impl $($desc)+
|
||||
where
|
||||
T: MakeSchema + 'static,
|
||||
T: MakeSchema,
|
||||
{
|
||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
gen.subschema_for::<T>()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue