Split Visitor into two traits
This commit is contained in:
		
							parent
							
								
									656a70e02c
								
							
						
					
					
						commit
						a02947462d
					
				
					 3 changed files with 121 additions and 74 deletions
				
			
		| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
use crate::flatten::Merge;
 | 
					use crate::flatten::Merge;
 | 
				
			||||||
use crate::schema::*;
 | 
					use crate::schema::*;
 | 
				
			||||||
use crate::{visit::*, JsonSchema, Map};
 | 
					use crate::{visit::*, JsonSchema, Map};
 | 
				
			||||||
 | 
					use dyn_clone::DynClone;
 | 
				
			||||||
 | 
					use std::{any::Any, fmt::Debug};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Settings to customize how Schemas are generated.
 | 
					/// Settings to customize how Schemas are generated.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -26,8 +28,8 @@ pub struct SchemaSettings {
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// Defaults to `"http://json-schema.org/draft-07/schema#"`.
 | 
					    /// Defaults to `"http://json-schema.org/draft-07/schema#"`.
 | 
				
			||||||
    pub meta_schema: Option<String>,
 | 
					    pub meta_schema: Option<String>,
 | 
				
			||||||
    /// TODO document
 | 
					    /// A list of visitors that get applied to all generated root schemas.
 | 
				
			||||||
    pub visitors: Visitors,
 | 
					    pub visitors: Vec<Box<dyn Visitor2>>,
 | 
				
			||||||
    _hidden: (),
 | 
					    _hidden: (),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +47,7 @@ impl SchemaSettings {
 | 
				
			||||||
            option_add_null_type: true,
 | 
					            option_add_null_type: true,
 | 
				
			||||||
            definitions_path: "#/definitions/".to_owned(),
 | 
					            definitions_path: "#/definitions/".to_owned(),
 | 
				
			||||||
            meta_schema: Some("http://json-schema.org/draft-07/schema#".to_owned()),
 | 
					            meta_schema: Some("http://json-schema.org/draft-07/schema#".to_owned()),
 | 
				
			||||||
            visitors: Visitors(vec![Box::new(RemoveRefSiblings)]),
 | 
					            visitors: vec![Box::new(RemoveRefSiblings)],
 | 
				
			||||||
            _hidden: (),
 | 
					            _hidden: (),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -57,7 +59,7 @@ impl SchemaSettings {
 | 
				
			||||||
            option_add_null_type: true,
 | 
					            option_add_null_type: true,
 | 
				
			||||||
            definitions_path: "#/definitions/".to_owned(),
 | 
					            definitions_path: "#/definitions/".to_owned(),
 | 
				
			||||||
            meta_schema: Some("https://json-schema.org/draft/2019-09/schema".to_owned()),
 | 
					            meta_schema: Some("https://json-schema.org/draft/2019-09/schema".to_owned()),
 | 
				
			||||||
            visitors: Visitors::default(),
 | 
					            visitors: Vec::default(),
 | 
				
			||||||
            _hidden: (),
 | 
					            _hidden: (),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -72,12 +74,12 @@ impl SchemaSettings {
 | 
				
			||||||
                "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema"
 | 
					                "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema"
 | 
				
			||||||
                    .to_owned(),
 | 
					                    .to_owned(),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            visitors: Visitors(vec![
 | 
					            visitors: vec![
 | 
				
			||||||
                Box::new(RemoveRefSiblings),
 | 
					                Box::new(RemoveRefSiblings),
 | 
				
			||||||
                Box::new(ReplaceBoolSchemas {
 | 
					                Box::new(ReplaceBoolSchemas {
 | 
				
			||||||
                    skip_additional_properties: true,
 | 
					                    skip_additional_properties: true,
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
            ]),
 | 
					            ],
 | 
				
			||||||
            _hidden: (),
 | 
					            _hidden: (),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -99,9 +101,9 @@ impl SchemaSettings {
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// TODO document
 | 
					    /// Appends the given visitor to the list of [visitors](SchemaSettings::visitors) for these `SchemaSettings`.
 | 
				
			||||||
    pub fn with_visitor(mut self, visitor: impl Visitor + 'static) -> Self {
 | 
					    pub fn with_visitor(mut self, visitor: impl Visitor + Debug + DynClone + 'static) -> Self {
 | 
				
			||||||
        self.visitors.0.push(Box::new(visitor));
 | 
					        self.visitors.push(Box::new(visitor));
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,10 +113,6 @@ impl SchemaSettings {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// TODO document
 | 
					 | 
				
			||||||
#[derive(Debug, Clone, Default)]
 | 
					 | 
				
			||||||
pub struct Visitors(Vec<Box<dyn Visitor>>);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The main type used to generate JSON Schemas.
 | 
					/// The main type used to generate JSON Schemas.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Example
 | 
					/// # Example
 | 
				
			||||||
| 
						 | 
					@ -236,7 +234,7 @@ impl SchemaGenerator {
 | 
				
			||||||
            schema,
 | 
					            schema,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for visitor in &mut self.settings.visitors.0 {
 | 
					        for visitor in &mut self.settings.visitors {
 | 
				
			||||||
            visitor.visit_root_schema(&mut root)
 | 
					            visitor.visit_root_schema(&mut root)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -256,7 +254,7 @@ impl SchemaGenerator {
 | 
				
			||||||
            schema,
 | 
					            schema,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for visitor in &mut self.settings.visitors.0 {
 | 
					        for visitor in &mut self.settings.visitors {
 | 
				
			||||||
            visitor.visit_root_schema(&mut root)
 | 
					            visitor.visit_root_schema(&mut root)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -323,62 +321,39 @@ impl SchemaGenerator {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// TODO document
 | 
					/// A [Visitor](Visitor) which implements additional traits required to be included in a [SchemaSettings].
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					///
 | 
				
			||||||
pub struct ReplaceBoolSchemas {
 | 
					/// You will rarely need to use this trait directly as it is automatically implemented for any type which implements all of:
 | 
				
			||||||
    pub skip_additional_properties: bool,
 | 
					/// - [`Visitor`]
 | 
				
			||||||
 | 
					/// - [`std::fmt::Debug`]
 | 
				
			||||||
 | 
					/// - [`std::any::Any`] (implemented for all `'static` types)
 | 
				
			||||||
 | 
					/// - [`dyn_clone::DynClone`] (or [`std::clone::Clone`])
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Example
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					/// use schemars::visit::Visitor;
 | 
				
			||||||
 | 
					/// use schemars::gen::Visitor2;
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// #[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					/// struct MyVisitor;
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// impl Visitor for MyVisitor { }
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// let v: &dyn Visitor2 = &MyVisitor;
 | 
				
			||||||
 | 
					/// assert_eq!(v.as_any().is::<MyVisitor>(), true);
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					pub trait Visitor2: Visitor + Debug + DynClone + Any {
 | 
				
			||||||
 | 
					    /// Upcasts this visitor into an `Any`, which can be used to inspect and manipulate it as its concrete type.
 | 
				
			||||||
 | 
					    fn as_any(&self) -> &dyn Any;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Visitor for ReplaceBoolSchemas {
 | 
					dyn_clone::clone_trait_object!(Visitor2);
 | 
				
			||||||
    fn visit_schema(&mut self, schema: &mut Schema) {
 | 
					 | 
				
			||||||
        if let Schema::Bool(b) = *schema {
 | 
					 | 
				
			||||||
            *schema = Schema::Bool(b).into_object().into()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        visit_schema(self, schema)
 | 
					impl<T> Visitor2 for T
 | 
				
			||||||
    }
 | 
					where
 | 
				
			||||||
 | 
					    T: Visitor + Debug + DynClone + Any,
 | 
				
			||||||
    fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
 | 
					{
 | 
				
			||||||
        if self.skip_additional_properties {
 | 
					    fn as_any(&self) -> &dyn Any {
 | 
				
			||||||
            let mut additional_properties = None;
 | 
					        self
 | 
				
			||||||
            if let Some(obj) = &mut schema.object {
 | 
					 | 
				
			||||||
                if let Some(ap) = &obj.additional_properties {
 | 
					 | 
				
			||||||
                    if let Schema::Bool(_) = ap.as_ref() {
 | 
					 | 
				
			||||||
                        additional_properties = obj.additional_properties.take();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            visit_schema_object(self, schema);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if additional_properties.is_some() {
 | 
					 | 
				
			||||||
                schema.object().additional_properties = additional_properties;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            visit_schema_object(self, schema);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// TODO document
 | 
					 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					 | 
				
			||||||
pub struct RemoveRefSiblings;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Visitor for RemoveRefSiblings {
 | 
					 | 
				
			||||||
    fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
 | 
					 | 
				
			||||||
        visit_schema_object(self, schema);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if let Some(reference) = schema.reference.take() {
 | 
					 | 
				
			||||||
            if schema == &SchemaObject::default() {
 | 
					 | 
				
			||||||
                schema.reference = Some(reference);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                let ref_schema = Schema::new_ref(reference);
 | 
					 | 
				
			||||||
                let all_of = &mut schema.subschemas().all_of;
 | 
					 | 
				
			||||||
                match all_of {
 | 
					 | 
				
			||||||
                    Some(vec) => vec.push(ref_schema),
 | 
					 | 
				
			||||||
                    None => *all_of = Some(vec![ref_schema]),
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,18 @@ impl Schema {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// TODO document
 | 
					    /// Converts the given schema (if it is a boolean schema) into an equivalent schema object.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// If the given schema is already a schema object, this has no effect.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Example
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
 | 
					    /// use schemars::schema::{Schema, SchemaObject};
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// let bool_schema = Schema::Bool(true);
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// assert_eq!(bool_schema.into_object(), SchemaObject::default());
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
    pub fn into_object(self) -> SchemaObject {
 | 
					    pub fn into_object(self) -> SchemaObject {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            Schema::Object(o) => o,
 | 
					            Schema::Object(o) => o,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,34 +1,38 @@
 | 
				
			||||||
use crate::schema::{RootSchema, Schema, SchemaObject, SingleOrVec};
 | 
					use crate::schema::{RootSchema, Schema, SchemaObject, SingleOrVec};
 | 
				
			||||||
use dyn_clone::DynClone;
 | 
					 | 
				
			||||||
use std::fmt::Debug;
 | 
					use std::fmt::Debug;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait Visitor: Debug + DynClone {
 | 
					/// TODO document
 | 
				
			||||||
 | 
					pub trait Visitor {
 | 
				
			||||||
 | 
					    /// TODO document
 | 
				
			||||||
    fn visit_root_schema(&mut self, root: &mut RootSchema) {
 | 
					    fn visit_root_schema(&mut self, root: &mut RootSchema) {
 | 
				
			||||||
        visit_root_schema(self, root)
 | 
					        visit_root_schema(self, root)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// TODO document
 | 
				
			||||||
    fn visit_schema(&mut self, schema: &mut Schema) {
 | 
					    fn visit_schema(&mut self, schema: &mut Schema) {
 | 
				
			||||||
        visit_schema(self, schema)
 | 
					        visit_schema(self, schema)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// TODO document
 | 
				
			||||||
    fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
 | 
					    fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
 | 
				
			||||||
        visit_schema_object(self, schema)
 | 
					        visit_schema_object(self, schema)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dyn_clone::clone_trait_object!(Visitor);
 | 
					/// TODO document
 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn visit_root_schema<V: Visitor + ?Sized>(v: &mut V, root: &mut RootSchema) {
 | 
					pub fn visit_root_schema<V: Visitor + ?Sized>(v: &mut V, root: &mut RootSchema) {
 | 
				
			||||||
    v.visit_schema_object(&mut root.schema);
 | 
					    v.visit_schema_object(&mut root.schema);
 | 
				
			||||||
    visit_map_values(v, &mut root.definitions);
 | 
					    visit_map_values(v, &mut root.definitions);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// TODO document
 | 
				
			||||||
pub fn visit_schema<V: Visitor + ?Sized>(v: &mut V, schema: &mut Schema) {
 | 
					pub fn visit_schema<V: Visitor + ?Sized>(v: &mut V, schema: &mut Schema) {
 | 
				
			||||||
    if let Schema::Object(schema) = schema {
 | 
					    if let Schema::Object(schema) = schema {
 | 
				
			||||||
        v.visit_schema_object(schema)
 | 
					        v.visit_schema_object(schema)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// TODO document
 | 
				
			||||||
pub fn visit_schema_object<V: Visitor + ?Sized>(v: &mut V, schema: &mut SchemaObject) {
 | 
					pub fn visit_schema_object<V: Visitor + ?Sized>(v: &mut V, schema: &mut SchemaObject) {
 | 
				
			||||||
    if let Some(sub) = &mut schema.subschemas {
 | 
					    if let Some(sub) = &mut schema.subschemas {
 | 
				
			||||||
        visit_vec(v, &mut sub.all_of);
 | 
					        visit_vec(v, &mut sub.all_of);
 | 
				
			||||||
| 
						 | 
					@ -85,3 +89,60 @@ fn visit_single_or_vec<V: Visitor + ?Sized>(v: &mut V, target: &mut Option<Singl
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// TODO document
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct ReplaceBoolSchemas {
 | 
				
			||||||
 | 
					    pub skip_additional_properties: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Visitor for ReplaceBoolSchemas {
 | 
				
			||||||
 | 
					    fn visit_schema(&mut self, schema: &mut Schema) {
 | 
				
			||||||
 | 
					        visit_schema(self, schema);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Schema::Bool(b) = *schema {
 | 
				
			||||||
 | 
					            *schema = Schema::Bool(b).into_object().into()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
 | 
				
			||||||
 | 
					        if self.skip_additional_properties {
 | 
				
			||||||
 | 
					            if let Some(obj) = &mut schema.object {
 | 
				
			||||||
 | 
					                if let Some(ap) = &obj.additional_properties {
 | 
				
			||||||
 | 
					                    if let Schema::Bool(_) = ap.as_ref() {
 | 
				
			||||||
 | 
					                        let additional_properties = obj.additional_properties.take();
 | 
				
			||||||
 | 
					                        visit_schema_object(self, schema);
 | 
				
			||||||
 | 
					                        schema.object().additional_properties = additional_properties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        return;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        visit_schema_object(self, schema);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// TODO document
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct RemoveRefSiblings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Visitor for RemoveRefSiblings {
 | 
				
			||||||
 | 
					    fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
 | 
				
			||||||
 | 
					        visit_schema_object(self, schema);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(reference) = schema.reference.take() {
 | 
				
			||||||
 | 
					            if schema == &SchemaObject::default() {
 | 
				
			||||||
 | 
					                schema.reference = Some(reference);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                let ref_schema = Schema::new_ref(reference);
 | 
				
			||||||
 | 
					                let all_of = &mut schema.subschemas().all_of;
 | 
				
			||||||
 | 
					                match all_of {
 | 
				
			||||||
 | 
					                    Some(vec) => vec.push(ref_schema),
 | 
				
			||||||
 | 
					                    None => *all_of = Some(vec![ref_schema]),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue