1use serde_json::{to_value, Value};
2
3use super::super::json_schema;
4use super::coercers;
5use super::errors;
6use super::param;
7use super::validators;
8
9pub type DynBuilder = Box<dyn Fn(&mut json_schema::Builder) + Send + Sync>;
10
11pub struct Builder {
12 requires: Vec<param::Param>,
13 optional: Vec<param::Param>,
14 validators: validators::Validators,
15 schema_builder: Option<DynBuilder>,
16 schema_id: Option<url::Url>,
17}
18
19unsafe impl Send for Builder {}
20
21impl Builder {
22 pub fn new() -> Builder {
23 Builder {
24 requires: vec![],
25 optional: vec![],
26 validators: vec![],
27 schema_builder: None,
28 schema_id: None,
29 }
30 }
31
32 pub fn build<F>(rules: F) -> Builder
33 where
34 F: FnOnce(&mut Builder),
35 {
36 let mut builder = Builder::new();
37 rules(&mut builder);
38
39 builder
40 }
41
42 pub fn get_required(&self) -> &Vec<param::Param> {
43 &self.requires
44 }
45
46 pub fn get_optional(&self) -> &Vec<param::Param> {
47 &self.optional
48 }
49
50 pub fn get_validators(&self) -> &validators::Validators {
51 &self.validators
52 }
53
54 pub fn req_defined(&mut self, name: &str) {
55 let params = param::Param::new(name);
56 self.requires.push(params);
57 }
58
59 pub fn req_typed(&mut self, name: &str, coercer: Box<dyn coercers::Coercer + Send + Sync>) {
60 let params = param::Param::new_with_coercer(name, coercer);
61 self.requires.push(params);
62 }
63
64 pub fn req_nested<F>(
65 &mut self,
66 name: &str,
67 coercer: Box<dyn coercers::Coercer + Send + Sync>,
68 nest_def: F,
69 ) where
70 F: FnOnce(&mut Builder),
71 {
72 let nest_builder = Builder::build(nest_def);
73 let params = param::Param::new_with_nest(name, coercer, nest_builder);
74 self.requires.push(params);
75 }
76
77 pub fn req<F>(&mut self, name: &str, param_builder: F)
78 where
79 F: FnOnce(&mut param::Param),
80 {
81 let params = param::Param::build(name, param_builder);
82 self.requires.push(params);
83 }
84
85 pub fn opt_defined(&mut self, name: &str) {
86 let params = param::Param::new(name);
87 self.optional.push(params);
88 }
89
90 pub fn opt_typed(&mut self, name: &str, coercer: Box<dyn coercers::Coercer + Send + Sync>) {
91 let params = param::Param::new_with_coercer(name, coercer);
92 self.optional.push(params);
93 }
94
95 pub fn opt_nested<F>(
96 &mut self,
97 name: &str,
98 coercer: Box<dyn coercers::Coercer + Send + Sync>,
99 nest_def: F,
100 ) where
101 F: FnOnce(&mut Builder),
102 {
103 let nest_builder = Builder::build(nest_def);
104 let params = param::Param::new_with_nest(name, coercer, nest_builder);
105 self.optional.push(params);
106 }
107
108 pub fn opt<F>(&mut self, name: &str, param_builder: F)
109 where
110 F: FnOnce(&mut param::Param),
111 {
112 let params = param::Param::build(name, param_builder);
113 self.optional.push(params);
114 }
115
116 pub fn validate(&mut self, validator: Box<dyn validators::Validator + 'static + Send + Sync>) {
117 self.validators.push(validator);
118 }
119
120 pub fn validate_with<F>(&mut self, validator: F)
121 where
122 F: Fn(&Value, &str) -> validators::ValidatorResult + 'static + Send + Sync,
123 {
124 self.validators.push(Box::new(validator));
125 }
126
127 pub fn mutually_exclusive(&mut self, params: &[&str]) {
128 let validator = Box::new(validators::MutuallyExclusive::new(params));
129 self.validators.push(validator);
130 }
131
132 pub fn exactly_one_of(&mut self, params: &[&str]) {
133 let validator = Box::new(validators::ExactlyOneOf::new(params));
134 self.validators.push(validator);
135 }
136
137 pub fn at_least_one_of(&mut self, params: &[&str]) {
138 let validator = Box::new(validators::AtLeastOneOf::new(params));
139 self.validators.push(validator);
140 }
141
142 pub fn schema_id(&mut self, id: url::Url) {
143 self.schema_id = Some(id);
144 }
145
146 pub fn schema<F>(&mut self, build: F)
147 where
148 F: Fn(&mut json_schema::Builder) + 'static + Send + Sync,
149 {
150 self.schema_builder = Some(Box::new(build));
151 }
152
153 pub fn build_schemes(
154 &mut self,
155 scope: &mut json_schema::Scope,
156 ) -> Result<(), json_schema::SchemaError> {
157 for param in self.requires.iter_mut().chain(self.optional.iter_mut()) {
158 if param.schema_builder.is_some() {
159 let json_schema =
160 json_schema::builder::schema_box(param.schema_builder.take().unwrap());
161 let id = scope.compile(to_value(&json_schema).unwrap(), true)?;
162 param.schema_id = Some(id);
163 }
164
165 if param.nest.is_some() {
166 param.nest.as_mut().unwrap().build_schemes(scope)?;
167 }
168 }
169
170 if self.schema_builder.is_some() {
171 let json_schema = json_schema::builder::schema_box(self.schema_builder.take().unwrap());
172 let id = scope.compile(to_value(json_schema).unwrap(), true)?;
173 self.schema_id = Some(id);
174 }
175
176 Ok(())
177 }
178
179 pub fn process(
180 &self,
181 val: &mut Value,
182 scope: Option<&json_schema::Scope>,
183 ) -> json_schema::ValidationState {
184 self.process_nest(val, "", scope)
185 }
186
187 pub fn process_nest(
188 &self,
189 val: &mut Value,
190 path: &str,
191 scope: Option<&json_schema::Scope>,
192 ) -> json_schema::ValidationState {
193 let mut state = if val.is_array() {
194 let mut state = json_schema::ValidationState::new();
195 let array = val.as_array_mut().unwrap();
196 for (idx, item) in array.iter_mut().enumerate() {
197 let item_path = [path, idx.to_string().as_ref()].join("/");
198 if item.is_object() {
199 let process_state = self.process_object(item, item_path.as_ref(), scope);
200 state.append(process_state);
201 } else {
202 state.errors.push(Box::new(errors::WrongType {
203 path: item_path.to_string(),
204 detail: "List value is not and object".to_string(),
205 }))
206 }
207 }
208
209 state
210 } else if val.is_object() {
211 self.process_object(val, path, scope)
212 } else {
213 let mut state = json_schema::ValidationState::new();
214 state.errors.push(Box::new(errors::WrongType {
215 path: path.to_string(),
216 detail: "Value is not an object or an array".to_string(),
217 }));
218
219 state
220 };
221
222 let path = if path.is_empty() { "/" } else { path };
223
224 if let Some(ref id) = self.schema_id {
225 if let Some(scope) = scope {
226 let schema = scope.resolve(id);
227 match schema {
228 Some(schema) => state.append(schema.validate_in(val, path)),
229 None => state.missing.push(id.clone()),
230 }
231 }
232 }
233
234 state
235 }
236
237 fn process_object(
238 &self,
239 val: &mut Value,
240 path: &str,
241 scope: Option<&json_schema::Scope>,
242 ) -> json_schema::ValidationState {
243 let mut state = json_schema::ValidationState::new();
244
245 {
246 let object = val.as_object_mut().expect("We expect object here");
247 for param in self.requires.iter() {
248 let name = ¶m.name;
249 let present = object.contains_key(name);
250 let param_path = [path, name.as_ref()].join("/");
251 if present {
252 let process_result =
253 param.process(object.get_mut(name).unwrap(), param_path.as_ref(), scope);
254 if let Some(new_value) = process_result.value {
255 object.insert(name.clone(), new_value);
256 }
257 state.append(process_result.state);
258 } else {
259 state.errors.push(Box::new(errors::Required {
260 path: param_path.clone(),
261 }))
262 }
263 }
264
265 for param in self.optional.iter() {
266 let name = ¶m.name;
267 let present = object.contains_key(name);
268 let param_path = [path, name.as_ref()].join("/");
269 if present {
270 let process_result =
271 param.process(object.get_mut(name).unwrap(), param_path.as_ref(), scope);
272 if let Some(new_value) = process_result.value {
273 object.insert(name.clone(), new_value);
274 }
275 state.append(process_result.state);
276 }
277 }
278 }
279
280 let path = if path.is_empty() { "/" } else { path };
281
282 for validator in self.validators.iter() {
283 match validator.validate(val, path) {
284 Ok(()) => (),
285 Err(err) => {
286 state.errors.extend(err);
287 }
288 };
289 }
290
291 {
292 if state.is_valid() {
293 let object = val.as_object_mut().expect("We expect object here");
294
295 for param in self.optional.iter() {
297 let name = ¶m.name;
298 let present = object.contains_key(name);
299 if !present {
300 if let Some(val) = param.default.as_ref() {
301 object.insert(name.clone(), val.clone());
302 }
303 }
304 }
305 }
306 }
307
308 state
309 }
310}