schemars/
flatten.rs

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