1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
use crate::schema::*; use crate::{JsonSchemaError, Map, Result, Set}; impl Schema { pub fn flatten(self, other: Self) -> Result { if is_null_type(&self) { return Ok(other); } else if is_null_type(&other) { return Ok(self); } let s1 = ensure_object_type(self)?; let s2 = ensure_object_type(other)?; Ok(Schema::Object(s1.merge(s2))) } } 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!(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 { definitions: self.definitions.merge(other.definitions), schema: self.schema.or(other.schema), 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, } } } 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, or: max_properties min_properties additional_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: Ord, V> Merge for Map<K, V> { 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, } } fn ensure_object_type(schema: Schema) -> Result<SchemaObject> { let s = match schema { Schema::Object(s) => s, s => { return Err(JsonSchemaError::new( "Only schemas with type `object` or `null` can be flattened.", s, )) } }; match s.instance_type { Some(SingleOrVec::Single(ref t)) if **t != InstanceType::Object => { Err(JsonSchemaError::new( "Only schemas with type `object` or `null` can be flattened.", s.into(), )) } Some(SingleOrVec::Vec(ref t)) if !t.contains(&InstanceType::Object) => { Err(JsonSchemaError::new( "Only schemas with type `object` or `null` can be flattened.", s.into(), )) } _ => Ok(s), } }