tamasfe_schemars/
flatten.rs

1use crate::schema::*;
2use crate::{Map, Set};
3
4impl Schema {
5    #[doc(hidden)]
6    pub fn flatten(self, other: Self) -> Schema {
7        if is_null_type(&self) {
8            return other;
9        } else if is_null_type(&other) {
10            return self;
11        }
12        let s1: SchemaObject = self.into();
13        let s2: SchemaObject = other.into();
14        Schema::Object(s1.merge(s2))
15    }
16}
17
18pub(crate) trait Merge: Sized {
19    fn merge(self, other: Self) -> Self;
20}
21
22macro_rules! impl_merge {
23    ($ty:ident { merge: $($merge_field:ident)*, or: $($or_field:ident)*, }) => {
24        impl Merge for $ty {
25            fn merge(self, other: Self) -> Self {
26                $ty {
27                    $($merge_field: self.$merge_field.merge(other.$merge_field),)*
28                    $($or_field: self.$or_field.or(other.$or_field),)*
29                }
30            }
31        }
32    };
33    ($ty:ident { or: $($or_field:ident)*, }) => {
34        impl_merge!( $ty { merge: , or: $($or_field)*, });
35    };
36}
37
38impl_merge!(SchemaObject {
39    merge: extensions instance_type enum_values
40        metadata subschemas number string array object,
41    or: format const_value reference,
42});
43
44impl Merge for Metadata {
45    fn merge(self, other: Self) -> Self {
46        Metadata {
47            id: self.id.or(other.id),
48            title: self.title.or(other.title),
49            description: self.description.or(other.description),
50            default: self.default.or(other.default),
51            deprecated: self.deprecated || other.deprecated,
52            read_only: self.read_only || other.read_only,
53            write_only: self.write_only || other.write_only,
54            examples: self.examples.merge(other.examples),
55        }
56    }
57}
58
59impl_merge!(SubschemaValidation {
60    or: all_of any_of one_of not if_schema then_schema else_schema,
61});
62
63impl_merge!(NumberValidation {
64    or: multiple_of maximum exclusive_maximum minimum exclusive_minimum,
65});
66
67impl_merge!(StringValidation {
68    or: max_length min_length pattern,
69});
70
71impl_merge!(ArrayValidation {
72    or: items additional_items max_items min_items unique_items contains,
73});
74
75impl_merge!(ObjectValidation {
76    merge: required properties pattern_properties,
77    or: max_properties min_properties additional_properties property_names,
78});
79
80impl<T: Merge> Merge for Option<T> {
81    fn merge(self, other: Self) -> Self {
82        match (self, other) {
83            (Some(x), Some(y)) => Some(x.merge(y)),
84            (None, y) => y,
85            (x, None) => x,
86        }
87    }
88}
89
90impl<T: Merge> Merge for Box<T> {
91    fn merge(mut self, other: Self) -> Self {
92        *self = (*self).merge(*other);
93        self
94    }
95}
96
97impl<T> Merge for Vec<T> {
98    fn merge(mut self, other: Self) -> Self {
99        self.extend(other);
100        self
101    }
102}
103
104impl<K, V> Merge for Map<K, V>
105where
106    K: std::hash::Hash + Eq + Ord,
107{
108    fn merge(mut self, other: Self) -> Self {
109        self.extend(other);
110        self
111    }
112}
113
114impl<T: Ord> Merge for Set<T> {
115    fn merge(mut self, other: Self) -> Self {
116        self.extend(other);
117        self
118    }
119}
120
121impl Merge for SingleOrVec<InstanceType> {
122    fn merge(self, other: Self) -> Self {
123        if self == other {
124            return self;
125        }
126        let mut vec = match (self, other) {
127            (SingleOrVec::Vec(v1), SingleOrVec::Vec(v2)) => v1.merge(v2),
128            (SingleOrVec::Vec(mut v), SingleOrVec::Single(s))
129            | (SingleOrVec::Single(s), SingleOrVec::Vec(mut v)) => {
130                v.push(*s);
131                v
132            }
133            (SingleOrVec::Single(s1), SingleOrVec::Single(s2)) => vec![*s1, *s2],
134        };
135        vec.sort();
136        vec.dedup();
137        SingleOrVec::Vec(vec)
138    }
139}
140
141fn is_null_type(schema: &Schema) -> bool {
142    let s = match schema {
143        Schema::Object(s) => s,
144        _ => return false,
145    };
146    match &s.instance_type {
147        Some(SingleOrVec::Single(t)) if **t == InstanceType::Null => true,
148        _ => false,
149    }
150}