Add schema_id(), handles different types with the same name (#247)

This commit is contained in:
Graham Esau 2023-09-17 20:36:52 +01:00 committed by GitHub
parent 53bb51cb25
commit 342b2dff33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 415 additions and 34 deletions

View file

@ -11,6 +11,8 @@ use crate::schema::*;
use crate::{visit::*, JsonSchema, Map};
use dyn_clone::DynClone;
use serde::Serialize;
use std::borrow::Cow;
use std::collections::HashMap;
use std::{any::Any, collections::HashSet, fmt::Debug};
/// Settings to customize how Schemas are generated.
@ -149,7 +151,9 @@ impl SchemaSettings {
pub struct SchemaGenerator {
settings: SchemaSettings,
definitions: Map<String, Schema>,
pending_schema_names: HashSet<String>,
pending_schema_ids: HashSet<Cow<'static, str>>,
schema_id_to_name: HashMap<Cow<'static, str>, String>,
used_schema_names: HashSet<String>,
}
impl Clone for SchemaGenerator {
@ -157,7 +161,9 @@ impl Clone for SchemaGenerator {
Self {
settings: self.settings.clone(),
definitions: self.definitions.clone(),
pending_schema_names: HashSet::new(),
pending_schema_ids: HashSet::new(),
schema_id_to_name: HashMap::new(),
used_schema_names: HashSet::new(),
}
}
}
@ -213,27 +219,54 @@ impl SchemaGenerator {
/// If `T`'s schema depends on any [referenceable](JsonSchema::is_referenceable) schemas, then this method will
/// add them to the `SchemaGenerator`'s schema definitions.
pub fn subschema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
let name = T::schema_name();
let id = T::schema_id();
let return_ref = T::is_referenceable()
&& (!self.settings.inline_subschemas || self.pending_schema_names.contains(&name));
&& (!self.settings.inline_subschemas || self.pending_schema_ids.contains(&id));
if return_ref {
let reference = format!("{}{}", self.settings().definitions_path, name);
let name = match self.schema_id_to_name.get(&id).cloned() {
Some(n) => n,
None => {
let base_name = T::schema_name();
let mut name = String::new();
if self.used_schema_names.contains(&base_name) {
for i in 2.. {
name = format!("{}{}", base_name, i);
if !self.used_schema_names.contains(&name) {
break;
}
}
} else {
name = base_name;
}
self.used_schema_names.insert(name.clone());
self.schema_id_to_name.insert(id.clone(), name.clone());
name
}
};
let reference = format!("{}{}", self.settings.definitions_path, name);
if !self.definitions.contains_key(&name) {
self.insert_new_subschema_for::<T>(name);
self.insert_new_subschema_for::<T>(name, id);
}
Schema::new_ref(reference)
} else {
self.json_schema_internal::<T>(&name)
self.json_schema_internal::<T>(id)
}
}
fn insert_new_subschema_for<T: ?Sized + JsonSchema>(&mut self, name: String) {
fn insert_new_subschema_for<T: ?Sized + JsonSchema>(
&mut self,
name: String,
id: Cow<'static, str>,
) {
let dummy = Schema::Bool(false);
// insert into definitions BEFORE calling json_schema to avoid infinite recursion
self.definitions.insert(name.clone(), dummy);
let schema = self.json_schema_internal::<T>(&name);
let schema = self.json_schema_internal::<T>(id);
self.definitions.insert(name, schema);
}
@ -274,9 +307,8 @@ impl SchemaGenerator {
/// add them to the `SchemaGenerator`'s schema definitions and include them in the returned `SchemaObject`'s
/// [`definitions`](../schema/struct.Metadata.html#structfield.definitions)
pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> RootSchema {
let name = T::schema_name();
let mut schema = self.json_schema_internal::<T>(&name).into_object();
schema.metadata().title.get_or_insert(name);
let mut schema = self.json_schema_internal::<T>(T::schema_id()).into_object();
schema.metadata().title.get_or_insert_with(T::schema_name);
let mut root = RootSchema {
meta_schema: self.settings.meta_schema.clone(),
definitions: self.definitions.clone(),
@ -295,9 +327,8 @@ impl SchemaGenerator {
/// If `T`'s schema depends on any [referenceable](JsonSchema::is_referenceable) schemas, then this method will
/// include them in the returned `SchemaObject`'s [`definitions`](../schema/struct.Metadata.html#structfield.definitions)
pub fn into_root_schema_for<T: ?Sized + JsonSchema>(mut self) -> RootSchema {
let name = T::schema_name();
let mut schema = self.json_schema_internal::<T>(&name).into_object();
schema.metadata().title.get_or_insert(name);
let mut schema = self.json_schema_internal::<T>(T::schema_id()).into_object();
schema.metadata().title.get_or_insert_with(T::schema_name);
let mut root = RootSchema {
meta_schema: self.settings.meta_schema,
definitions: self.definitions,
@ -418,29 +449,29 @@ impl SchemaGenerator {
}
}
fn json_schema_internal<T: ?Sized + JsonSchema>(&mut self, name: &str) -> Schema {
fn json_schema_internal<T: ?Sized + JsonSchema>(&mut self, id: Cow<'static, str>) -> Schema {
struct PendingSchemaState<'a> {
gen: &'a mut SchemaGenerator,
name: &'a str,
id: Cow<'static, str>,
did_add: bool,
}
impl<'a> PendingSchemaState<'a> {
fn new(gen: &'a mut SchemaGenerator, name: &'a str) -> Self {
let did_add = gen.pending_schema_names.insert(name.to_owned());
Self { gen, name, did_add }
fn new(gen: &'a mut SchemaGenerator, id: Cow<'static, str>) -> Self {
let did_add = gen.pending_schema_ids.insert(id.clone());
Self { gen, id, did_add }
}
}
impl Drop for PendingSchemaState<'_> {
fn drop(&mut self) {
if self.did_add {
self.gen.pending_schema_names.remove(self.name);
self.gen.pending_schema_ids.remove(&self.id);
}
}
}
let pss = PendingSchemaState::new(self, name);
let pss = PendingSchemaState::new(self, id);
T::json_schema(pss.gen)
}
}

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
// Does not require T: JsonSchema.
impl<T> JsonSchema for [T; 0] {
@ -10,6 +11,10 @@ impl<T> JsonSchema for [T; 0] {
"EmptyArray".to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("[]")
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::Array.into()),
@ -33,6 +38,11 @@ macro_rules! array_impls {
format!("Array_size_{}_of_{}", $len, T::schema_name())
}
fn schema_id() -> Cow<'static, str> {
Cow::Owned(
format!("[{}; {}]", $len, T::schema_id()))
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::Array.into()),

View file

@ -3,6 +3,7 @@ use crate::schema::*;
use crate::JsonSchema;
use chrono::prelude::*;
use serde_json::json;
use std::borrow::Cow;
impl JsonSchema for Weekday {
no_ref_schema!();
@ -11,6 +12,10 @@ impl JsonSchema for Weekday {
"Weekday".to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("chrono::Weekday")
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::String.into()),
@ -41,6 +46,10 @@ macro_rules! formatted_string_impl {
stringify!($ty).to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed(stringify!(chrono::$ty))
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::String.into()),

View file

@ -2,6 +2,7 @@ use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use serde_json::json;
use std::borrow::Cow;
use std::ops::{Bound, Range, RangeInclusive};
impl<T: JsonSchema> JsonSchema for Option<T> {
@ -11,6 +12,10 @@ impl<T: JsonSchema> JsonSchema for Option<T> {
format!("Nullable_{}", T::schema_name())
}
fn schema_id() -> Cow<'static, str> {
Cow::Owned(format!("Option<{}>", T::schema_id()))
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema = gen.subschema_for::<T>();
if gen.settings().option_add_null_type {
@ -69,6 +74,10 @@ impl<T: JsonSchema, E: JsonSchema> JsonSchema for Result<T, E> {
format!("Result_of_{}_or_{}", T::schema_name(), E::schema_name())
}
fn schema_id() -> Cow<'static, str> {
Cow::Owned(format!("Result<{}, {}>", T::schema_id(), E::schema_id()))
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut ok_schema = SchemaObject {
instance_type: Some(InstanceType::Object.into()),
@ -99,6 +108,10 @@ impl<T: JsonSchema> JsonSchema for Bound<T> {
format!("Bound_of_{}", T::schema_name())
}
fn schema_id() -> Cow<'static, str> {
Cow::Owned(format!("Bound<{}>", T::schema_id()))
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut included_schema = SchemaObject {
instance_type: Some(InstanceType::Object.into()),
@ -139,6 +152,10 @@ impl<T: JsonSchema> JsonSchema for Range<T> {
format!("Range_of_{}", T::schema_name())
}
fn schema_id() -> Cow<'static, str> {
Cow::Owned(format!("Range<{}>", T::schema_id()))
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema = SchemaObject {
instance_type: Some(InstanceType::Object.into()),

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
macro_rules! decimal_impl {
($type:ty) => {
@ -11,6 +12,10 @@ macro_rules! decimal_impl {
"Decimal".to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed($name)
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::String.into()),

View file

@ -2,6 +2,7 @@ use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use either::Either;
use std::borrow::Cow;
impl<L: JsonSchema, R: JsonSchema> JsonSchema for Either<L, R> {
no_ref_schema!();
@ -10,6 +11,14 @@ impl<L: JsonSchema, R: JsonSchema> JsonSchema for Either<L, R> {
format!("Either_{}_or_{}", L::schema_name(), R::schema_name())
}
fn schema_id() -> Cow<'static, str> {
Cow::Owned(format!(
"either::Either<{}, {}>",
L::schema_id(),
R::schema_id()
))
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema = SchemaObject::default();
schema.subschemas().any_of = Some(vec![gen.subschema_for::<L>(), gen.subschema_for::<R>()]);

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
use std::ffi::{CStr, CString, OsStr, OsString};
impl JsonSchema for OsString {
@ -8,6 +9,10 @@ impl JsonSchema for OsString {
"OsString".to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("std::ffi::OsString")
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut unix_schema = SchemaObject {
instance_type: Some(InstanceType::Object.into()),

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
macro_rules! map_impl {
($($desc:tt)+) => {
@ -14,6 +15,10 @@ macro_rules! map_impl {
format!("Map_of_{}", V::schema_name())
}
fn schema_id() -> Cow<'static, str> {
Cow::Owned(format!("Map<{}>", V::schema_id()))
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let subschema = gen.subschema_for::<V>();
SchemaObject {

View file

@ -17,6 +17,10 @@ macro_rules! forward_impl {
<$target>::schema_name()
}
fn schema_id() -> std::borrow::Cow<'static, str> {
<$target>::schema_id()
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
<$target>::json_schema(gen)
}

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
use std::num::*;
macro_rules! nonzero_unsigned_impl {
@ -12,6 +13,10 @@ macro_rules! nonzero_unsigned_impl {
stringify!($type).to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed(stringify!(std::num::$type))
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let zero_schema: Schema = SchemaObject {
const_value: Some(0.into()),

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
use std::num::*;
macro_rules! nonzero_unsigned_impl {
@ -12,6 +13,10 @@ macro_rules! nonzero_unsigned_impl {
stringify!($type).to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed(stringify!(std::num::$type))
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema: SchemaObject = <$primitive>::json_schema(gen).into();
schema.number().minimum = Some(1.0);

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::path::{Path, PathBuf};
@ -19,6 +20,10 @@ macro_rules! simple_impl {
$name.to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed($name)
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::$instance_type.into()),
@ -64,6 +69,10 @@ macro_rules! unsigned_impl {
$format.to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed($format)
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
let mut schema = SchemaObject {
instance_type: Some(InstanceType::$instance_type.into()),
@ -91,6 +100,10 @@ impl JsonSchema for char {
"Character".to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("char")
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::String.into()),

View file

@ -2,6 +2,7 @@ use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use semver::Version;
use std::borrow::Cow;
impl JsonSchema for Version {
no_ref_schema!();
@ -10,6 +11,10 @@ impl JsonSchema for Version {
"Version".to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("semver::Version")
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::String.into()),

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
macro_rules! seq_impl {
($($desc:tt)+) => {
@ -14,6 +15,11 @@ macro_rules! seq_impl {
format!("Array_of_{}", T::schema_name())
}
fn schema_id() -> Cow<'static, str> {
Cow::Owned(
format!("[{}]", T::schema_id()))
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::Array.into()),
@ -41,6 +47,11 @@ macro_rules! set_impl {
format!("Set_of_{}", T::schema_name())
}
fn schema_id() -> Cow<'static, str> {
Cow::Owned(
format!("Set<{}>", T::schema_id()))
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::Array.into()),

View file

@ -2,6 +2,7 @@ use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use serde_json::{Map, Number, Value};
use std::borrow::Cow;
use std::collections::BTreeMap;
impl JsonSchema for Value {
@ -11,6 +12,10 @@ impl JsonSchema for Value {
"AnyValue".to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("AnyValue")
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
Schema::Bool(true)
}
@ -25,6 +30,10 @@ impl JsonSchema for Number {
"Number".to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("Number")
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::Number.into()),

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
use std::time::{Duration, SystemTime};
impl JsonSchema for Duration {
@ -8,6 +9,10 @@ impl JsonSchema for Duration {
"Duration".to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("std::time::Duration")
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema = SchemaObject {
instance_type: Some(InstanceType::Object.into()),
@ -29,6 +34,10 @@ impl JsonSchema for SystemTime {
"SystemTime".to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("std::time::SystemTime")
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema = SchemaObject {
instance_type: Some(InstanceType::Object.into()),

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
macro_rules! tuple_impls {
($($len:expr => ($($name:ident)+))+) => {
@ -14,6 +15,14 @@ macro_rules! tuple_impls {
name
}
fn schema_id() -> Cow<'static, str> {
let mut id = "(".to_owned();
id.push_str(&[$($name::schema_id()),+].join(","));
id.push(')');
Cow::Owned(id)
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let items = vec![
$(gen.subschema_for::<$name>()),+

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
use url::Url;
impl JsonSchema for Url {
@ -10,6 +11,10 @@ impl JsonSchema for Url {
"Url".to_owned()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("url::Url")
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::String.into()),

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
use uuid08::Uuid;
impl JsonSchema for Uuid {
@ -10,6 +11,10 @@ impl JsonSchema for Uuid {
"Uuid".to_string()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("uuid::Uuid")
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::String.into()),

View file

@ -1,6 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use std::borrow::Cow;
use uuid1::Uuid;
impl JsonSchema for Uuid {
@ -10,6 +11,10 @@ impl JsonSchema for Uuid {
"Uuid".to_string()
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("uuid::Uuid")
}
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::String.into()),

View file

@ -41,6 +41,8 @@ pub mod visit;
#[cfg(feature = "schemars_derive")]
extern crate schemars_derive;
use std::borrow::Cow;
#[cfg(feature = "schemars_derive")]
pub use schemars_derive::*;
@ -56,7 +58,8 @@ use schema::Schema;
///
/// This can also be automatically derived on most custom types with `#[derive(JsonSchema)]`.
///
/// # Example
/// # Examples
/// Deriving an implementation:
/// ```
/// use schemars::{schema_for, JsonSchema};
///
@ -67,6 +70,64 @@ use schema::Schema;
///
/// let my_schema = schema_for!(MyStruct);
/// ```
///
/// When manually implementing `JsonSchema`, as well as determining an appropriate schema,
/// you will need to determine an appropriate name and ID for the type.
/// For non-generic types, the type name/path are suitable for this:
/// ```
/// use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
/// use std::borrow::Cow;
///
/// struct NonGenericType;
///
/// impl JsonSchema for NonGenericType {
/// fn schema_name() -> String {
/// // Exclude the module path to make the name in generated schemas clearer.
/// "NonGenericType".to_owned()
/// }
///
/// fn schema_id() -> Cow<'static, str> {
/// // Include the module, in case a type with the same name is in another module/crate
/// Cow::Borrowed(concat!(module_path!(), "::NonGenericType"))
/// }
///
/// fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
/// todo!()
/// }
/// }
///
/// 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:
/// ```
/// use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
/// use std::{borrow::Cow, marker::PhantomData};
///
/// struct GenericType<T>(PhantomData<T>);
///
/// impl<T: JsonSchema> JsonSchema for GenericType<T> {
/// fn schema_name() -> String {
/// format!("GenericType_{}", T::schema_name())
/// }
///
/// fn schema_id() -> Cow<'static, str> {
/// Cow::Owned(format!(
/// "{}::GenericType<{}>",
/// module_path!(),
/// T::schema_id()
/// ))
/// }
///
/// fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
/// todo!()
/// }
/// }
///
/// assert_eq!(<GenericType<i32>>::schema_id(), <&mut GenericType<&i32>>::schema_id());
/// ```
///
pub trait JsonSchema {
/// Whether JSON Schemas generated for this type should be re-used where possible using the `$ref` keyword.
///
@ -83,6 +144,17 @@ pub trait JsonSchema {
/// This is used as the title for root schemas, and the key within the root's `definitions` property for subschemas.
fn schema_name() -> String;
/// 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.
/// If two types produce different schemas, then they **must** have 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()`.
fn schema_id() -> Cow<'static, str> {
Cow::Owned(Self::schema_name())
}
/// Generates a JSON Schema for this type.
///
/// If the returned schema depends on any [referenceable](JsonSchema::is_referenceable) schemas, then this method will

View file

@ -0,0 +1,41 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Config2",
"type": "object",
"required": [
"a_cfg",
"b_cfg"
],
"properties": {
"a_cfg": {
"$ref": "#/definitions/Config"
},
"b_cfg": {
"$ref": "#/definitions/Config2"
}
},
"definitions": {
"Config": {
"type": "object",
"required": [
"test"
],
"properties": {
"test": {
"type": "string"
}
}
},
"Config2": {
"type": "object",
"required": [
"test2"
],
"properties": {
"test2": {
"type": "string"
}
}
}
}
}

View file

@ -0,0 +1,35 @@
mod util;
use schemars::JsonSchema;
use util::*;
mod a {
use super::*;
#[allow(dead_code)]
#[derive(JsonSchema)]
pub struct Config {
test: String,
}
}
mod b {
use super::*;
#[allow(dead_code)]
#[derive(JsonSchema)]
pub struct Config {
test2: String,
}
}
#[allow(dead_code)]
#[derive(JsonSchema)]
pub struct Config2 {
a_cfg: a::Config,
b_cfg: b::Config,
}
#[test]
fn same_name() -> TestResult {
test_default_generated_schema::<Config2>("same_name")
}