Add schema_id(), handles different types with the same name (#247)
This commit is contained in:
parent
53bb51cb25
commit
342b2dff33
26 changed files with 415 additions and 34 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -1,3 +1,4 @@
|
||||||
{
|
{
|
||||||
"rust-analyzer.check.command": "clippy"
|
"rust-analyzer.check.command": "clippy",
|
||||||
|
"rust-analyzer.showUnlinkedFileNotification": false
|
||||||
}
|
}
|
|
@ -11,6 +11,8 @@ use crate::schema::*;
|
||||||
use crate::{visit::*, JsonSchema, Map};
|
use crate::{visit::*, JsonSchema, Map};
|
||||||
use dyn_clone::DynClone;
|
use dyn_clone::DynClone;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::{any::Any, collections::HashSet, fmt::Debug};
|
use std::{any::Any, collections::HashSet, fmt::Debug};
|
||||||
|
|
||||||
/// Settings to customize how Schemas are generated.
|
/// Settings to customize how Schemas are generated.
|
||||||
|
@ -149,7 +151,9 @@ impl SchemaSettings {
|
||||||
pub struct SchemaGenerator {
|
pub struct SchemaGenerator {
|
||||||
settings: SchemaSettings,
|
settings: SchemaSettings,
|
||||||
definitions: Map<String, Schema>,
|
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 {
|
impl Clone for SchemaGenerator {
|
||||||
|
@ -157,7 +161,9 @@ impl Clone for SchemaGenerator {
|
||||||
Self {
|
Self {
|
||||||
settings: self.settings.clone(),
|
settings: self.settings.clone(),
|
||||||
definitions: self.definitions.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
|
/// If `T`'s schema depends on any [referenceable](JsonSchema::is_referenceable) schemas, then this method will
|
||||||
/// add them to the `SchemaGenerator`'s schema definitions.
|
/// 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 name = T::schema_name();
|
let id = T::schema_id();
|
||||||
let return_ref = T::is_referenceable()
|
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 {
|
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) {
|
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)
|
Schema::new_ref(reference)
|
||||||
} else {
|
} 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);
|
let dummy = Schema::Bool(false);
|
||||||
// insert into definitions BEFORE calling json_schema to avoid infinite recursion
|
// insert into definitions BEFORE calling json_schema to avoid infinite recursion
|
||||||
self.definitions.insert(name.clone(), dummy);
|
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);
|
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
|
/// add them to the `SchemaGenerator`'s schema definitions and include them in the returned `SchemaObject`'s
|
||||||
/// [`definitions`](../schema/struct.Metadata.html#structfield.definitions)
|
/// [`definitions`](../schema/struct.Metadata.html#structfield.definitions)
|
||||||
pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> RootSchema {
|
pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> RootSchema {
|
||||||
let name = T::schema_name();
|
let mut schema = self.json_schema_internal::<T>(T::schema_id()).into_object();
|
||||||
let mut schema = self.json_schema_internal::<T>(&name).into_object();
|
schema.metadata().title.get_or_insert_with(T::schema_name);
|
||||||
schema.metadata().title.get_or_insert(name);
|
|
||||||
let mut root = RootSchema {
|
let mut root = RootSchema {
|
||||||
meta_schema: self.settings.meta_schema.clone(),
|
meta_schema: self.settings.meta_schema.clone(),
|
||||||
definitions: self.definitions.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
|
/// 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)
|
/// 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 {
|
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>(T::schema_id()).into_object();
|
||||||
let mut schema = self.json_schema_internal::<T>(&name).into_object();
|
schema.metadata().title.get_or_insert_with(T::schema_name);
|
||||||
schema.metadata().title.get_or_insert(name);
|
|
||||||
let mut root = RootSchema {
|
let mut root = RootSchema {
|
||||||
meta_schema: self.settings.meta_schema,
|
meta_schema: self.settings.meta_schema,
|
||||||
definitions: self.definitions,
|
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> {
|
struct PendingSchemaState<'a> {
|
||||||
gen: &'a mut SchemaGenerator,
|
gen: &'a mut SchemaGenerator,
|
||||||
name: &'a str,
|
id: Cow<'static, str>,
|
||||||
did_add: bool,
|
did_add: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PendingSchemaState<'a> {
|
impl<'a> PendingSchemaState<'a> {
|
||||||
fn new(gen: &'a mut SchemaGenerator, name: &'a str) -> Self {
|
fn new(gen: &'a mut SchemaGenerator, id: Cow<'static, str>) -> Self {
|
||||||
let did_add = gen.pending_schema_names.insert(name.to_owned());
|
let did_add = gen.pending_schema_ids.insert(id.clone());
|
||||||
Self { gen, name, did_add }
|
Self { gen, id, did_add }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for PendingSchemaState<'_> {
|
impl Drop for PendingSchemaState<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.did_add {
|
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)
|
T::json_schema(pss.gen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
// Does not require T: JsonSchema.
|
// Does not require T: JsonSchema.
|
||||||
impl<T> JsonSchema for [T; 0] {
|
impl<T> JsonSchema for [T; 0] {
|
||||||
|
@ -10,6 +11,10 @@ impl<T> JsonSchema for [T; 0] {
|
||||||
"EmptyArray".to_owned()
|
"EmptyArray".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("[]")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
instance_type: Some(InstanceType::Array.into()),
|
||||||
|
@ -33,6 +38,11 @@ macro_rules! array_impls {
|
||||||
format!("Array_size_{}_of_{}", $len, T::schema_name())
|
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 {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
instance_type: Some(InstanceType::Array.into()),
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
impl JsonSchema for Weekday {
|
impl JsonSchema for Weekday {
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
@ -11,6 +12,10 @@ impl JsonSchema for Weekday {
|
||||||
"Weekday".to_owned()
|
"Weekday".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("chrono::Weekday")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::String.into()),
|
instance_type: Some(InstanceType::String.into()),
|
||||||
|
@ -41,6 +46,10 @@ macro_rules! formatted_string_impl {
|
||||||
stringify!($ty).to_owned()
|
stringify!($ty).to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed(stringify!(chrono::$ty))
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::String.into()),
|
instance_type: Some(InstanceType::String.into()),
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::ops::{Bound, Range, RangeInclusive};
|
use std::ops::{Bound, Range, RangeInclusive};
|
||||||
|
|
||||||
impl<T: JsonSchema> JsonSchema for Option<T> {
|
impl<T: JsonSchema> JsonSchema for Option<T> {
|
||||||
|
@ -11,6 +12,10 @@ impl<T: JsonSchema> JsonSchema for Option<T> {
|
||||||
format!("Nullable_{}", T::schema_name())
|
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 {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut schema = gen.subschema_for::<T>();
|
let mut schema = gen.subschema_for::<T>();
|
||||||
if gen.settings().option_add_null_type {
|
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())
|
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 {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut ok_schema = SchemaObject {
|
let mut ok_schema = SchemaObject {
|
||||||
instance_type: Some(InstanceType::Object.into()),
|
instance_type: Some(InstanceType::Object.into()),
|
||||||
|
@ -99,6 +108,10 @@ impl<T: JsonSchema> JsonSchema for Bound<T> {
|
||||||
format!("Bound_of_{}", T::schema_name())
|
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 {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut included_schema = SchemaObject {
|
let mut included_schema = SchemaObject {
|
||||||
instance_type: Some(InstanceType::Object.into()),
|
instance_type: Some(InstanceType::Object.into()),
|
||||||
|
@ -139,6 +152,10 @@ impl<T: JsonSchema> JsonSchema for Range<T> {
|
||||||
format!("Range_of_{}", T::schema_name())
|
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 {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut schema = SchemaObject {
|
let mut schema = SchemaObject {
|
||||||
instance_type: Some(InstanceType::Object.into()),
|
instance_type: Some(InstanceType::Object.into()),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
macro_rules! decimal_impl {
|
macro_rules! decimal_impl {
|
||||||
($type:ty) => {
|
($type:ty) => {
|
||||||
|
@ -11,6 +12,10 @@ macro_rules! decimal_impl {
|
||||||
"Decimal".to_owned()
|
"Decimal".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed($name)
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::String.into()),
|
instance_type: Some(InstanceType::String.into()),
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
impl<L: JsonSchema, R: JsonSchema> JsonSchema for Either<L, R> {
|
impl<L: JsonSchema, R: JsonSchema> JsonSchema for Either<L, R> {
|
||||||
no_ref_schema!();
|
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())
|
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 {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut schema = SchemaObject::default();
|
let mut schema = SchemaObject::default();
|
||||||
schema.subschemas().any_of = Some(vec![gen.subschema_for::<L>(), gen.subschema_for::<R>()]);
|
schema.subschemas().any_of = Some(vec![gen.subschema_for::<L>(), gen.subschema_for::<R>()]);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::ffi::{CStr, CString, OsStr, OsString};
|
use std::ffi::{CStr, CString, OsStr, OsString};
|
||||||
|
|
||||||
impl JsonSchema for OsString {
|
impl JsonSchema for OsString {
|
||||||
|
@ -8,6 +9,10 @@ impl JsonSchema for OsString {
|
||||||
"OsString".to_owned()
|
"OsString".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("std::ffi::OsString")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut unix_schema = SchemaObject {
|
let mut unix_schema = SchemaObject {
|
||||||
instance_type: Some(InstanceType::Object.into()),
|
instance_type: Some(InstanceType::Object.into()),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
macro_rules! map_impl {
|
macro_rules! map_impl {
|
||||||
($($desc:tt)+) => {
|
($($desc:tt)+) => {
|
||||||
|
@ -14,6 +15,10 @@ macro_rules! map_impl {
|
||||||
format!("Map_of_{}", V::schema_name())
|
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 {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let subschema = gen.subschema_for::<V>();
|
let subschema = gen.subschema_for::<V>();
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
|
|
|
@ -17,6 +17,10 @@ macro_rules! forward_impl {
|
||||||
<$target>::schema_name()
|
<$target>::schema_name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> std::borrow::Cow<'static, str> {
|
||||||
|
<$target>::schema_id()
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
<$target>::json_schema(gen)
|
<$target>::json_schema(gen)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::num::*;
|
use std::num::*;
|
||||||
|
|
||||||
macro_rules! nonzero_unsigned_impl {
|
macro_rules! nonzero_unsigned_impl {
|
||||||
|
@ -12,6 +13,10 @@ macro_rules! nonzero_unsigned_impl {
|
||||||
stringify!($type).to_owned()
|
stringify!($type).to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed(stringify!(std::num::$type))
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let zero_schema: Schema = SchemaObject {
|
let zero_schema: Schema = SchemaObject {
|
||||||
const_value: Some(0.into()),
|
const_value: Some(0.into()),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::num::*;
|
use std::num::*;
|
||||||
|
|
||||||
macro_rules! nonzero_unsigned_impl {
|
macro_rules! nonzero_unsigned_impl {
|
||||||
|
@ -12,6 +13,10 @@ macro_rules! nonzero_unsigned_impl {
|
||||||
stringify!($type).to_owned()
|
stringify!($type).to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed(stringify!(std::num::$type))
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut schema: SchemaObject = <$primitive>::json_schema(gen).into();
|
let mut schema: SchemaObject = <$primitive>::json_schema(gen).into();
|
||||||
schema.number().minimum = Some(1.0);
|
schema.number().minimum = Some(1.0);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
@ -19,6 +20,10 @@ macro_rules! simple_impl {
|
||||||
$name.to_owned()
|
$name.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed($name)
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::$instance_type.into()),
|
instance_type: Some(InstanceType::$instance_type.into()),
|
||||||
|
@ -64,6 +69,10 @@ macro_rules! unsigned_impl {
|
||||||
$format.to_owned()
|
$format.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed($format)
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
let mut schema = SchemaObject {
|
let mut schema = SchemaObject {
|
||||||
instance_type: Some(InstanceType::$instance_type.into()),
|
instance_type: Some(InstanceType::$instance_type.into()),
|
||||||
|
@ -91,6 +100,10 @@ impl JsonSchema for char {
|
||||||
"Character".to_owned()
|
"Character".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("char")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::String.into()),
|
instance_type: Some(InstanceType::String.into()),
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
impl JsonSchema for Version {
|
impl JsonSchema for Version {
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
@ -10,6 +11,10 @@ impl JsonSchema for Version {
|
||||||
"Version".to_owned()
|
"Version".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("semver::Version")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::String.into()),
|
instance_type: Some(InstanceType::String.into()),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
macro_rules! seq_impl {
|
macro_rules! seq_impl {
|
||||||
($($desc:tt)+) => {
|
($($desc:tt)+) => {
|
||||||
|
@ -14,6 +15,11 @@ macro_rules! seq_impl {
|
||||||
format!("Array_of_{}", T::schema_name())
|
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 {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
instance_type: Some(InstanceType::Array.into()),
|
||||||
|
@ -41,6 +47,11 @@ macro_rules! set_impl {
|
||||||
format!("Set_of_{}", T::schema_name())
|
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 {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
instance_type: Some(InstanceType::Array.into()),
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
use serde_json::{Map, Number, Value};
|
use serde_json::{Map, Number, Value};
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
impl JsonSchema for Value {
|
impl JsonSchema for Value {
|
||||||
|
@ -11,6 +12,10 @@ impl JsonSchema for Value {
|
||||||
"AnyValue".to_owned()
|
"AnyValue".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("AnyValue")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
Schema::Bool(true)
|
Schema::Bool(true)
|
||||||
}
|
}
|
||||||
|
@ -25,6 +30,10 @@ impl JsonSchema for Number {
|
||||||
"Number".to_owned()
|
"Number".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("Number")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::Number.into()),
|
instance_type: Some(InstanceType::Number.into()),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
impl JsonSchema for Duration {
|
impl JsonSchema for Duration {
|
||||||
|
@ -8,6 +9,10 @@ impl JsonSchema for Duration {
|
||||||
"Duration".to_owned()
|
"Duration".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("std::time::Duration")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut schema = SchemaObject {
|
let mut schema = SchemaObject {
|
||||||
instance_type: Some(InstanceType::Object.into()),
|
instance_type: Some(InstanceType::Object.into()),
|
||||||
|
@ -29,6 +34,10 @@ impl JsonSchema for SystemTime {
|
||||||
"SystemTime".to_owned()
|
"SystemTime".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("std::time::SystemTime")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut schema = SchemaObject {
|
let mut schema = SchemaObject {
|
||||||
instance_type: Some(InstanceType::Object.into()),
|
instance_type: Some(InstanceType::Object.into()),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
macro_rules! tuple_impls {
|
macro_rules! tuple_impls {
|
||||||
($($len:expr => ($($name:ident)+))+) => {
|
($($len:expr => ($($name:ident)+))+) => {
|
||||||
|
@ -14,6 +15,14 @@ macro_rules! tuple_impls {
|
||||||
name
|
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 {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let items = vec![
|
let items = vec![
|
||||||
$(gen.subschema_for::<$name>()),+
|
$(gen.subschema_for::<$name>()),+
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
impl JsonSchema for Url {
|
impl JsonSchema for Url {
|
||||||
|
@ -10,6 +11,10 @@ impl JsonSchema for Url {
|
||||||
"Url".to_owned()
|
"Url".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("url::Url")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::String.into()),
|
instance_type: Some(InstanceType::String.into()),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
use uuid08::Uuid;
|
use uuid08::Uuid;
|
||||||
|
|
||||||
impl JsonSchema for Uuid {
|
impl JsonSchema for Uuid {
|
||||||
|
@ -10,6 +11,10 @@ impl JsonSchema for Uuid {
|
||||||
"Uuid".to_string()
|
"Uuid".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("uuid::Uuid")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::String.into()),
|
instance_type: Some(InstanceType::String.into()),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use crate::JsonSchema;
|
use crate::JsonSchema;
|
||||||
|
use std::borrow::Cow;
|
||||||
use uuid1::Uuid;
|
use uuid1::Uuid;
|
||||||
|
|
||||||
impl JsonSchema for Uuid {
|
impl JsonSchema for Uuid {
|
||||||
|
@ -10,6 +11,10 @@ impl JsonSchema for Uuid {
|
||||||
"Uuid".to_string()
|
"Uuid".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("uuid::Uuid")
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::String.into()),
|
instance_type: Some(InstanceType::String.into()),
|
||||||
|
|
|
@ -41,6 +41,8 @@ pub mod visit;
|
||||||
|
|
||||||
#[cfg(feature = "schemars_derive")]
|
#[cfg(feature = "schemars_derive")]
|
||||||
extern crate schemars_derive;
|
extern crate schemars_derive;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
#[cfg(feature = "schemars_derive")]
|
#[cfg(feature = "schemars_derive")]
|
||||||
pub use 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)]`.
|
/// This can also be automatically derived on most custom types with `#[derive(JsonSchema)]`.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Examples
|
||||||
|
/// Deriving an implementation:
|
||||||
/// ```
|
/// ```
|
||||||
/// use schemars::{schema_for, JsonSchema};
|
/// use schemars::{schema_for, JsonSchema};
|
||||||
///
|
///
|
||||||
|
@ -67,6 +70,64 @@ use schema::Schema;
|
||||||
///
|
///
|
||||||
/// let my_schema = schema_for!(MyStruct);
|
/// 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 {
|
pub trait JsonSchema {
|
||||||
/// Whether JSON Schemas generated for this type should be re-used where possible using the `$ref` keyword.
|
/// 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.
|
/// This is used as the title for root schemas, and the key within the root's `definitions` property for subschemas.
|
||||||
fn schema_name() -> String;
|
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.
|
/// Generates a JSON Schema for this type.
|
||||||
///
|
///
|
||||||
/// If the returned schema depends on any [referenceable](JsonSchema::is_referenceable) schemas, then this method will
|
/// If the returned schema depends on any [referenceable](JsonSchema::is_referenceable) schemas, then this method will
|
||||||
|
|
41
schemars/tests/expected/same_name.json
Normal file
41
schemars/tests/expected/same_name.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
schemars/tests/same_name.rs
Normal file
35
schemars/tests/same_name.rs
Normal 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")
|
||||||
|
}
|
|
@ -67,6 +67,10 @@ fn derive_json_schema(
|
||||||
<#ty as schemars::JsonSchema>::schema_name()
|
<#ty as schemars::JsonSchema>::schema_name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> std::borrow::Cow<'static, str> {
|
||||||
|
<#ty as schemars::JsonSchema>::schema_id()
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||||
<#ty as schemars::JsonSchema>::json_schema(gen)
|
<#ty as schemars::JsonSchema>::json_schema(gen)
|
||||||
}
|
}
|
||||||
|
@ -98,27 +102,66 @@ fn derive_json_schema(
|
||||||
let const_params: Vec<_> = cont.generics.const_params().map(|c| &c.ident).collect();
|
let const_params: Vec<_> = cont.generics.const_params().map(|c| &c.ident).collect();
|
||||||
let params: Vec<_> = type_params.iter().chain(const_params.iter()).collect();
|
let params: Vec<_> = type_params.iter().chain(const_params.iter()).collect();
|
||||||
|
|
||||||
let schema_name = if params.is_empty()
|
let (schema_name, schema_id) = if params.is_empty()
|
||||||
|| (cont.attrs.is_renamed && !schema_base_name.contains('{'))
|
|| (cont.attrs.is_renamed && !schema_base_name.contains('{'))
|
||||||
{
|
{
|
||||||
|
(
|
||||||
quote! {
|
quote! {
|
||||||
#schema_base_name.to_owned()
|
#schema_base_name.to_owned()
|
||||||
}
|
},
|
||||||
|
quote! {
|
||||||
|
std::borrow::Cow::Borrowed(std::concat!(
|
||||||
|
std::module_path!(),
|
||||||
|
"::",
|
||||||
|
#schema_base_name
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)
|
||||||
} else if cont.attrs.is_renamed {
|
} else if cont.attrs.is_renamed {
|
||||||
let mut schema_name_fmt = schema_base_name;
|
let mut schema_name_fmt = schema_base_name;
|
||||||
for tp in ¶ms {
|
for tp in ¶ms {
|
||||||
schema_name_fmt.push_str(&format!("{{{}:.0}}", tp));
|
schema_name_fmt.push_str(&format!("{{{}:.0}}", tp));
|
||||||
}
|
}
|
||||||
|
(
|
||||||
quote! {
|
quote! {
|
||||||
format!(#schema_name_fmt #(,#type_params=#type_params::schema_name())* #(,#const_params=#const_params)*)
|
format!(#schema_name_fmt #(,#type_params=#type_params::schema_name())* #(,#const_params=#const_params)*)
|
||||||
}
|
},
|
||||||
|
quote! {
|
||||||
|
std::borrow::Cow::Owned(
|
||||||
|
format!(
|
||||||
|
std::concat!(
|
||||||
|
std::module_path!(),
|
||||||
|
"::",
|
||||||
|
#schema_name_fmt
|
||||||
|
)
|
||||||
|
#(,#type_params=#type_params::schema_id())*
|
||||||
|
#(,#const_params=#const_params)*
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
let mut schema_name_fmt = schema_base_name;
|
let mut schema_name_fmt = schema_base_name;
|
||||||
schema_name_fmt.push_str("_for_{}");
|
schema_name_fmt.push_str("_for_{}");
|
||||||
schema_name_fmt.push_str(&"_and_{}".repeat(params.len() - 1));
|
schema_name_fmt.push_str(&"_and_{}".repeat(params.len() - 1));
|
||||||
|
(
|
||||||
quote! {
|
quote! {
|
||||||
format!(#schema_name_fmt #(,#type_params::schema_name())* #(,#const_params)*)
|
format!(#schema_name_fmt #(,#type_params::schema_name())* #(,#const_params)*)
|
||||||
}
|
},
|
||||||
|
quote! {
|
||||||
|
std::borrow::Cow::Owned(
|
||||||
|
format!(
|
||||||
|
std::concat!(
|
||||||
|
std::module_path!(),
|
||||||
|
"::",
|
||||||
|
#schema_name_fmt
|
||||||
|
)
|
||||||
|
#(,#type_params::schema_id())*
|
||||||
|
#(,#const_params)*
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let schema_expr = if repr {
|
let schema_expr = if repr {
|
||||||
|
@ -138,6 +181,10 @@ fn derive_json_schema(
|
||||||
#schema_name
|
#schema_name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> std::borrow::Cow<'static, str> {
|
||||||
|
#schema_id
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||||
#schema_expr
|
#schema_expr
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,15 @@ fn type_for_schema(with_attr: &WithAttr) -> (syn::Type, Option<TokenStream>) {
|
||||||
#fn_name.to_string()
|
#fn_name.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> std::borrow::Cow<'static, str> {
|
||||||
|
std::borrow::Cow::Borrowed(std::concat!(
|
||||||
|
"_SchemarsSchemaWithFunction/",
|
||||||
|
std::module_path!(),
|
||||||
|
"/",
|
||||||
|
#fn_name
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||||
#fun(gen)
|
#fun(gen)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue