1use serde::Serialize;
2use serde_json::{to_value, Value};
3
4use super::super::json_schema;
5use super::builder;
6use super::coercers;
7use super::validators;
8
9pub struct Param {
10 pub name: String,
11 pub coercer: Option<Box<dyn coercers::Coercer + Send + Sync>>,
12 pub nest: Option<builder::Builder>,
13 pub description: Option<String>,
14 pub allow_null: bool,
15 pub validators: validators::Validators,
16 pub default: Option<Value>,
17 pub schema_builder: Option<builder::DynBuilder>,
18 pub schema_id: Option<url::Url>,
19}
20
21unsafe impl Send for Param {}
22
23impl Param {
24 pub fn new(name: &str) -> Param {
25 Param {
26 name: name.to_string(),
27 description: None,
28 coercer: None,
29 nest: None,
30 allow_null: false,
31 validators: vec![],
32 default: None,
33 schema_builder: None,
34 schema_id: None,
35 }
36 }
37
38 pub fn new_with_coercer(
39 name: &str,
40 coercer: Box<dyn coercers::Coercer + Send + Sync>,
41 ) -> Param {
42 Param {
43 name: name.to_string(),
44 description: None,
45 coercer: Some(coercer),
46 nest: None,
47 allow_null: false,
48 validators: vec![],
49 default: None,
50 schema_builder: None,
51 schema_id: None,
52 }
53 }
54
55 pub fn new_with_nest(
56 name: &str,
57 coercer: Box<dyn coercers::Coercer + Send + Sync>,
58 nest: builder::Builder,
59 ) -> Param {
60 Param {
61 name: name.to_string(),
62 description: None,
63 coercer: Some(coercer),
64 nest: Some(nest),
65 allow_null: false,
66 validators: vec![],
67 default: None,
68 schema_builder: None,
69 schema_id: None,
70 }
71 }
72
73 pub fn build<F>(name: &str, build_def: F) -> Param
74 where
75 F: FnOnce(&mut Param),
76 {
77 let mut param = Param::new(name);
78 build_def(&mut param);
79
80 param
81 }
82
83 pub fn desc(&mut self, description: &str) {
84 self.description = Some(description.to_string());
85 }
86
87 pub fn schema_id(&mut self, id: url::Url) {
88 self.schema_id = Some(id);
89 }
90
91 pub fn schema<F>(&mut self, build: F)
92 where
93 F: Fn(&mut json_schema::Builder) + 'static + Send + Sync,
94 {
95 self.schema_builder = Some(Box::new(build));
96 }
97
98 pub fn coerce(&mut self, coercer: Box<dyn coercers::Coercer + Send + Sync>) {
99 self.coercer = Some(coercer);
100 }
101
102 pub fn nest<F>(&mut self, nest_def: F)
103 where
104 F: FnOnce(&mut builder::Builder),
105 {
106 self.nest = Some(builder::Builder::build(nest_def));
107 }
108
109 pub fn allow_null(&mut self) {
110 self.allow_null = true;
111 }
112
113 pub fn regex(&mut self, regex: fancy_regex::Regex) {
114 self.validators.push(Box::new(regex));
115 }
116
117 pub fn validate(&mut self, validator: Box<dyn validators::Validator + 'static + Send + Sync>) {
118 self.validators.push(validator);
119 }
120
121 pub fn validate_with<F>(&mut self, validator: F)
122 where
123 F: Fn(&Value, &str) -> super::validators::ValidatorResult + 'static + Send + Sync,
124 {
125 self.validators.push(Box::new(validator));
126 }
127
128 fn process_validators(&self, val: &Value, path: &str) -> super::super::ValicoErrors {
129 let mut errors = vec![];
130 for validator in self.validators.iter() {
131 match validator.validate(val, path) {
132 Ok(()) => (),
133 Err(validation_errors) => errors.extend(validation_errors),
134 }
135 }
136
137 errors
138 }
139
140 pub fn process(
141 &self,
142 val: &mut Value,
143 path: &str,
144 scope: Option<&json_schema::Scope>,
145 ) -> super::ExtendedResult<Option<Value>> {
146 if val.is_null() && self.allow_null {
147 return super::ExtendedResult::new(None);
148 }
149
150 let mut result = super::ExtendedResult::new(None);
151 let mut return_value = None;
152
153 {
154 let val = if self.coercer.is_some() {
155 match self.coercer.as_ref().unwrap().coerce(val, path) {
156 Ok(None) => val,
157 Ok(Some(new_value)) => {
158 return_value = Some(new_value);
159 return_value.as_mut().unwrap()
160 }
161 Err(errors) => {
162 result.state.errors.extend(errors);
163 return result;
164 }
165 }
166 } else {
167 val
168 };
169
170 if self.nest.is_some() {
171 let process_state = self.nest.as_ref().unwrap().process_nest(val, path, scope);
172 result.append(process_state);
173 }
174
175 let validation_errors = self.process_validators(val, path);
176 result.state.errors.extend(validation_errors);
177
178 if let Some(ref id) = self.schema_id {
179 if let Some(scope) = scope {
180 let schema = scope.resolve(id);
181 match schema {
182 Some(schema) => result.append(schema.validate_in(val, path)),
183 None => result.state.missing.push(id.clone()),
184 }
185 }
186 }
187 }
188
189 if return_value.is_some() {
190 result.value = return_value;
191 }
192
193 result
194 }
195}
196
197impl Param {
198 pub fn allow_values<T: Serialize>(&mut self, values: &[T]) {
199 self.validators
200 .push(Box::new(validators::AllowedValues::new(
201 values.iter().map(|v| to_value(v).unwrap()).collect(),
202 )));
203 }
204
205 pub fn reject_values<T: Serialize>(&mut self, values: &[T]) {
206 self.validators
207 .push(Box::new(validators::RejectedValues::new(
208 values.iter().map(|v| to_value(v).unwrap()).collect(),
209 )));
210 }
211
212 pub fn default<T: Serialize>(&mut self, default: T) {
213 self.default = Some(to_value(&default).unwrap());
214 }
215}