use serde_json::Value;
pub trait JsonSchema {
fn json_schema(&self) -> Value;
}
pub type NestedSchemaEntry = (&'static str, fn() -> serde_json::Value);
pub trait CollectNestedSchemas {
fn collect_nested_schemas(&self, _out: &mut Vec<NestedSchemaEntry>) {}
}
impl JsonSchema for crate::primitives::ZString {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
impl JsonSchema for crate::primitives::ZNumber {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
impl JsonSchema for crate::primitives::ZInt {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
impl JsonSchema for crate::primitives::ZBoolean {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
impl JsonSchema for crate::primitives::ZBytes {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
#[cfg(feature = "decimal")]
impl JsonSchema for crate::primitives::ZDecimal {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
#[cfg(feature = "net")]
impl JsonSchema for crate::primitives::ZIpNetwork {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
impl JsonSchema for crate::primitives::ZSocketAddr {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
impl JsonSchema for crate::primitives::ZJsonValue {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
#[cfg(feature = "file")]
impl JsonSchema for crate::primitives::ZFile {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
#[cfg(feature = "std")]
impl JsonSchema for crate::primitives::ZDuration {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
#[cfg(feature = "std")]
impl JsonSchema for crate::primitives::ZPath {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
impl JsonSchema for crate::primitives::ZEnum {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
impl JsonSchema for crate::primitives::ZAny {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
#[cfg(feature = "chrono")]
impl JsonSchema for crate::primitives::ZDate {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
#[cfg(feature = "chrono")]
impl JsonSchema for crate::primitives::ZDateTime {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
impl<T: crate::schema::VldSchema + JsonSchema> JsonSchema for crate::collections::ZArray<T> {
fn json_schema(&self) -> Value {
self.to_json_schema_inner()
}
}
impl<V: crate::schema::VldSchema + JsonSchema> JsonSchema for crate::collections::ZRecord<V> {
fn json_schema(&self) -> Value {
self.to_json_schema_inner()
}
}
impl<T> JsonSchema for crate::collections::ZSet<T>
where
T: crate::schema::VldSchema + JsonSchema,
T::Output: Eq + std::hash::Hash,
{
fn json_schema(&self) -> Value {
self.to_json_schema_inner()
}
}
impl<S: crate::schema::VldSchema + JsonSchema> JsonSchema for crate::modifiers::ZOptional<S> {
fn json_schema(&self) -> Value {
let inner = self.inner_schema().json_schema();
serde_json::json!({
"oneOf": [inner, {"type": "null"}]
})
}
}
impl<S: crate::schema::VldSchema + JsonSchema> JsonSchema for crate::modifiers::ZNullable<S> {
fn json_schema(&self) -> Value {
let inner = self.inner_schema().json_schema();
serde_json::json!({
"oneOf": [inner, {"type": "null"}]
})
}
}
impl<S: crate::schema::VldSchema + JsonSchema> JsonSchema for crate::modifiers::ZNullish<S> {
fn json_schema(&self) -> Value {
let inner = self.inner_schema().json_schema();
serde_json::json!({
"oneOf": [inner, {"type": "null"}]
})
}
}
impl<S: crate::schema::VldSchema + JsonSchema> JsonSchema for crate::modifiers::ZDefault<S>
where
S::Output: Clone,
{
fn json_schema(&self) -> Value {
self.inner_schema().json_schema()
}
}
impl<S: crate::schema::VldSchema + JsonSchema> JsonSchema for crate::combinators::ZCatch<S>
where
S::Output: Clone,
{
fn json_schema(&self) -> Value {
self.inner_schema().json_schema()
}
}
impl<S: crate::schema::VldSchema + JsonSchema, F> JsonSchema for crate::combinators::ZRefine<S, F>
where
F: Fn(&S::Output) -> bool,
{
fn json_schema(&self) -> Value {
self.inner_schema().json_schema()
}
}
impl<S: crate::schema::VldSchema + JsonSchema, F, U> JsonSchema
for crate::combinators::ZTransform<S, F, U>
where
F: Fn(S::Output) -> U,
{
fn json_schema(&self) -> Value {
self.inner_schema().json_schema()
}
}
impl<S: crate::schema::VldSchema + JsonSchema> JsonSchema for crate::combinators::ZDescribe<S> {
fn json_schema(&self) -> Value {
let mut schema = self.inner_schema().json_schema();
let desc = self.description();
if !desc.is_empty() {
schema["description"] = Value::String(desc.to_string());
}
schema
}
}
impl<A, B> JsonSchema for crate::combinators::ZUnion2<A, B>
where
A: crate::schema::VldSchema + JsonSchema,
B: crate::schema::VldSchema + JsonSchema,
{
fn json_schema(&self) -> Value {
serde_json::json!({
"oneOf": [self.schema_a().json_schema(), self.schema_b().json_schema()]
})
}
}
impl<A, B, C> JsonSchema for crate::combinators::ZUnion3<A, B, C>
where
A: crate::schema::VldSchema + JsonSchema,
B: crate::schema::VldSchema + JsonSchema,
C: crate::schema::VldSchema + JsonSchema,
{
fn json_schema(&self) -> Value {
serde_json::json!({
"oneOf": [
self.schema_a().json_schema(),
self.schema_b().json_schema(),
self.schema_c().json_schema(),
]
})
}
}
impl<A, B> JsonSchema for crate::combinators::ZIntersection<A, B>
where
A: crate::schema::VldSchema + JsonSchema,
B: crate::schema::VldSchema + JsonSchema,
{
fn json_schema(&self) -> Value {
serde_json::json!({
"allOf": [self.schema_a().json_schema(), self.schema_b().json_schema()]
})
}
}
impl<T, F> JsonSchema for crate::schema::NestedSchema<T, F>
where
F: Fn(&serde_json::Value) -> Result<T, crate::error::VldError>,
{
fn json_schema(&self) -> Value {
match self.name {
Some(name) => serde_json::json!({
"$ref": format!("#/components/schemas/{}", name)
}),
None => serde_json::json!({ "type": "object" }),
}
}
}
impl JsonSchema for crate::object::ZObject {
fn json_schema(&self) -> Value {
self.to_json_schema()
}
}
impl CollectNestedSchemas for crate::primitives::ZString {}
impl CollectNestedSchemas for crate::primitives::ZNumber {}
impl CollectNestedSchemas for crate::primitives::ZInt {}
impl CollectNestedSchemas for crate::primitives::ZBoolean {}
impl CollectNestedSchemas for crate::primitives::ZBytes {}
#[cfg(feature = "decimal")]
impl CollectNestedSchemas for crate::primitives::ZDecimal {}
#[cfg(feature = "net")]
impl CollectNestedSchemas for crate::primitives::ZIpNetwork {}
impl CollectNestedSchemas for crate::primitives::ZSocketAddr {}
impl CollectNestedSchemas for crate::primitives::ZJsonValue {}
impl CollectNestedSchemas for crate::primitives::ZEnum {}
impl CollectNestedSchemas for crate::primitives::ZAny {}
#[cfg(feature = "file")]
impl CollectNestedSchemas for crate::primitives::ZFile {}
#[cfg(feature = "std")]
impl CollectNestedSchemas for crate::primitives::ZDuration {}
#[cfg(feature = "std")]
impl CollectNestedSchemas for crate::primitives::ZPath {}
#[cfg(feature = "chrono")]
impl CollectNestedSchemas for crate::primitives::ZDate {}
#[cfg(feature = "chrono")]
impl CollectNestedSchemas for crate::primitives::ZDateTime {}
impl<T: crate::schema::VldSchema + CollectNestedSchemas> CollectNestedSchemas
for crate::collections::ZArray<T>
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.element_schema().collect_nested_schemas(out);
}
}
impl<V: crate::schema::VldSchema + CollectNestedSchemas> CollectNestedSchemas
for crate::collections::ZRecord<V>
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.value_schema_ref().collect_nested_schemas(out);
}
}
impl<T> CollectNestedSchemas for crate::collections::ZSet<T>
where
T: crate::schema::VldSchema + CollectNestedSchemas,
T::Output: Eq + std::hash::Hash,
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.element_schema().collect_nested_schemas(out);
}
}
impl<S: crate::schema::VldSchema + CollectNestedSchemas> CollectNestedSchemas
for crate::modifiers::ZOptional<S>
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.inner_schema().collect_nested_schemas(out);
}
}
impl<S: crate::schema::VldSchema + CollectNestedSchemas> CollectNestedSchemas
for crate::modifiers::ZNullable<S>
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.inner_schema().collect_nested_schemas(out);
}
}
impl<S: crate::schema::VldSchema + CollectNestedSchemas> CollectNestedSchemas
for crate::modifiers::ZNullish<S>
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.inner_schema().collect_nested_schemas(out);
}
}
impl<S: crate::schema::VldSchema + CollectNestedSchemas> CollectNestedSchemas
for crate::modifiers::ZDefault<S>
where
S::Output: Clone,
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.inner_schema().collect_nested_schemas(out);
}
}
impl<S: crate::schema::VldSchema + CollectNestedSchemas> CollectNestedSchemas
for crate::combinators::ZCatch<S>
where
S::Output: Clone,
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.inner_schema().collect_nested_schemas(out);
}
}
impl<S: crate::schema::VldSchema + CollectNestedSchemas, F> CollectNestedSchemas
for crate::combinators::ZRefine<S, F>
where
F: Fn(&S::Output) -> bool,
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.inner_schema().collect_nested_schemas(out);
}
}
impl<S: crate::schema::VldSchema + CollectNestedSchemas, F, U> CollectNestedSchemas
for crate::combinators::ZTransform<S, F, U>
where
F: Fn(S::Output) -> U,
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.inner_schema().collect_nested_schemas(out);
}
}
impl<S: crate::schema::VldSchema + CollectNestedSchemas> CollectNestedSchemas
for crate::combinators::ZDescribe<S>
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.inner_schema().collect_nested_schemas(out);
}
}
impl<A, B> CollectNestedSchemas for crate::combinators::ZUnion2<A, B>
where
A: crate::schema::VldSchema + CollectNestedSchemas,
B: crate::schema::VldSchema + CollectNestedSchemas,
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.schema_a().collect_nested_schemas(out);
self.schema_b().collect_nested_schemas(out);
}
}
impl<A, B, C> CollectNestedSchemas for crate::combinators::ZUnion3<A, B, C>
where
A: crate::schema::VldSchema + CollectNestedSchemas,
B: crate::schema::VldSchema + CollectNestedSchemas,
C: crate::schema::VldSchema + CollectNestedSchemas,
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.schema_a().collect_nested_schemas(out);
self.schema_b().collect_nested_schemas(out);
self.schema_c().collect_nested_schemas(out);
}
}
impl<A, B> CollectNestedSchemas for crate::combinators::ZIntersection<A, B>
where
A: crate::schema::VldSchema + CollectNestedSchemas,
B: crate::schema::VldSchema + CollectNestedSchemas,
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
self.schema_a().collect_nested_schemas(out);
self.schema_b().collect_nested_schemas(out);
}
}
impl<T, F> CollectNestedSchemas for crate::schema::NestedSchema<T, F>
where
F: Fn(&serde_json::Value) -> Result<T, crate::error::VldError>,
{
fn collect_nested_schemas(&self, out: &mut Vec<NestedSchemaEntry>) {
if let (Some(name), Some(f)) = (self.name, self.json_schema_fn) {
out.push((name, f));
}
}
}
impl CollectNestedSchemas for crate::object::ZObject {}
pub fn to_openapi_document(name: &str, schema: &Value) -> Value {
serde_json::json!({
"openapi": "3.1.0",
"info": { "title": "API", "version": "1.0.0" },
"paths": {},
"components": {
"schemas": {
name: schema
}
}
})
}
pub fn to_openapi_document_multi(schemas: &[(&str, Value)]) -> Value {
let mut map = serde_json::Map::new();
for (name, schema) in schemas {
map.insert(name.to_string(), schema.clone());
}
serde_json::json!({
"openapi": "3.1.0",
"info": { "title": "API", "version": "1.0.0" },
"paths": {},
"components": {
"schemas": Value::Object(map)
}
})
}