Wrap comment lines at 100 chars

This commit is contained in:
Graham Esau 2024-08-30 13:05:33 +01:00
parent 0672c862c8
commit 5d58a4d3f0
9 changed files with 147 additions and 92 deletions

View file

@ -21,7 +21,8 @@ type CowStr = alloc::borrow::Cow<'static, str>;
/// Settings to customize how Schemas are generated. /// Settings to customize how Schemas are generated.
/// ///
/// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added. /// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
/// If you rely on generated schemas conforming to draft 2020-12, consider using the [`SchemaSettings::draft2020_12()`] method. /// If you rely on generated schemas conforming to draft 2020-12, consider using the
/// [`SchemaSettings::draft2020_12()`] method.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[non_exhaustive] #[non_exhaustive]
pub struct SchemaSettings { pub struct SchemaSettings {
@ -35,7 +36,8 @@ pub struct SchemaSettings {
/// ///
/// Defaults to `true`. /// Defaults to `true`.
pub option_add_null_type: bool, pub option_add_null_type: bool,
/// A JSON pointer to the expected location of referenceable subschemas within the resulting root schema. /// A JSON pointer to the expected location of referenceable subschemas within the resulting
/// root schema.
/// ///
/// A single leading `#` and/or single trailing `/` are ignored. /// A single leading `#` and/or single trailing `/` are ignored.
/// ///
@ -57,7 +59,8 @@ pub struct SchemaSettings {
impl Default for SchemaSettings { impl Default for SchemaSettings {
/// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added. /// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
/// If you rely on generated schemas conforming to draft 2020-12, consider using the [`SchemaSettings::draft2020_12()`] method. /// If you rely on generated schemas conforming to draft 2020-12, consider using the
/// [`SchemaSettings::draft2020_12()`] method.
fn default() -> SchemaSettings { fn default() -> SchemaSettings {
SchemaSettings::draft2020_12() SchemaSettings::draft2020_12()
} }
@ -145,7 +148,8 @@ impl SchemaSettings {
self self
} }
/// Appends the given transform to the list of [transforms](SchemaSettings::transforms) for these `SchemaSettings`. /// Appends the given transform to the list of [transforms](SchemaSettings::transforms) for
/// these `SchemaSettings`.
pub fn with_transform(mut self, transform: impl Transform + Clone + 'static + Send) -> Self { pub fn with_transform(mut self, transform: impl Transform + Clone + 'static + Send) -> Self {
self.transforms.push(Box::new(transform)); self.transforms.push(Box::new(transform));
self self
@ -222,13 +226,15 @@ impl SchemaGenerator {
&self.settings &self.settings
} }
/// Generates a JSON Schema for the type `T`, and returns either the schema itself or a `$ref` schema referencing `T`'s schema. /// Generates a JSON Schema for the type `T`, and returns either the schema itself or a `$ref`
/// schema referencing `T`'s schema.
/// ///
/// If `T` is not [inlined](JsonSchema::always_inline_schema), this will add `T`'s schema to this generator's definitions, and /// If `T` is not [inlined](JsonSchema::always_inline_schema), this will add `T`'s schema to
/// return a `$ref` schema referencing that schema. Otherwise, this method behaves identically to [`JsonSchema::json_schema`]. /// this generator's definitions, and return a `$ref` schema referencing that schema.
/// Otherwise, this method behaves identically to [`JsonSchema::json_schema`].
/// ///
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then this method will /// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then
/// add them to the `SchemaGenerator`'s schema definitions. /// this method will add them to the `SchemaGenerator`'s schema definitions.
pub fn subschema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema { pub fn subschema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
let id = T::schema_id(); let id = T::schema_id();
let return_ref = !T::always_inline_schema() let return_ref = !T::always_inline_schema()
@ -278,40 +284,44 @@ impl SchemaGenerator {
self.definitions.insert(name.into(), schema.to_value()); self.definitions.insert(name.into(), schema.to_value());
} }
/// Borrows the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that have been generated. /// Borrows the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that
/// have been generated.
/// ///
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas /// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the
/// themselves. /// values are the schemas themselves.
pub fn definitions(&self) -> &JsonMap<String, Value> { pub fn definitions(&self) -> &JsonMap<String, Value> {
&self.definitions &self.definitions
} }
/// Mutably borrows the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that have been generated. /// Mutably borrows the collection of all [non-inlined](JsonSchema::always_inline_schema)
/// schemas that have been generated.
/// ///
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas /// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the
/// themselves. /// values are the schemas themselves.
pub fn definitions_mut(&mut self) -> &mut JsonMap<String, Value> { pub fn definitions_mut(&mut self) -> &mut JsonMap<String, Value> {
&mut self.definitions &mut self.definitions
} }
/// Returns the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that have been generated, /// Returns the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that
/// leaving an empty `Map` in its place. /// have been generated, leaving an empty `Map` in its place.
/// ///
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas /// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the
/// themselves. /// values are the schemas themselves.
pub fn take_definitions(&mut self) -> JsonMap<String, Value> { pub fn take_definitions(&mut self) -> JsonMap<String, Value> {
core::mem::take(&mut self.definitions) core::mem::take(&mut self.definitions)
} }
/// Returns an iterator over the [transforms](SchemaSettings::transforms) being used by this `SchemaGenerator`. /// Returns an iterator over the [transforms](SchemaSettings::transforms) being used by this
/// `SchemaGenerator`.
pub fn transforms_mut(&mut self) -> impl Iterator<Item = &mut dyn GenTransform> { pub fn transforms_mut(&mut self) -> impl Iterator<Item = &mut dyn GenTransform> {
self.settings.transforms.iter_mut().map(Box::as_mut) self.settings.transforms.iter_mut().map(Box::as_mut)
} }
/// Generates a JSON Schema for the type `T`. /// Generates a JSON Schema for the type `T`.
/// ///
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then this method will /// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then
/// include them in the returned `Schema` at the [definitions path](SchemaSettings::definitions_path) (by default `"$defs"`). /// this method will include them in the returned `Schema` at the [definitions
/// path](SchemaSettings::definitions_path) (by default `"$defs"`).
pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema { pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
let mut schema = self.json_schema_internal::<T>(T::schema_id()); let mut schema = self.json_schema_internal::<T>(T::schema_id());
@ -333,8 +343,9 @@ impl SchemaGenerator {
/// Consumes `self` and generates a JSON Schema for the type `T`. /// Consumes `self` and generates a JSON Schema for the type `T`.
/// ///
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then this method will /// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then
/// include them in the returned `Schema` at the [definitions path](SchemaSettings::definitions_path) (by default `"$defs"`). /// this method will include them in the returned `Schema` at the [definitions
/// path](SchemaSettings::definitions_path) (by default `"$defs"`).
pub fn into_root_schema_for<T: ?Sized + JsonSchema>(mut self) -> Schema { pub fn into_root_schema_for<T: ?Sized + JsonSchema>(mut self) -> Schema {
let mut schema = self.json_schema_internal::<T>(T::schema_id()); let mut schema = self.json_schema_internal::<T>(T::schema_id());
@ -357,8 +368,9 @@ impl SchemaGenerator {
/// Generates a JSON Schema for the given example value. /// Generates a JSON Schema for the given example value.
/// ///
/// If the value implements [`JsonSchema`], then prefer using the [`root_schema_for()`](Self::root_schema_for()) /// If the value implements [`JsonSchema`], then prefer using the
/// function which will generally produce a more precise schema, particularly when the value contains any enums. /// [`root_schema_for()`](Self::root_schema_for()) function which will generally produce a
/// more precise schema, particularly when the value contains any enums.
/// ///
/// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`]. /// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`].
pub fn root_schema_for_value<T: ?Sized + Serialize>( pub fn root_schema_for_value<T: ?Sized + Serialize>(
@ -388,8 +400,9 @@ impl SchemaGenerator {
/// Consumes `self` and generates a JSON Schema for the given example value. /// Consumes `self` and generates a JSON Schema for the given example value.
/// ///
/// If the value implements [`JsonSchema`], then prefer using the [`into_root_schema_for()!`](Self::into_root_schema_for()) /// If the value implements [`JsonSchema`], then prefer using the
/// function which will generally produce a more precise schema, particularly when the value contains any enums. /// [`into_root_schema_for()!`](Self::into_root_schema_for()) function which will generally
/// produce a more precise schema, particularly when the value contains any enums.
/// ///
/// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`]. /// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`].
pub fn into_root_schema_for_value<T: ?Sized + Serialize>( pub fn into_root_schema_for_value<T: ?Sized + Serialize>(
@ -511,9 +524,11 @@ fn json_pointer_mut<'a>(
Some(object) Some(object)
} }
/// A [`Transform`] which implements additional traits required to be included in a [`SchemaSettings`]. /// A [`Transform`] 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: /// You will rarely need to use this trait directly as it is automatically implemented for any type
/// which implements all of:
/// - [`Transform`] /// - [`Transform`]
/// - [`std::any::Any`] (implemented for all `'static` types) /// - [`std::any::Any`] (implemented for all `'static` types)
/// - [`std::clone::Clone`] /// - [`std::clone::Clone`]
@ -537,7 +552,8 @@ fn json_pointer_mut<'a>(
/// assert!(v.as_any().is::<MyTransform>()); /// assert!(v.as_any().is::<MyTransform>());
/// ``` /// ```
pub trait GenTransform: Transform + DynClone + Any + Send { pub trait GenTransform: Transform + DynClone + Any + Send {
/// Upcasts this transform into an [`Any`], which can be used to inspect and manipulate it as its concrete type. /// Upcasts this transform into an [`Any`], which can be used to inspect and manipulate it as
/// its concrete type.
/// ///
/// # Example /// # Example
/// To remove a specific transform from an instance of `SchemaSettings`: /// To remove a specific transform from an instance of `SchemaSettings`:
@ -556,7 +572,8 @@ pub trait GenTransform: Transform + DynClone + Any + Send {
/// ``` /// ```
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
/// Mutably upcasts this transform into an [`Any`], which can be used to inspect and manipulate it as its concrete type. /// Mutably upcasts this transform into an [`Any`], which can be used to inspect and manipulate
/// it as its concrete type.
/// ///
/// # Example /// # Example
/// To modify a specific transform in an instance of `SchemaSettings`: /// To modify a specific transform in an instance of `SchemaSettings`:

View file

@ -109,7 +109,8 @@ pub mod r#gen {
/// assert_eq!(NonGenericType::schema_id(), <&mut NonGenericType>::schema_id()); /// assert_eq!(NonGenericType::schema_id(), <&mut NonGenericType>::schema_id());
/// ``` /// ```
/// ///
/// But generic type parameters which may affect the generated schema should typically be included in the name/ID: /// But generic type parameters which may affect the generated schema should typically be included
/// in the name/ID:
/// ``` /// ```
/// use schemars::{SchemaGenerator, Schema, JsonSchema, json_schema}; /// use schemars::{SchemaGenerator, Schema, JsonSchema, json_schema};
/// use std::{borrow::Cow, marker::PhantomData}; /// use std::{borrow::Cow, marker::PhantomData};
@ -138,14 +139,14 @@ pub mod r#gen {
/// ///
/// assert_eq!(<GenericType<i32>>::schema_id(), <&mut GenericType<&i32>>::schema_id()); /// assert_eq!(<GenericType<i32>>::schema_id(), <&mut GenericType<&i32>>::schema_id());
/// ``` /// ```
///
pub trait JsonSchema { pub trait JsonSchema {
/// Whether JSON Schemas generated for this type should be included directly in parent schemas, rather than being /// Whether JSON Schemas generated for this type should be included directly in parent schemas,
/// re-used where possible using the `$ref` keyword. /// rather than being re-used where possible using the `$ref` keyword.
/// ///
/// For trivial types (such as primitives), this should return `true`. For more complex types, it should return `false`. /// For trivial types (such as primitives), this should return `true`. For more complex types,
/// For recursive types, this **must** return `false` to prevent infinite cycles when generating schemas. /// it should return `false`. For recursive types, this **must** return `false` to prevent
/// infinite cycles when generating schemas.
/// ///
/// By default, this returns `false`. /// By default, this returns `false`.
fn always_inline_schema() -> bool { fn always_inline_schema() -> bool {
@ -154,24 +155,27 @@ pub trait JsonSchema {
/// The name of the generated JSON Schema. /// The name of the generated JSON Schema.
/// ///
/// This is used as the title for root schemas, and the key within the root's `definitions` property for subschemas. /// This is used as the title for root schemas, and the key within the root's `definitions`
/// property for subschemas.
fn schema_name() -> Cow<'static, str>; fn schema_name() -> Cow<'static, str>;
/// Returns a string that uniquely identifies the schema produced by this type. /// Returns a string that uniquely identifies the schema produced by this type.
/// ///
/// This does not have to be a human-readable string, and the value will not itself be included in generated schemas. /// This does not have to be a human-readable string, and the value will not itself be included
/// If two types produce different schemas, then they **must** have different `schema_id()`s, /// in generated schemas. If two types produce different schemas, then they **must** have
/// but two types that produce identical schemas should *ideally* have the same `schema_id()`. /// different `schema_id()`s, but two types that produce identical schemas should *ideally*
/// have the same `schema_id()`.
/// ///
/// The default implementation returns the same value as [`schema_name()`](JsonSchema::schema_name). /// The default implementation returns the same value as
/// [`schema_name()`](JsonSchema::schema_name).
fn schema_id() -> Cow<'static, str> { fn schema_id() -> Cow<'static, str> {
Self::schema_name() Self::schema_name()
} }
/// Generates a JSON Schema for this type. /// Generates a JSON Schema for this type.
/// ///
/// If the returned schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then this method will /// If the returned schema depends on any [non-inlined](JsonSchema::always_inline_schema)
/// add them to the [`SchemaGenerator`]'s schema definitions. /// schemas, then this method will add them to the [`SchemaGenerator`]'s schema definitions.
/// ///
/// This should not return a `$ref` schema. /// This should not return a `$ref` schema.
fn json_schema(generator: &mut SchemaGenerator) -> Schema; fn json_schema(generator: &mut SchemaGenerator) -> Schema;

View file

@ -52,9 +52,10 @@ macro_rules! schema_for {
/// Generates a [`Schema`](crate::Schema) for the given example value using default settings. /// Generates a [`Schema`](crate::Schema) for the given example value using default settings.
/// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added. /// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
/// ///
/// The value must implement [`Serialize`](serde::Serialize). If the value also implements [`JsonSchema`](crate::JsonSchema), /// The value must implement [`Serialize`](serde::Serialize). If the value also implements
/// then prefer using the [`schema_for!(Type)`](schema_for) macro which will generally produce a more precise schema, /// [`JsonSchema`](crate::JsonSchema), then prefer using the [`schema_for!(Type)`](schema_for) macro
/// particularly when the value contains any enums. /// which will generally produce a more precise schema, particularly when the value contains any
/// enums.
/// ///
/// If the `Serialize` implementation of the value decides to fail, this macro will panic. /// If the `Serialize` implementation of the value decides to fail, this macro will panic.
/// For a non-panicking alternative, create a [`SchemaGenerator`](crate::SchemaGenerator) and use /// For a non-panicking alternative, create a [`SchemaGenerator`](crate::SchemaGenerator) and use
@ -80,9 +81,11 @@ macro_rules! schema_for_value {
}; };
} }
/// Construct a [`Schema`](crate::Schema) from a JSON literal. This can either be a JSON object, or a boolean (`true` or `false`). /// Construct a [`Schema`](crate::Schema) from a JSON literal. This can either be a JSON object, or
/// a boolean (`true` or `false`).
/// ///
/// You can interpolate variables or expressions into a JSON object using the same rules as the [`serde_json::json`] macro. /// You can interpolate variables or expressions into a JSON object using the same rules as the
/// [`serde_json::json`] macro.
/// ///
/// # Example /// # Example
/// ``` /// ```

View file

@ -9,7 +9,8 @@ use serde_json::{Map, Value};
/// A JSON Schema. /// A JSON Schema.
/// ///
/// This wraps a JSON [`Value`] that must be either an [object](Value::Object) or a [bool](Value::Bool). /// This wraps a JSON [`Value`] that must be either an [object](Value::Object) or a
/// [bool](Value::Bool).
/// ///
/// A custom JSON schema can be created using the [`json_schema!`](crate::json_schema) macro: /// A custom JSON schema can be created using the [`json_schema!`](crate::json_schema) macro:
/// ``` /// ```
@ -20,8 +21,11 @@ use serde_json::{Map, Value};
/// }); /// });
/// ``` /// ```
/// ///
/// Because a `Schema` is a thin wrapper around a `Value`, you can also use [`TryFrom::try_from`]/[`TryInto::try_into`] to create a `Schema` from an existing `Value`. /// Because a `Schema` is a thin wrapper around a `Value`, you can also use
/// This operation is fallible, because only [objects](Value::Object) and [bools](Value::Bool) can be converted in this way. /// [`TryFrom::try_from`]/[`TryInto::try_into`] to create a `Schema` from an existing `Value`.
/// This operation is fallible, because only [objects](Value::Object) and [bools](Value::Bool) can
/// be converted in this way.
///
/// ``` /// ```
/// use schemars::{Schema, json_schema}; /// use schemars::{Schema, json_schema};
/// use serde_json::json; /// use serde_json::json;
@ -42,10 +46,11 @@ use serde_json::{Map, Value};
/// ///
/// let mut json_object = json!({"type": ["object", "null"]}); /// let mut json_object = json!({"type": ["object", "null"]});
/// let object_schema_mut: &mut Schema = (&mut json_object).try_into().unwrap(); /// let object_schema_mut: &mut Schema = (&mut json_object).try_into().unwrap();
///
/// ``` /// ```
/// ///
/// Similarly, you can use [`From`]/[`Into`] to (infallibly) create a `Schema` from an existing [`Map<String, Value>`] or [`bool`]. /// Similarly, you can use [`From`]/[`Into`] to (infallibly) create a `Schema` from an existing
/// [`Map<String, Value>`] or [`bool`].
///
/// ``` /// ```
/// use schemars::{Schema, json_schema}; /// use schemars::{Schema, json_schema};
/// use serde_json::{Map, json}; /// use serde_json::{Map, json};
@ -101,12 +106,14 @@ impl Schema {
self.0.as_bool() self.0.as_bool()
} }
/// If the `Schema`'s underlying JSON value is an object, borrows the object as a `Map` of properties. /// If the `Schema`'s underlying JSON value is an object, borrows the object as a `Map` of
/// properties.
pub fn as_object(&self) -> Option<&Map<String, Value>> { pub fn as_object(&self) -> Option<&Map<String, Value>> {
self.0.as_object() self.0.as_object()
} }
/// If the `Schema`'s underlying JSON value is an object, mutably borrows the object as a `Map` of properties. /// If the `Schema`'s underlying JSON value is an object, mutably borrows the object as a `Map`
/// of properties.
pub fn as_object_mut(&mut self) -> Option<&mut Map<String, Value>> { pub fn as_object_mut(&mut self) -> Option<&mut Map<String, Value>> {
self.0.as_object_mut() self.0.as_object_mut()
} }
@ -124,10 +131,12 @@ impl Schema {
self.0 self.0
} }
/// Converts the `Schema` (if it wraps a bool value) into an equivalent object schema. Then mutably borrows the object as a `Map` of properties. /// Converts the `Schema` (if it wraps a bool value) into an equivalent object schema. Then
/// mutably borrows the object as a `Map` of properties.
/// ///
/// `true` is transformed into an empty schema `{}`, which successfully validates against all possible values. /// `true` is transformed into an empty schema `{}`, which successfully validates against all
/// `false` is transformed into the schema `{"not": {}}`, which does not successfully validate against any value. /// possible values. `false` is transformed into the schema `{"not": {}}`, which does not
/// successfully validate against any value.
#[allow(clippy::missing_panics_doc)] #[allow(clippy::missing_panics_doc)]
pub fn ensure_object(&mut self) -> &mut Map<String, Value> { pub fn ensure_object(&mut self) -> &mut Map<String, Value> {
if let Some(b) = self.as_bool() { if let Some(b) = self.as_bool() {
@ -145,11 +154,13 @@ impl Schema {
/// Inserts a property into the schema, replacing any previous value. /// Inserts a property into the schema, replacing any previous value.
/// ///
/// If the schema wraps a bool value, it will first be converted into an equivalent object schema. /// If the schema wraps a bool value, it will first be converted into an equivalent object
/// schema.
/// ///
/// If the schema did not have this key present, `None` is returned. /// If the schema did not have this key present, `None` is returned.
/// ///
/// If the schema did have this key present, the value is updated, and the old value is returned. /// If the schema did have this key present, the value is updated, and the old value is
/// returned.
/// ///
/// # Example /// # Example
/// ``` /// ```
@ -166,7 +177,8 @@ impl Schema {
self.ensure_object().insert(k, v) self.ensure_object().insert(k, v)
} }
/// If the `Schema`'s underlying JSON value is an object, gets a reference to that object's value for the given key. /// If the `Schema`'s underlying JSON value is an object, gets a reference to that object's
/// value for the given key.
/// ///
/// This always returns `None` for bool schemas. /// This always returns `None` for bool schemas.
/// ///
@ -190,7 +202,8 @@ impl Schema {
self.0.as_object().and_then(|o| o.get(key)) self.0.as_object().and_then(|o| o.get(key))
} }
/// If the `Schema`'s underlying JSON value is an object, removes and returns its value for the given key. /// If the `Schema`'s underlying JSON value is an object, removes and returns its value for the
/// given key.
/// ///
/// This always returns `None` for bool schemas, without modifying them. /// This always returns `None` for bool schemas, without modifying them.
/// ///
@ -202,7 +215,6 @@ impl Schema {
/// let mut schema = json_schema!({"type": "array"}); /// let mut schema = json_schema!({"type": "array"});
/// assert_eq!(schema.remove("type"), Some(json!("array"))); /// assert_eq!(schema.remove("type"), Some(json!("array")));
/// assert_eq!(schema, json_schema!({})); /// assert_eq!(schema, json_schema!({}));
///
/// ``` /// ```
pub fn remove<Q>(&mut self, key: &Q) -> Option<Value> pub fn remove<Q>(&mut self, key: &Q) -> Option<Value>
where where

View file

@ -117,11 +117,13 @@ use serde_json::{json, Map, Value};
pub trait Transform { pub trait Transform {
/// Applies the transform to the given [`Schema`]. /// Applies the transform to the given [`Schema`].
/// ///
/// When overriding this method, you may want to call the [`transform_subschemas`] function to also transform any subschemas. /// When overriding this method, you may want to call the [`transform_subschemas`] function to
/// also transform any subschemas.
fn transform(&mut self, schema: &mut Schema); fn transform(&mut self, schema: &mut Schema);
// Not public API // Not public API
// Hack to enable implementing Debug on Box<dyn GenTransform> even though closures don't implement Debug // Hack to enable implementing Debug on Box<dyn GenTransform> even though closures don't
// implement Debug
#[doc(hidden)] #[doc(hidden)]
fn _debug_type_name(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn _debug_type_name(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(core::any::type_name::<Self>()) f.write_str(core::any::type_name::<Self>())
@ -167,7 +169,8 @@ pub fn transform_subschemas<T: Transform + ?Sized>(t: &mut T, schema: &mut Schem
} }
} }
} }
// Support `items` array even though this is not allowed in draft 2020-12 (see above comment) // Support `items` array even though this is not allowed in draft 2020-12 (see above
// comment)
"items" => { "items" => {
if let Some(array) = value.as_array_mut() { if let Some(array) = value.as_array_mut() {
for value in array { for value in array {
@ -220,9 +223,11 @@ pub(crate) fn transform_immediate_subschemas<T: Transform + ?Sized>(
} }
} }
/// A helper struct that can wrap a non-recursive [`Transform`] (i.e. one that does not apply to subschemas) into a recursive one. /// A helper struct that can wrap a non-recursive [`Transform`] (i.e. one that does not apply to
/// subschemas) into a recursive one.
/// ///
/// Its implementation of `Transform` will first apply the inner transform to the "parent" schema, and then its subschemas (and their subschemas, and so on). /// Its implementation of `Transform` will first apply the inner transform to the "parent" schema,
/// and then its subschemas (and their subschemas, and so on).
/// ///
/// # Example /// # Example
/// ``` /// ```
@ -267,10 +272,12 @@ where
/// Replaces boolean JSON Schemas with equivalent object schemas. /// Replaces boolean JSON Schemas with equivalent object schemas.
/// This also applies to subschemas. /// This also applies to subschemas.
/// ///
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support booleans as 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 {
/// When set to `true`, a schema's `additionalProperties` property will not be changed from a boolean. /// 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,
} }
@ -294,10 +301,11 @@ impl Transform for ReplaceBoolSchemas {
} }
} }
/// Restructures JSON Schema objects so that the `$ref` property will never appear alongside any other properties. /// Restructures JSON Schema objects so that the `$ref` property will never appear alongside any
/// This also applies to subschemas. /// other properties. This also applies to subschemas.
/// ///
/// This is useful for versions of JSON Schema (e.g. Draft 7) that do not support other properties alongside `$ref`. /// This is useful for versions 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;
@ -318,10 +326,11 @@ impl Transform for RemoveRefSiblings {
} }
} }
/// Removes the `examples` schema property and (if present) set its first value as the `example` property. /// Removes the `examples` schema property and (if present) set its first value as the `example`
/// This also applies to subschemas. /// property. This also applies to subschemas.
/// ///
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `examples` 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;
@ -340,7 +349,8 @@ impl Transform for SetSingleExample {
/// Replaces the `const` schema property with a single-valued `enum` property. /// Replaces the `const` schema property with a single-valued `enum` property.
/// This also applies to subschemas. /// This also applies to subschemas.
/// ///
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `const` property. /// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `const`
/// property.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ReplaceConstValue; pub struct ReplaceConstValue;
@ -357,9 +367,11 @@ impl Transform for ReplaceConstValue {
/// Rename the `prefixItems` schema property to `items`. /// Rename the `prefixItems` schema property to `items`.
/// This also applies to subschemas. /// This also applies to subschemas.
/// ///
/// If the schema contains both `prefixItems` and `items`, then this additionally renames `items` to `additionalItems`. /// If the schema contains both `prefixItems` and `items`, then this additionally renames `items` to
/// `additionalItems`.
/// ///
/// This is useful for versions of JSON Schema (e.g. Draft 7) that do not support the `prefixItems` property. /// This is useful for versions of JSON Schema (e.g. Draft 7) that do not support the `prefixItems`
/// property.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ReplacePrefixItems; pub struct ReplacePrefixItems;

View file

@ -21,7 +21,6 @@ struct MyStruct {
} }
/// # A Unit /// # A Unit
///
#[derive(JsonSchema)] #[derive(JsonSchema)]
struct MyUnitStruct; struct MyUnitStruct;

View file

@ -89,8 +89,9 @@ impl CommonAttrs {
"extend" => { "extend" => {
for ex in parse_extensions(meta, cx).into_iter().flatten() { for ex in parse_extensions(meta, cx).into_iter().flatten() {
// This is O(n^2) but should be fine with the typically small number of extensions. // This is O(n^2) but should be fine with the typically small number of
// If this does become a problem, it can be changed to use IndexMap, or a separate Map with cloned keys. // extensions. If this does become a problem, it can be changed to use
// IndexMap, or a separate Map with cloned keys.
if self.extensions.iter().any(|e| e.0 == ex.key_str) { if self.extensions.iter().any(|e| e.0 == ex.key_str) {
cx.error_spanned_by( cx.error_spanned_by(
ex.key_lit, ex.key_lit,

View file

@ -6,7 +6,8 @@ use syn::{Attribute, Data, Field, Meta, Variant};
use super::get_meta_items; use super::get_meta_items;
// List of keywords that can appear in #[serde(...)]/#[schemars(...)] attributes which we want serde_derive_internals to parse for us. // List of keywords that can appear in #[serde(...)]/#[schemars(...)] attributes which we want
// serde_derive_internals to parse for us.
pub(crate) static SERDE_KEYWORDS: &[&str] = &[ pub(crate) static SERDE_KEYWORDS: &[&str] = &[
"rename", "rename",
"rename_all", "rename_all",
@ -23,12 +24,15 @@ pub(crate) static SERDE_KEYWORDS: &[&str] = &[
"flatten", "flatten",
"remote", "remote",
"transparent", "transparent",
// Special case - `bound` is removed from serde attrs, so is only respected when present in schemars attr. // Special case - `bound` is removed from serde attrs, so is only respected when present in
// schemars attr.
"bound", "bound",
// Special cases - `with`/`serialize_with` are passed to serde but not copied from schemars attrs to serde attrs. // Special cases - `with`/`serialize_with` are passed to serde but not copied from schemars
// This is because we want to preserve any serde attribute's `serialize_with` value to determine whether the field's // attrs to serde attrs. This is because we want to preserve any serde attribute's
// default value should be serialized. We also check the `with` value on schemars/serde attrs e.g. to support deriving // `serialize_with` value to determine whether the field's default value should be
// JsonSchema on remote types, but we parse that ourselves rather than using serde_derive_internals. // serialized. We also check the `with` value on schemars/serde attrs e.g. to support deriving
// JsonSchema on remote types, but we parse that ourselves rather than using
// serde_derive_internals.
"serialize_with", "serialize_with",
"with", "with",
]; ];

View file

@ -201,8 +201,11 @@ fn add_trait_bounds(cont: &mut Container) {
let where_clause = cont.generics.make_where_clause(); let where_clause = cont.generics.make_where_clause();
where_clause.predicates.extend(bounds.iter().cloned()); where_clause.predicates.extend(bounds.iter().cloned());
} else { } else {
// No explicit trait bounds specified, assume the Rust convention of adding the trait to each type parameter // No explicit trait bounds specified, assume the Rust convention of adding the trait to
// TODO consider also adding trait bound to associated types when used as fields - I think Serde does this? // each type parameter
//
// TODO consider also adding trait bound to associated types
// when used as fields - I think Serde does this?
for param in &mut cont.generics.params { for param in &mut cont.generics.params {
if let syn::GenericParam::Type(ref mut type_param) = *param { if let syn::GenericParam::Type(ref mut type_param) = *param {
type_param.bounds.push(parse_quote!(schemars::JsonSchema)); type_param.bounds.push(parse_quote!(schemars::JsonSchema));