valico/json_schema/validators/
of.rs1use serde_json::Value;
2use std::borrow::Cow;
3use std::collections::HashSet;
4
5use super::super::errors;
6use super::super::scope;
7
8#[allow(missing_copy_implementations)]
9pub struct AllOf {
10 pub schemes: Vec<url::Url>,
11}
12
13impl super::Validator for AllOf {
14 fn validate(
15 &self,
16 val: &Value,
17 path: &str,
18 scope: &scope::Scope,
19 _: &super::ValidationState,
20 ) -> super::ValidationState {
21 let mut state = super::ValidationState::new();
22 let mut val = Cow::Borrowed(val);
23
24 let schemas = self
26 .schemes
27 .iter()
28 .map(|url| (url, scope.resolve(url)))
29 .filter_map(|(url, opt)| {
30 if opt.is_none() {
31 state.missing.push(url.clone())
32 }
33 opt
34 })
35 .collect::<Vec<_>>();
36
37 for schema in schemas.iter() {
39 let mut result = schema.validate_in(&val, path);
40 if result.is_valid() && result.replacement.is_some() {
41 *val.to_mut() = result.replacement.take().unwrap();
42 }
43 state.append(result);
44 }
45 if !state.is_valid() {
46 return state;
47 }
48
49 if let Cow::Owned(v) = val {
51 let mut second = Cow::Borrowed(&v);
52
53 for schema in schemas.iter() {
54 let mut result = schema.validate_in(&second, path);
55 if result.is_valid() && result.replacement.is_some() {
56 *second.to_mut() = result.replacement.take().unwrap();
57 }
58 state.append(result);
59 }
60 if let Cow::Owned(_) = second {
61 state.errors.push(Box::new(errors::DivergentDefaults {
62 path: path.to_string(),
63 }));
64 }
65 if !state.is_valid() {
66 return state;
67 }
68 val = Cow::Owned(v);
69 }
70
71 state.set_replacement(val);
72 state
73 }
74}
75
76#[allow(missing_copy_implementations)]
77pub struct AnyOf {
78 pub schemes: Vec<url::Url>,
79}
80
81impl super::Validator for AnyOf {
82 fn validate(
83 &self,
84 val: &Value,
85 path: &str,
86 scope: &scope::Scope,
87 _: &super::ValidationState,
88 ) -> super::ValidationState {
89 let mut state = super::ValidationState::new();
90 let mut val = Cow::Borrowed(val);
91
92 let mut invalid_states = vec![];
93 let mut evaluated: HashSet<String> = HashSet::new();
95 let mut valid = false;
96 for url in self.schemes.iter() {
97 let schema = scope.resolve(url);
98
99 if let Some(schema) = schema {
100 let mut result = schema.validate_in(&val, path);
101
102 state.missing.extend(result.missing.clone());
103
104 if result.is_valid() {
105 if let Some(result) = result.replacement.take() {
106 *val.to_mut() = result;
107 }
108 valid = true;
109 evaluated.extend(result.evaluated);
110 } else {
112 invalid_states.push(result)
113 }
114 } else {
115 state.missing.push(url.clone())
116 }
117 }
118
119 if !valid {
120 state.errors.push(Box::new(errors::AnyOf {
121 path: path.to_string(),
122 states: invalid_states,
123 }))
124 } else {
125 state.evaluated.extend(evaluated);
126 }
127
128 state.set_replacement(val);
129 state
130 }
131}
132
133#[allow(missing_copy_implementations)]
134pub struct OneOf {
135 pub schemes: Vec<url::Url>,
136}
137
138impl super::Validator for OneOf {
139 fn validate(
140 &self,
141 val: &Value,
142 path: &str,
143 scope: &scope::Scope,
144 _: &super::ValidationState,
145 ) -> super::ValidationState {
146 let mut state = super::ValidationState::new();
147 let mut val = Cow::Borrowed(val);
148
149 let mut states = vec![];
150 let mut valid = 0;
151 let mut evaluated = HashSet::new();
152 for url in self.schemes.iter() {
153 let schema = scope.resolve(url);
154
155 if let Some(schema) = schema {
156 let mut result = schema.validate_in(&val, path);
157
158 state.missing.extend(result.missing.clone());
159
160 if result.is_valid() {
161 if let Some(result) = result.replacement.take() {
162 *val.to_mut() = result;
163 }
164 valid += 1;
165 evaluated = result.evaluated;
166 } else {
167 states.push(result)
168 }
169 } else {
170 state.missing.push(url.clone())
171 }
172 }
173
174 if valid != 1 {
175 state.errors.push(Box::new(errors::OneOf {
176 path: path.to_string(),
177 states,
178 }))
179 } else {
180 state.evaluated = evaluated;
181 }
182
183 state.set_replacement(val);
184 state
185 }
186}