use crate::gen::{BoolSchemas, SchemaGenerator};
use crate::schema::*;
use crate::{Map, Result};
use serde_json::json;
pub trait MakeSchema {
fn is_referenceable() -> bool {
true
}
fn schema_name() -> String;
fn make_schema(gen: &mut SchemaGenerator) -> Result;
}
macro_rules! no_ref_schema {
() => {
fn is_referenceable() -> bool {
false
}
};
}
macro_rules! simple_impl {
($type:tt => $instance_type:ident) => {
impl MakeSchema for $type {
no_ref_schema!();
fn schema_name() -> String {
stringify!($instance_type).to_owned()
}
fn make_schema(_: &mut SchemaGenerator) -> Result {
Ok(SchemaObject {
instance_type: Some(InstanceType::$instance_type.into()),
..Default::default()
}
.into())
}
}
};
}
simple_impl!(str => String);
simple_impl!(String => String);
simple_impl!(bool => Boolean);
simple_impl!(f32 => Number);
simple_impl!(f64 => Number);
simple_impl!(i8 => Integer);
simple_impl!(i16 => Integer);
simple_impl!(i32 => Integer);
simple_impl!(i64 => Integer);
simple_impl!(i128 => Integer);
simple_impl!(isize => Integer);
simple_impl!(u8 => Integer);
simple_impl!(u16 => Integer);
simple_impl!(u32 => Integer);
simple_impl!(u64 => Integer);
simple_impl!(u128 => Integer);
simple_impl!(usize => Integer);
simple_impl!(() => Null);
impl MakeSchema for char {
no_ref_schema!();
fn schema_name() -> String {
"Character".to_owned()
}
fn make_schema(_: &mut SchemaGenerator) -> Result {
let mut extensions = Map::new();
extensions.insert("minLength".to_owned(), json!(1));
extensions.insert("maxLength".to_owned(), json!(1));
Ok(SchemaObject {
instance_type: Some(InstanceType::String.into()),
extensions,
..Default::default()
}
.into())
}
}
impl<T> MakeSchema for [T; 0] {
no_ref_schema!();
fn schema_name() -> String {
"Empty_Array".to_owned()
}
fn make_schema(_: &mut SchemaGenerator) -> Result {
let mut extensions = Map::new();
extensions.insert("maxItems".to_owned(), json!(0));
Ok(SchemaObject {
instance_type: Some(InstanceType::Array.into()),
extensions,
..Default::default()
}
.into())
}
}
macro_rules! array_impls {
($($len:tt)+) => {
$(
impl<T: MakeSchema> MakeSchema for [T; $len] {
no_ref_schema!();
fn schema_name() -> String {
format!("Array_Size_{}_Of_{}", $len, T::schema_name())
}
fn make_schema(gen: &mut SchemaGenerator) -> Result {
let mut extensions = Map::new();
extensions.insert("minItems".to_owned(), json!($len));
extensions.insert("maxItems".to_owned(), json!($len));
Ok(SchemaObject {
instance_type: Some(InstanceType::Array.into()),
items: Some(gen.subschema_for::<T>()?.into()),
extensions,
..Default::default()
}.into())
}
}
)+
}
}
array_impls! {
01 02 03 04 05 06 07 08 09 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32
}
macro_rules! tuple_impls {
($($len:expr => ($($name:ident)+))+) => {
$(
impl<$($name: MakeSchema),+> MakeSchema for ($($name,)+) {
no_ref_schema!();
fn schema_name() -> String {
["Tuple_Of".to_owned()$(, $name::schema_name())+].join("_And_")
}
fn make_schema(gen: &mut SchemaGenerator) -> Result {
let mut extensions = Map::new();
extensions.insert("minItems".to_owned(), json!($len));
extensions.insert("maxItems".to_owned(), json!($len));
let items = vec![
$(gen.subschema_for::<$name>()?),+
];
Ok(SchemaObject {
instance_type: Some(InstanceType::Array.into()),
items: Some(items.into()),
extensions,
..Default::default()
}.into())
}
}
)+
}
}
tuple_impls! {
1 => (T0)
2 => (T0 T1)
3 => (T0 T1 T2)
4 => (T0 T1 T2 T3)
5 => (T0 T1 T2 T3 T4)
6 => (T0 T1 T2 T3 T4 T5)
7 => (T0 T1 T2 T3 T4 T5 T6)
8 => (T0 T1 T2 T3 T4 T5 T6 T7)
9 => (T0 T1 T2 T3 T4 T5 T6 T7 T8)
10 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9)
11 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10)
12 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11)
13 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12)
14 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13)
15 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14)
16 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15)
}
macro_rules! seq_impl {
($($desc:tt)+) => {
impl $($desc)+
where
T: MakeSchema,
{
no_ref_schema!();
fn schema_name() -> String {
format!("Array_Of_{}", T::schema_name())
}
fn make_schema(gen: &mut SchemaGenerator) -> Result {
Ok(SchemaObject {
instance_type: Some(InstanceType::Array.into()),
items: Some(gen.subschema_for::<T>()?.into()),
..Default::default()
}.into())
}
}
};
}
seq_impl!(<T: Ord> MakeSchema for std::collections::BinaryHeap<T>);
seq_impl!(<T: Ord> MakeSchema for std::collections::BTreeSet<T>);
seq_impl!(<T: Eq + core::hash::Hash, H: core::hash::BuildHasher> MakeSchema for std::collections::HashSet<T, H>);
seq_impl!(<T> MakeSchema for std::collections::LinkedList<T>);
seq_impl!(<T> MakeSchema for Vec<T>);
seq_impl!(<T> MakeSchema for std::collections::VecDeque<T>);
macro_rules! map_impl {
($($desc:tt)+) => {
impl $($desc)+
where
K: Into<String>,
V: MakeSchema,
{
no_ref_schema!();
fn schema_name() -> String {
format!("Map_Of_{}", V::schema_name())
}
fn make_schema(gen: &mut SchemaGenerator) -> Result {
let subschema = gen.subschema_for::<V>()?;
let make_schema_bool = gen.settings().bool_schemas == BoolSchemas::AdditionalPropertiesOnly
&& subschema == gen.schema_for_any();
let mut extensions = Map::new();
extensions.insert(
"additionalProperties".to_owned(),
if make_schema_bool {
json!(true)
} else {
json!(subschema)
}
);
Ok(SchemaObject {
instance_type: Some(InstanceType::Object.into()),
extensions,
..Default::default()
}.into())
}
}
};
}
map_impl!(<K: Ord, V> MakeSchema for std::collections::BTreeMap<K, V>);
map_impl!(<K: Eq + core::hash::Hash, V, H: core::hash::BuildHasher> MakeSchema for std::collections::HashMap<K, V, H>);
impl<T: MakeSchema> MakeSchema for Option<T> {
no_ref_schema!();
fn schema_name() -> String {
format!("Nullable_{}", T::schema_name())
}
fn make_schema(gen: &mut SchemaGenerator) -> Result {
let mut schema = gen.subschema_for::<T>()?;
if gen.settings().option_add_null_type {
schema = match schema {
Schema::Bool(true) => Schema::Bool(true),
Schema::Bool(false) => <()>::make_schema(gen)?,
schema => SchemaObject {
any_of: Some(vec![schema, <()>::make_schema(gen)?]),
..Default::default()
}
.into(),
}
}
if gen.settings().option_nullable {
let mut deref = gen.get_schema_object(&schema)?;
deref.extensions.insert("nullable".to_owned(), json!(true));
schema = Schema::Object(deref);
};
Ok(schema)
}
}
impl<T> MakeSchema for std::marker::PhantomData<T> {
no_ref_schema!();
fn schema_name() -> String {
<()>::schema_name()
}
fn make_schema(gen: &mut SchemaGenerator) -> Result {
<()>::make_schema(gen)
}
}
macro_rules! deref_impl {
($($desc:tt)+) => {
impl $($desc)+
where
T: MakeSchema,
{
fn is_referenceable() -> bool {
T::is_referenceable()
}
fn schema_name() -> String {
T::schema_name()
}
fn make_schema(gen: &mut SchemaGenerator) -> Result {
T::make_schema(gen)
}
}
};
}
deref_impl!(<'a, T> MakeSchema for &'a T);
deref_impl!(<'a, T> MakeSchema for &'a mut T);
deref_impl!(<T> MakeSchema for Box<T>);
deref_impl!(<T> MakeSchema for std::rc::Rc<T>);
deref_impl!(<T> MakeSchema for std::sync::Arc<T>);
deref_impl!(<'a, T: ToOwned> MakeSchema for std::borrow::Cow<'a, T>);
impl MakeSchema for serde_json::Value {
no_ref_schema!();
fn schema_name() -> String {
"Any_Value".to_owned()
}
fn make_schema(gen: &mut SchemaGenerator) -> Result {
Ok(gen.schema_for_any())
}
}