Add documentation comments, rename Visitor2

This commit is contained in:
Graham Esau 2020-09-24 20:32:35 +01:00
parent 0c02525fb9
commit 460976e765
6 changed files with 92 additions and 42 deletions

View file

@ -14,8 +14,8 @@
- `SchemaSettings` no longer implements `PartialEq` - `SchemaSettings` no longer implements `PartialEq`
- `SchemaGenerator::into_definitions()` - this has been superseded by `SchemaGenerator::take_definitions()` - `SchemaGenerator::into_definitions()` - this has been superseded by `SchemaGenerator::take_definitions()`
### Changed (**BREAKING CHANGES**): ### Changed:
- Minimum supported rust version is now 1.36.0 - **BREAKING CHANGE** Minimum supported rust version is now 1.36.0
### Fixed: ### Fixed:
- **BREAKING CHANGE** unknown items in `#[schemars(...)]` attributes now cause a compilation error (https://github.com/GREsau/schemars/issues/18) - **BREAKING CHANGE** unknown items in `#[schemars(...)]` attributes now cause a compilation error (https://github.com/GREsau/schemars/issues/18)

View file

@ -1,3 +1,12 @@
/*!
JSON Schema generator and settings.
This module is useful if you want more control over how the schema generated then the [`schema_for!`] macro gives you.
There are two main types in this module:two main types in this module:
* [`SchemaSettings`], which defines what JSON Schema features should be used when generating schemas (for example, how `Option`s should be represented).
* [`SchemaGenerator`], which manages the generation of a schema document.
*/
use crate::flatten::Merge; use crate::flatten::Merge;
use crate::schema::*; use crate::schema::*;
use crate::{visit::*, JsonSchema, Map}; use crate::{visit::*, JsonSchema, Map};
@ -29,7 +38,7 @@ 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>,
/// A list of visitors that get applied to all generated root schemas. /// A list of visitors that get applied to all generated root schemas.
pub visitors: Vec<Box<dyn Visitor2>>, pub visitors: Vec<Box<dyn GenVisitor>>,
_hidden: (), _hidden: (),
} }
@ -105,7 +114,7 @@ impl SchemaSettings {
} }
/// Appends the given visitor to the list of [visitors](SchemaSettings::visitors) for these `SchemaSettings`. /// 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 { pub fn with_visitor(mut self, visitor: impl Visitor + Debug + Clone + 'static) -> Self {
self.visitors.push(Box::new(visitor)); self.visitors.push(Box::new(visitor));
self self
} }
@ -225,7 +234,7 @@ impl SchemaGenerator {
} }
/// Returns an iterator over the [visitors](SchemaSettings::visitors) being used by this `SchemaGenerator`. /// Returns an iterator over the [visitors](SchemaSettings::visitors) being used by this `SchemaGenerator`.
pub fn visitors_mut(&mut self) -> impl Iterator<Item = &mut dyn Visitor2> { pub fn visitors_mut(&mut self) -> impl Iterator<Item = &mut dyn GenVisitor> {
self.settings.visitors.iter_mut().map(|v| v.as_mut()) self.settings.visitors.iter_mut().map(|v| v.as_mut())
} }
@ -336,31 +345,31 @@ impl SchemaGenerator {
/// - [`Visitor`] /// - [`Visitor`]
/// - [`std::fmt::Debug`] /// - [`std::fmt::Debug`]
/// - [`std::any::Any`] (implemented for all `'static` types) /// - [`std::any::Any`] (implemented for all `'static` types)
/// - [`dyn_clone::DynClone`] (or [`std::clone::Clone`]) /// - [`std::clone::Clone`]
/// ///
/// # Example /// # Example
/// ``` /// ```
/// use schemars::visit::Visitor; /// use schemars::visit::Visitor;
/// use schemars::gen::Visitor2; /// use schemars::gen::GenVisitor;
/// ///
/// #[derive(Debug, Clone)] /// #[derive(Debug, Clone)]
/// struct MyVisitor; /// struct MyVisitor;
/// ///
/// impl Visitor for MyVisitor { } /// impl Visitor for MyVisitor { }
/// ///
/// let v: &dyn Visitor2 = &MyVisitor; /// let v: &dyn GenVisitor = &MyVisitor;
/// assert_eq!(v.as_any().is::<MyVisitor>(), true); /// assert!(v.as_any().is::<MyVisitor>());
/// ``` /// ```
pub trait Visitor2: Visitor + Debug + DynClone + Any { pub trait GenVisitor: Visitor + Debug + DynClone + Any {
/// Upcasts this visitor into an `Any`, which can be used to inspect and manipulate it as its concrete type. /// 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; fn as_any(&self) -> &dyn Any;
} }
dyn_clone::clone_trait_object!(Visitor2); dyn_clone::clone_trait_object!(GenVisitor);
impl<T> Visitor2 for T impl<T> GenVisitor for T
where where
T: Visitor + Debug + DynClone + Any, T: Visitor + Debug + Clone + Any,
{ {
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self

View file

@ -227,7 +227,8 @@ pub type Map<K, V> = indexmap::IndexMap<K, V>;
pub type Set<T> = std::collections::BTreeSet<T>; pub type Set<T> = std::collections::BTreeSet<T>;
/// A view into a single entry in a map, which may either be vacant or occupied. /// A view into a single entry in a map, which may either be vacant or occupied.
/// This is constructed from the `entry` method on `BTreeMap` or `IndexMap` //
/// This is constructed from the `entry` method on `BTreeMap` or `IndexMap`,
/// depending on whether the `preserve_order` feature flag is set. /// depending on whether the `preserve_order` feature flag is set.
#[cfg(not(feature = "preserve_order"))] #[cfg(not(feature = "preserve_order"))]
pub type MapEntry<'a, K, V> = std::collections::btree_map::Entry<'a, K, V>; pub type MapEntry<'a, K, V> = std::collections::btree_map::Entry<'a, K, V>;
@ -239,11 +240,8 @@ mod json_schema_impls;
#[macro_use] #[macro_use]
mod macros; mod macros;
/// JSON Schema generator and settings.
pub mod gen; pub mod gen;
/// JSON Schema types.
pub mod schema; pub mod schema;
/// TODO document
pub mod visit; pub mod visit;
#[cfg(feature = "schemars_derive")] #[cfg(feature = "schemars_derive")]

View file

@ -1,6 +1,6 @@
/// Generates a [`RootSchema`](schema::RootSchema) for the given type using default settings. /// Generates a [`RootSchema`](crate::schema::RootSchema) for the given type using default settings.
/// ///
/// The type must implement [`JsonSchema`]. /// The type must implement [`JsonSchema`](crate::JsonSchema).
/// ///
/// # Example /// # Example
/// ``` /// ```

View file

@ -1,3 +1,7 @@
/*!
JSON Schema types.
*/
#[cfg(feature = "impl_json_schema")] #[cfg(feature = "impl_json_schema")]
use crate as schemars; use crate as schemars;
#[cfg(feature = "impl_json_schema")] #[cfg(feature = "impl_json_schema")]

View file

@ -1,37 +1,70 @@
/*!
Contains the [`Visitor`] trait, used to recursively modify a constructed schema and its subschemas.
Sometimes you may want to apply a change to a schema, as well as all schemas contained within it.
The easiest way to achieve this is by defining a type that implements [`Visitor`].
All methods of `Visitor` have a default implementation that makes no change but recursively visits all subschemas.
When overriding one of these methods, you will *usually* want to still call this default implementation.
# Example
To add a custom property to all schemas:
```
use schemars::schema::SchemaObject;
use schemars::visit::{Visitor, visit_schema_object};
pub struct MyVisitor;
impl Visitor for MyVisitor {
fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
// First, make our change to this schema
schema.extensions.insert("my_property".to_string(), serde_json::json!("hello world"));
// Then delegate to default implementation to visit any subschemas
visit_schema_object(self, schema);
}
}
```
*/
use crate::schema::{RootSchema, Schema, SchemaObject, SingleOrVec}; use crate::schema::{RootSchema, Schema, SchemaObject, SingleOrVec};
/// TODO document /// Trait used to recursively modify a constructed schema and its subschemas.
pub trait Visitor { pub trait Visitor {
/// TODO document /// Override this method to modify a [`RootSchema`] and (optionally) its subschemas.
///
/// When overriding this method, you will usually want to call the [`visit_root_schema`] function to visit subschemas.
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 /// Override this method to modify a [`Schema`] and (optionally) its subschemas.
///
/// When overriding this method, you will usually want to call the [`visit_schema`] function to visit subschemas.
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 /// Override this method to modify a [`SchemaObject`] and (optionally) its subschemas.
///
/// When overriding this method, you will usually want to call the [`visit_schema_object`] function to visit subschemas.
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)
} }
} }
/// TODO document /// Visits all subschemas of the [`RootSchema`].
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 /// Visits all subschemas of the [`Schema`].
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 /// Visits all subschemas of the [`SchemaObject`].
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);
@ -89,10 +122,12 @@ fn visit_single_or_vec<V: Visitor + ?Sized>(v: &mut V, target: &mut Option<Singl
} }
} }
/// TODO document /// This visitor will replace all boolean JSON Schemas with equivalent object schemas.
///
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support booleans as schemas.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ReplaceBoolSchemas { pub struct ReplaceBoolSchemas {
/// TODO document /// When set to `true`, a schema's `additionalProperties` property will not be changed from a boolean.
pub skip_additional_properties: bool, pub skip_additional_properties: bool,
} }
@ -106,25 +141,27 @@ impl Visitor for ReplaceBoolSchemas {
} }
fn visit_schema_object(&mut self, schema: &mut SchemaObject) { fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
if self.skip_additional_properties { if !self.skip_additional_properties {
if let Some(obj) = &mut schema.object { visit_schema_object(self, schema);
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; return;
} }
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;
} }
} }
} }
visit_schema_object(self, schema);
} }
} }
/// TODO document /// This visitor will restructure JSON Schema objects so that the `$ref` property will never appear alongside any other properties.
///
/// This is useful for dialects of JSON Schema (e.g. Draft 7) that do not support other properties alongside `$ref`.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RemoveRefSiblings; pub struct RemoveRefSiblings;
@ -147,10 +184,12 @@ impl Visitor for RemoveRefSiblings {
} }
} }
/// TODO document /// This visitor will remove the `examples` schema property and (if present) set its first value as the `example` property.
///
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `examples` property.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SetSingleExample { pub struct SetSingleExample {
/// TODO document /// When set to `true`, the `examples` property will not be removed, but its first value will still be copied to `example`.
pub retain_examples: bool, pub retain_examples: bool,
} }