json_model/attribute/
array_items.rs1use super::{AllowedType, Attribute};
2use crate::definition::{Definition, Type};
3use crate::error::{Error, ValidationError};
4use crate::validator::{Context, DocumentPath, State};
5
6use std::collections::HashSet;
7
8use serde_json;
9
10#[derive(Debug)]
11pub struct ArrayItems {
12 name: String,
13 ptrs: HashSet<String>,
14}
15
16impl ArrayItems {
17 pub fn new(state: &mut State, mut path: DocumentPath, ctx: &Context) -> Result<Self, Error> {
18 let obj = ctx.raw_definition();
19
20 match Type::new(obj, path.clone())? {
21 Type::Array => (),
22 typ => return Err(Error::ForbiddenType { path, typ }),
23 };
24
25 let defs = match obj.get(ctx.name().as_str()) {
26 Some(items) => match items.as_array() {
27 Some(items_arr) => items_arr,
28 None => {
29 path.add(ctx.name().as_str());
30 return Err(Error::InvalidValue {
31 path,
32 value: items.clone(),
33 });
34 }
35 },
36 None => {
37 return Err(Error::MissingAttribute {
38 path,
39 attr: ctx.name(),
40 })
41 }
42 };
43
44 path.add(ctx.name().as_str());
45
46 let mut ptrs = HashSet::<String>::new();
47 for (i, d) in defs.iter().enumerate() {
48 let mut path = path.clone();
49 path.add(i.to_string().as_str());
50 let def = Definition::new(state, d, ctx.ptr(), path.clone(), ctx.path())?;
51 ptrs.insert(def.ptr());
52 state.add_definition(def, path)?;
53 }
54
55 Ok(ArrayItems {
56 name: ctx.name(),
57 ptrs,
58 })
59 }
60
61 pub fn allowed_types() -> HashSet<AllowedType> {
62 let mut set = HashSet::<AllowedType>::new();
63 set.insert(AllowedType::new(Type::Array, true));
64 set
65 }
66
67 pub fn build(
68 state: &mut State,
69 path: DocumentPath,
70 ctx: &Context,
71 ) -> Result<Box<Attribute>, Error> {
72 Ok(Box::new(ArrayItems::new(state, path, ctx)?))
73 }
74}
75
76impl Attribute for ArrayItems {
77 fn validate(
78 &self,
79 state: &State,
80 path: Vec<String>,
81 input: &serde_json::Value,
82 ) -> Result<(), ValidationError> {
83 let arr = match input.as_array() {
84 Some(arr) => arr,
85 None => {
86 return Err(ValidationError::Failure {
87 rule: "type".to_string(),
88 path: path,
89 message: "Value must be an array.".to_string(),
90 })
91 }
92 };
93
94 for (i, value) in arr.iter().enumerate() {
95 let mut found = false;
96 let mut path = path.clone();
97 path.push(i.to_string());
98 for ptr in &self.ptrs {
99 let def = match state.get_definition(ptr.as_str()) {
100 Some(def) => def,
101 None => return Err(ValidationError::UndefinedDefinition),
102 };
103 if let Ok(_) = def.validate(state, value, path.clone()) {
104 found = true;
105 break;
106 }
107 }
108 if !found {
109 return Err(ValidationError::Failure {
110 rule: "items".to_string(),
111 path: path,
112 message: "Value must be a valid array item.".to_string(),
113 });
114 }
115 }
116
117 Ok(())
118 }
119}