valico/json_schema/validators/
contains.rs1use serde_json::Value;
2use std::borrow::Cow;
3
4use super::super::errors;
5use super::super::scope;
6
7#[allow(missing_copy_implementations)]
8pub struct Contains {
9 pub url: url::Url,
10 pub max_contains: Option<u64>,
11 pub min_contains: Option<u64>,
12}
13
14impl super::Validator for Contains {
15 fn validate(
16 &self,
17 val: &Value,
18 path: &str,
19 scope: &scope::Scope,
20 _: &super::ValidationState,
21 ) -> super::ValidationState {
22 let mut array = Cow::Borrowed(nonstrict_process!(val.as_array(), path));
23
24 let schema = scope.resolve(&self.url);
25 let mut state = super::ValidationState::new();
26
27 if let Some(schema) = schema {
28 let mut matched_count = 0;
29 for idx in 0..array.len() {
30 let item_path = [path, idx.to_string().as_ref()].join("/");
31 let item = &array[idx];
32 let mut result = schema.validate_in(item, item_path.as_ref());
33 if result.is_valid() {
34 matched_count += 1;
35 if let Some(result) = result.replacement.take() {
36 array.to_mut()[idx] = result;
37 }
38 if self.max_contains.is_none() && self.min_contains.is_none() {
39 break;
40 }
41 }
42 }
43
44 if matched_count == 0 && self.min_contains != Some(0) {
45 state.errors.push(Box::new(errors::Contains {
46 path: path.to_string(),
47 }))
48 }
49
50 if self
51 .max_contains
52 .map(|max| matched_count > max)
53 .unwrap_or(false)
54 {
55 state.errors.push(Box::new(errors::ContainsMinMax {
56 path: path.to_string(),
57 }));
58 }
59
60 if self
61 .min_contains
62 .map(|min| matched_count < min)
63 .unwrap_or(false)
64 {
65 state.errors.push(Box::new(errors::ContainsMinMax {
66 path: path.to_string(),
67 }));
68 }
69 } else {
70 state.missing.push(self.url.clone());
71 }
72
73 state.set_replacement(array);
74 state
75 }
76}