diff --git a/schemars/src/generator.rs b/schemars/src/generator.rs index 52c5b41..6bde36f 100644 --- a/schemars/src/generator.rs +++ b/schemars/src/generator.rs @@ -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, - definitions: Map, + definitions: Map, } impl SchemaGenerator { @@ -18,23 +17,24 @@ impl SchemaGenerator { } } - pub fn subschema_for(&mut self) -> Schema { + pub fn subschema_for(&mut self) -> Schema { if !T::generates_ref_schema() { return T::make_schema(self); } - let type_id = TypeId::of::(); + 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::(); 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(&mut self) -> Schema { + pub fn root_schema_for(&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(mut self) -> Schema { + pub fn into_root_schema_for(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(&mut self) -> String { + fn make_unique_name(&mut self) -> String { let base_name = T::schema_name(); // TODO remove namespace, remove special chars if self.names.contains(&base_name) { diff --git a/schemars/src/main.rs b/schemars/src/main.rs index f88bcbf..b5feaf0 100644 --- a/schemars/src/main.rs +++ b/schemars/src/main.rs @@ -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::(); let json = serde_json::to_string(&schema)?; println!("{}", json); diff --git a/schemars/src/make_schema.rs b/schemars/src/make_schema.rs index e66caac..db78ede 100644 --- a/schemars/src/make_schema.rs +++ b/schemars/src/make_schema.rs @@ -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::()) + } + 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::().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 MakeSchema for [T; 0] { macro_rules! array_impls { ($($len:tt)+) => { $( - impl MakeSchema for [T; $len] + impl 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, - T: MakeSchema + 'static, + T: MakeSchema, { fn make_schema(gen: &mut SchemaGenerator) -> Schema { @@ -176,7 +190,7 @@ map_impl!( MakeSchema f ////////// OPTION ////////// -impl MakeSchema for Option { +impl MakeSchema for Option { fn make_schema(gen: &mut SchemaGenerator) -> Schema { match gen.subschema_for::() { 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::()