use crate::schema::*;
use crate::{Map, Set};
impl Schema {
#[doc(hidden)]
pub fn flatten(self, other: Self) -> Schema {
if is_null_type(&self) {
return other;
} else if is_null_type(&other) {
return self;
}
let s1: SchemaObject = self.into();
let s2: SchemaObject = other.into();
Schema::Object(s1.merge(s2))
}
}
pub(crate) trait Merge: Sized {
fn merge(self, other: Self) -> Self;
}
macro_rules! impl_merge {
($ty:ident { merge: $($merge_field:ident)*, or: $($or_field:ident)*, }) => {
impl Merge for $ty {
fn merge(self, other: Self) -> Self {
$ty {
$($merge_field: self.$merge_field.merge(other.$merge_field),)*
$($or_field: self.$or_field.or(other.$or_field),)*
}
}
}
};
($ty:ident { or: $($or_field:ident)*, }) => {
impl_merge!( $ty { merge: , or: $($or_field)*, });
};
}
impl Merge for Option<Box<Schema>> {
fn merge(self, other: Self) -> Self {
match (self.map(|x| *x), other.map(|x| *x)) {
(Some(Schema::Bool(true)), _) => Some(Box::new(true.into())),
(_, Some(Schema::Bool(true))) => Some(Box::new(true.into())),
(None, _) => None,
(_, None) => None,
(Some(Schema::Object(s1)), Some(Schema::Object(s2))) => {
Some(Box::new(Schema::Object(s1.merge(s2))))
}
(Some(s1 @ Schema::Object(_)), Some(Schema::Bool(false))) => Some(Box::new(s1)),
(Some(Schema::Bool(false)), Some(s2 @ Schema::Object(_))) => Some(Box::new(s2)),
(Some(Schema::Bool(false)), Some(Schema::Bool(false))) => Some(Box::new(false.into())),
}
}
}
impl_merge!(SchemaObject {
merge: extensions instance_type enum_values
metadata subschemas number string array object,
or: format const_value reference,
});
impl Merge for Metadata {
fn merge(self, other: Self) -> Self {
Metadata {
id: self.id.or(other.id),
title: self.title.or(other.title),
description: self.description.or(other.description),
default: self.default.or(other.default),
deprecated: self.deprecated || other.deprecated,
read_only: self.read_only || other.read_only,
write_only: self.write_only || other.write_only,
examples: self.examples.merge(other.examples),
}
}
}
impl_merge!(SubschemaValidation {
or: all_of any_of one_of not if_schema then_schema else_schema,
});
impl_merge!(NumberValidation {
or: multiple_of maximum exclusive_maximum minimum exclusive_minimum,
});
impl_merge!(StringValidation {
or: max_length min_length pattern,
});
impl_merge!(ArrayValidation {
or: items additional_items max_items min_items unique_items contains,
});
impl_merge!(ObjectValidation {
merge: required properties pattern_properties additional_properties,
or: max_properties min_properties property_names,
});
impl<T: Merge> Merge for Option<T> {
fn merge(self, other: Self) -> Self {
match (self, other) {
(Some(x), Some(y)) => Some(x.merge(y)),
(None, y) => y,
(x, None) => x,
}
}
}
impl<T: Merge> Merge for Box<T> {
fn merge(mut self, other: Self) -> Self {
*self = (*self).merge(*other);
self
}
}
impl<T> Merge for Vec<T> {
fn merge(mut self, other: Self) -> Self {
self.extend(other);
self
}
}
impl<K, V> Merge for Map<K, V>
where
K: std::hash::Hash + Eq + Ord,
{
fn merge(mut self, other: Self) -> Self {
self.extend(other);
self
}
}
impl<T: Ord> Merge for Set<T> {
fn merge(mut self, other: Self) -> Self {
self.extend(other);
self
}
}
impl Merge for SingleOrVec<InstanceType> {
fn merge(self, other: Self) -> Self {
if self == other {
return self;
}
let mut vec = match (self, other) {
(SingleOrVec::Vec(v1), SingleOrVec::Vec(v2)) => v1.merge(v2),
(SingleOrVec::Vec(mut v), SingleOrVec::Single(s))
| (SingleOrVec::Single(s), SingleOrVec::Vec(mut v)) => {
v.push(*s);
v
}
(SingleOrVec::Single(s1), SingleOrVec::Single(s2)) => vec![*s1, *s2],
};
vec.sort();
vec.dedup();
SingleOrVec::Vec(vec)
}
}
fn is_null_type(schema: &Schema) -> bool {
let s = match schema {
Schema::Object(s) => s,
_ => return false,
};
match &s.instance_type {
Some(SingleOrVec::Single(t)) if **t == InstanceType::Null => true,
_ => false,
}
}