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::schema::*;
|
||||
use crate::{visit::*, JsonSchema, Map};
|
||||
use dyn_clone::DynClone;
|
||||
use std::{any::Any, fmt::Debug};
|
||||
|
||||
/// Settings to customize how Schemas are generated.
|
||||
///
|
||||
|
@ -26,8 +28,8 @@ pub struct SchemaSettings {
|
|||
///
|
||||
/// Defaults to `"http://json-schema.org/draft-07/schema#"`.
|
||||
pub meta_schema: Option<String>,
|
||||
/// TODO document
|
||||
pub visitors: Visitors,
|
||||
/// A list of visitors that get applied to all generated root schemas.
|
||||
pub visitors: Vec<Box<dyn Visitor2>>,
|
||||
_hidden: (),
|
||||
}
|
||||
|
||||
|
@ -45,7 +47,7 @@ impl SchemaSettings {
|
|||
option_add_null_type: true,
|
||||
definitions_path: "#/definitions/".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: (),
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +59,7 @@ impl SchemaSettings {
|
|||
option_add_null_type: true,
|
||||
definitions_path: "#/definitions/".to_owned(),
|
||||
meta_schema: Some("https://json-schema.org/draft/2019-09/schema".to_owned()),
|
||||
visitors: Visitors::default(),
|
||||
visitors: Vec::default(),
|
||||
_hidden: (),
|
||||
}
|
||||
}
|
||||
|
@ -72,12 +74,12 @@ impl SchemaSettings {
|
|||
"https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema"
|
||||
.to_owned(),
|
||||
),
|
||||
visitors: Visitors(vec![
|
||||
visitors: vec![
|
||||
Box::new(RemoveRefSiblings),
|
||||
Box::new(ReplaceBoolSchemas {
|
||||
skip_additional_properties: true,
|
||||
}),
|
||||
]),
|
||||
],
|
||||
_hidden: (),
|
||||
}
|
||||
}
|
||||
|
@ -99,9 +101,9 @@ impl SchemaSettings {
|
|||
self
|
||||
}
|
||||
|
||||
/// TODO document
|
||||
pub fn with_visitor(mut self, visitor: impl Visitor + 'static) -> Self {
|
||||
self.visitors.0.push(Box::new(visitor));
|
||||
/// Appends the given visitor to the list of [visitors](SchemaSettings::visitors) for these `SchemaSettings`.
|
||||
pub fn with_visitor(mut self, visitor: impl Visitor + Debug + DynClone + 'static) -> Self {
|
||||
self.visitors.push(Box::new(visitor));
|
||||
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.
|
||||
///
|
||||
/// # Example
|
||||
|
@ -236,7 +234,7 @@ impl SchemaGenerator {
|
|||
schema,
|
||||
};
|
||||
|
||||
for visitor in &mut self.settings.visitors.0 {
|
||||
for visitor in &mut self.settings.visitors {
|
||||
visitor.visit_root_schema(&mut root)
|
||||
}
|
||||
|
||||
|
@ -256,7 +254,7 @@ impl SchemaGenerator {
|
|||
schema,
|
||||
};
|
||||
|
||||
for visitor in &mut self.settings.visitors.0 {
|
||||
for visitor in &mut self.settings.visitors {
|
||||
visitor.visit_root_schema(&mut root)
|
||||
}
|
||||
|
||||
|
@ -323,62 +321,39 @@ impl SchemaGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
/// TODO document
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ReplaceBoolSchemas {
|
||||
pub skip_additional_properties: bool,
|
||||
/// A [Visitor](Visitor) which implements additional traits required to be included in a [SchemaSettings].
|
||||
///
|
||||
/// You will rarely need to use this trait directly as it is automatically implemented for any type which implements all of:
|
||||
/// - [`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 {
|
||||
fn visit_schema(&mut self, schema: &mut Schema) {
|
||||
if let Schema::Bool(b) = *schema {
|
||||
*schema = Schema::Bool(b).into_object().into()
|
||||
}
|
||||
dyn_clone::clone_trait_object!(Visitor2);
|
||||
|
||||
visit_schema(self, schema)
|
||||
}
|
||||
|
||||
fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
|
||||
if self.skip_additional_properties {
|
||||
let mut additional_properties = None;
|
||||
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]),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> Visitor2 for T
|
||||
where
|
||||
T: Visitor + Debug + DynClone + Any,
|
||||
{
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
match self {
|
||||
Schema::Object(o) => o,
|
||||
|
|
|
@ -1,34 +1,38 @@
|
|||
use crate::schema::{RootSchema, Schema, SchemaObject, SingleOrVec};
|
||||
use dyn_clone::DynClone;
|
||||
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) {
|
||||
visit_root_schema(self, root)
|
||||
}
|
||||
|
||||
/// TODO document
|
||||
fn visit_schema(&mut self, schema: &mut Schema) {
|
||||
visit_schema(self, schema)
|
||||
}
|
||||
|
||||
/// TODO document
|
||||
fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
|
||||
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) {
|
||||
v.visit_schema_object(&mut root.schema);
|
||||
visit_map_values(v, &mut root.definitions);
|
||||
}
|
||||
|
||||
/// TODO document
|
||||
pub fn visit_schema<V: Visitor + ?Sized>(v: &mut V, schema: &mut Schema) {
|
||||
if let Schema::Object(schema) = schema {
|
||||
v.visit_schema_object(schema)
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO document
|
||||
pub fn visit_schema_object<V: Visitor + ?Sized>(v: &mut V, schema: &mut SchemaObject) {
|
||||
if let Some(sub) = &mut schema.subschemas {
|
||||
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