#[cfg(test)]
mod test_json_schema_macro;
use std::{collections::BTreeMap, sync::Arc};
pub type Fields = Arc<BTreeMap<&'static str, Option<Arc<Element>>>>;
#[derive(Debug)]
pub enum Element {
Scalar,
Array(Arc<Element>),
Object(Fields),
}
impl Element {
pub fn to_expectation(&self) -> Expect {
match self {
Element::Scalar => Expect::Scalar,
Element::Array(element) => Expect::Array(Arc::clone(element)),
Element::Object(fields) => Expect::Object(Arc::clone(fields)),
}
}
}
#[derive(Debug)]
pub enum Expect {
Scalar,
Array(Arc<Element>),
Object(Fields),
UnmatchedScalar,
UnmatchedArray,
UnmatchedObject,
OutOfSchema,
}
#[macro_export]
#[doc(hidden)]
macro_rules! json_schema {
(@array [$($elems:expr)*] {$($map:tt)*} $($rest:tt)*) => {
std::sync::Arc::new({$crate::json::schema::Element::Object({
let mut object = std::collections::BTreeMap::new();
$crate::json_schema!(@object object () ($($map)+) ($($map)+));
std::sync::Arc::new(object)
})})
};
(@object $object:ident () () ()) => {};
(@object $object:ident [$($key:tt)+] , $($rest:tt)*) => {
let _unused = $object.insert(($($key:tt)+).into(), None);
$crate::json_schema!(@object $object () ($($rest)*) ($($rest)*));
};
(@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
let _unused = $object.insert(($($key)+).into(), Some(std::sync::Arc::new($value)));
$crate::json_schema!(@object $object () ($($rest)*) ($($rest)*));
};
(@object $object:ident [$($key:tt)+] ($value:expr)) => {
let _unused = $object.insert(($($key)+).into(), Some(std::sync::Arc::new($value)));
$crate::json_schema!(@object $object () () ());
};
(@object $object:ident [$($key:tt)+] (, $($rest:tt)*)) => {
let _unused = $object.insert(($($key)+).into(), None);
$crate::json_schema!(@object $object () ($($rest)*) ($($rest)*));
};
(@object $object:ident [$($key:tt)+] ()) => {
let _unused = $object.insert(($($key)+).into(), None);
};
(@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
$crate::json_schema!(@object $object [$($key)+] ($crate::json_schema!([$($array)*])) $($rest)*);
};
(@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
$crate::json_schema!(@object $object [$($key)+] ($crate::json_schema!({$($map)*})) $($rest)*);
};
(@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => {
$crate::json_schema!(@object $object [$($key)+] ($crate::json_schema!($value)) , $($rest)*);
};
(@object $object:ident ($($key:tt)+) (, $($rest:tt)*) $copy:tt) => {
let _unused = $object.insert(($($key)+).into(), None);
$crate::json_schema!(@object $object [$($key)+] (, $($rest)*));
};
(@object $object:ident ($($key:tt)+) ($($rest:tt)*) $copy:tt) => {
let __unused = $object.insert(($($key)+).into(), None);
$crate::json_schema!(@object $object [$($key)+] ($($rest)*));
};
(@object $object:ident ($($key:tt)*) ($json:tt $($rest:tt)*) $copy:tt) => {
$crate::json_schema!(@object $object ($($key)* $json) ($($rest)*) ($($rest)*));
};
([]) => {
$crate::json::schema::Element::Array(std::sync::Arc::new($crate::json::schema::Element::Scalar))
};
([ $($json:tt)+ ]) => {
$crate::json::schema::Element::Array($crate::json_schema!(@array [] $($json)+))
};
({}) => {
$crate::json::schema::Element::Object(std::sync::Arc::new(std::collections::BTreeMap::new()))
};
({ $($json:tt)+ }) => {
$crate::json::schema::Element::Object({
let mut object = std::collections::BTreeMap::new();
$crate::json_schema!(@object object () ($($json)+) ($($json)+));
std::sync::Arc::new(object)
})
};
($other:expr) => {
$other
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! json_unexpected {
() => {};
}
#[macro_export]
#[doc(hidden)]
macro_rules! json_expect_expr_comma {
($e:expr , $($tt:tt)*) => {};
}