1use super::*;
2use crate::error::{Error, Result};
3use crate::{de::FogDeserializer, element::*, value::Value, value_ref::ValueRef};
4use serde::{Deserialize, Deserializer, Serialize};
5use std::default::Default;
6
7#[inline]
8fn is_false(v: &bool) -> bool {
9 !v
10}
11
12#[inline]
13fn u32_is_zero(v: &u32) -> bool {
14 *v == 0
15}
16
17#[inline]
18fn u32_is_max(v: &u32) -> bool {
19 *v == u32::MAX
20}
21
22fn get_str_validator<'de, D: Deserializer<'de>>(
23 deserializer: D,
24) -> Result<Option<Box<StrValidator>>, D::Error> {
25 Ok(Some(Box::new(StrValidator::deserialize(deserializer)?)))
28}
29
30fn get_validator<'de, D: Deserializer<'de>>(
31 deserializer: D,
32) -> Result<Option<Box<Validator>>, D::Error> {
33 Ok(Some(Box::new(Validator::deserialize(deserializer)?)))
36}
37
38#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
104#[serde(deny_unknown_fields, default)]
105pub struct MapValidator {
106 #[serde(skip_serializing_if = "String::is_empty")]
108 pub comment: String,
109 #[serde(skip_serializing_if = "u32_is_max")]
111 pub max_len: u32,
112 #[serde(skip_serializing_if = "u32_is_zero")]
114 pub min_len: u32,
115 #[serde(
117 skip_serializing_if = "Option::is_none",
118 deserialize_with = "get_str_validator"
119 )]
120 pub keys: Option<Box<StrValidator>>,
121 #[serde(
124 skip_serializing_if = "Option::is_none",
125 deserialize_with = "get_validator"
126 )]
127 pub values: Option<Box<Validator>>,
128 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
131 pub req: BTreeMap<String, Validator>,
132 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
136 pub opt: BTreeMap<String, Validator>,
137 #[serde(rename = "in", skip_serializing_if = "Vec::is_empty")]
139 pub in_list: Vec<BTreeMap<String, Value>>,
140 #[serde(rename = "nin", skip_serializing_if = "Vec::is_empty")]
142 pub nin_list: Vec<BTreeMap<String, Value>>,
143 #[serde(skip_serializing_if = "Vec::is_empty")]
146 pub same_len: Vec<String>,
147 #[serde(skip_serializing_if = "is_false")]
149 pub query: bool,
150 #[serde(skip_serializing_if = "is_false")]
152 pub size: bool,
153 #[serde(skip_serializing_if = "is_false")]
155 pub map_ok: bool,
156 #[serde(skip_serializing_if = "is_false")]
158 pub same_len_ok: bool,
159}
160
161impl Default for MapValidator {
162 fn default() -> Self {
163 Self {
164 comment: String::new(),
165 max_len: u32::MAX,
166 min_len: u32::MIN,
167 keys: None,
168 values: None,
169 req: BTreeMap::new(),
170 opt: BTreeMap::new(),
171 in_list: Vec::new(),
172 nin_list: Vec::new(),
173 same_len: Vec::new(),
174 query: false,
175 size: false,
176 map_ok: false,
177 same_len_ok: false,
178 }
179 }
180}
181
182impl MapValidator {
183 pub fn new() -> Self {
185 Self::default()
186 }
187
188 pub fn comment(mut self, comment: impl Into<String>) -> Self {
190 self.comment = comment.into();
191 self
192 }
193
194 pub fn values(mut self, values: Validator) -> Self {
196 self.values = Some(Box::new(values));
197 self
198 }
199
200 pub fn req_add(mut self, key: impl Into<String>, req: Validator) -> Self {
202 self.req.insert(key.into(), req);
203 self
204 }
205
206 pub fn opt_add(mut self, key: impl Into<String>, opt: Validator) -> Self {
208 self.opt.insert(key.into(), opt);
209 self
210 }
211
212 pub fn keys(mut self, keys: StrValidator) -> Self {
214 self.keys = Some(Box::new(keys));
215 self
216 }
217
218 pub fn max_len(mut self, max_len: u32) -> Self {
220 self.max_len = max_len;
221 self
222 }
223
224 pub fn min_len(mut self, min_len: u32) -> Self {
226 self.min_len = min_len;
227 self
228 }
229
230 pub fn in_add(mut self, add: impl Into<BTreeMap<String, Value>>) -> Self {
232 self.in_list.push(add.into());
233 self
234 }
235
236 pub fn nin_add(mut self, add: impl Into<BTreeMap<String, Value>>) -> Self {
238 self.nin_list.push(add.into());
239 self
240 }
241
242 pub fn same_len_add(mut self, add: impl Into<String>) -> Self {
244 self.same_len.push(add.into());
245 self
246 }
247
248 pub fn query(mut self, query: bool) -> Self {
250 self.query = query;
251 self
252 }
253
254 pub fn size(mut self, size: bool) -> Self {
256 self.size = size;
257 self
258 }
259
260 pub fn map_ok(mut self, map_ok: bool) -> Self {
262 self.map_ok = map_ok;
263 self
264 }
265
266 pub fn same_len_ok(mut self, same_len_ok: bool) -> Self {
268 self.same_len_ok = same_len_ok;
269 self
270 }
271
272 pub fn build(self) -> Validator {
274 Validator::Map(Box::new(self))
275 }
276
277 pub(crate) fn validate<'de, 'c>(
278 &'c self,
279 types: &'c BTreeMap<String, Validator>,
280 mut parser: Parser<'de>,
281 mut checklist: Option<Checklist<'c>>,
282 ) -> Result<(Parser<'de>, Option<Checklist<'c>>)> {
283 let val_parser = parser.clone();
284 let elem = parser
285 .next()
286 .ok_or_else(|| Error::FailValidate("Expected a map".to_string()))??;
287 let len = if let Element::Map(len) = elem {
288 len
289 } else {
290 return Err(Error::FailValidate(format!(
291 "Expected Map, got {}",
292 elem.name()
293 )));
294 };
295
296 if (len as u32) > self.max_len {
297 return Err(Error::FailValidate(format!(
298 "Map is {} pairs, longer than maximum allowed of {}",
299 len, self.max_len
300 )));
301 }
302 if (len as u32) < self.min_len {
303 return Err(Error::FailValidate(format!(
304 "Map is {} pairs, shorter than minimum allowed of {}",
305 len, self.min_len
306 )));
307 }
308
309 if !self.in_list.is_empty() || !self.nin_list.is_empty() {
311 let mut de = FogDeserializer::from_parser(val_parser);
312 let map = BTreeMap::<&str, ValueRef>::deserialize(&mut de)?;
313
314 if !self.in_list.is_empty() {
315 let in_pass = self.in_list.iter().any(|v| {
316 v.len() == map.len()
317 && v.iter()
318 .zip(map.iter())
319 .all(|((ks, vs), (ko, vo))| (ks == ko) && (vs == vo))
320 });
321 if !in_pass {
322 return Err(Error::FailValidate("Map is not on `in` list".to_string()));
323 }
324 }
325
326 let nin_pass = !self.nin_list.iter().any(|v| {
327 v.len() == map.len()
328 && v.iter()
329 .zip(map.iter())
330 .all(|((ks, vs), (ko, vo))| (ks == ko) && (vs == vo))
331 });
332 if !nin_pass {
333 return Err(Error::FailValidate("Map is on `nin` list".to_string()));
334 }
335 }
336
337 let mut reqs_found = 0;
339 let mut array_len: Option<usize> = None;
340 let mut array_len_cnt = 0;
341 for _ in 0..len {
342 let elem = parser
344 .next()
345 .ok_or_else(|| Error::FailValidate("expected a key string".to_string()))??;
346 let key = if let Element::Str(v) = elem {
347 v
348 } else {
349 return Err(Error::FailValidate(format!(
350 "expected Str, got {}",
351 elem.name()
352 )));
353 };
354
355 if self.same_len.iter().any(|s| s == key) {
356 let elem = parser.peek().ok_or_else(|| {
358 Error::FailValidate("expected an array element".to_string())
359 })??;
360 let Element::Array(len) = elem else {
361 return Err(Error::FailValidate(format!(
362 "expected array for key {:?}, got {}",
363 key, elem.name()
364 )));
365 };
366 if let Some(array_len) = array_len {
367 if array_len != len {
368 return Err(Error::FailValidate(format!(
369 "expected array of length {} for key {:?}, but length was {}",
370 array_len, key, len
371 )));
372 }
373 } else {
374 array_len = Some(len);
375 }
376 array_len_cnt += 1;
377 }
378
379 let (p, c) = if let Some(validator) = self.req.get(key) {
381 reqs_found += 1;
382 validator.validate(types, parser, checklist)?
383 } else if let Some(validator) = self.opt.get(key) {
384 validator.validate(types, parser, checklist)?
385 } else if let Some(validator) = &self.values {
386 if let Some(keys) = &self.keys {
388 keys.validate_str(key)?;
389 }
390 validator.validate(types, parser, checklist)?
391 } else {
392 return Err(Error::FailValidate(format!(
393 "Map key {:?} has no corresponding validator",
394 key
395 )));
396 };
397
398 parser = p;
399 checklist = c;
400 }
401
402 if array_len.is_some() && array_len_cnt != self.same_len.len() {
403 return Err(Error::FailValidate(
404 "Map had some, but not all, of the keys listed in `same_len`".into(),
405 ));
406 }
407
408 if reqs_found != self.req.len() {
409 return Err(Error::FailValidate(format!(
410 "Map did not have all required key-value pairs (missing {})",
411 reqs_found
412 )));
413 }
414
415 Ok((parser, checklist))
416 }
417
418 fn query_check_self(&self, types: &BTreeMap<String, Validator>, other: &MapValidator) -> bool {
419 let initial_check = (self.query || (other.in_list.is_empty() && other.nin_list.is_empty()))
420 && (self.size || (u32_is_max(&other.max_len) && u32_is_zero(&other.min_len)))
421 && (self.same_len_ok || other.same_len.is_empty())
422 && (self.map_ok
423 || (other.req.is_empty()
424 && other.opt.is_empty()
425 && other.keys.is_none()
426 && other.values.is_none()));
427 if !initial_check {
428 return false;
429 }
430 if self.map_ok {
431 let values_ok = match (&self.values, &other.values) {
435 (None, None) => true,
436 (Some(_), None) => true,
437 (None, Some(_)) => false,
438 (Some(s), Some(o)) => s.query_check(types, o.as_ref()),
439 };
440 if !values_ok {
441 return false;
442 }
443
444 let keys_ok = match (&self.keys, &other.keys) {
445 (None, None) => true,
446 (Some(_), None) => true,
447 (None, Some(_)) => false,
448 (Some(s), Some(o)) => s.query_check_str(o.as_ref()),
449 };
450 if !keys_ok {
451 return false;
452 }
453
454 let req_ok = other.req.iter().all(|(ko, kv)| {
455 self.req
456 .get(ko)
457 .or_else(|| self.opt.get(ko))
458 .or(self.values.as_deref())
459 .map(|v| v.query_check(types, kv))
460 .unwrap_or(false)
461 });
462 if !req_ok {
463 return false;
464 }
465
466 let opt_ok = other.opt.iter().all(|(ko, kv)| {
467 self.req
468 .get(ko)
469 .or_else(|| self.opt.get(ko))
470 .or(self.values.as_deref())
471 .map(|v| v.query_check(types, kv))
472 .unwrap_or(false)
473 });
474 opt_ok
475 } else {
476 true
477 }
478 }
479
480 pub(crate) fn query_check(
481 &self,
482 types: &BTreeMap<String, Validator>,
483 other: &Validator,
484 ) -> bool {
485 match other {
486 Validator::Map(other) => self.query_check_self(types, other),
487 Validator::Multi(list) => list.iter().all(|other| match other {
488 Validator::Map(other) => self.query_check_self(types, other),
489 _ => false,
490 }),
491 Validator::Any => true,
492 _ => false,
493 }
494 }
495}
496
497#[cfg(test)]
498mod test {
499 use super::*;
500 use crate::{de::FogDeserializer, ser::FogSerializer};
501
502 #[test]
503 fn ser_default() {
504 let schema = MapValidator::default();
506 let mut ser = FogSerializer::default();
507 schema.serialize(&mut ser).unwrap();
508 let expected: Vec<u8> = vec![0x80];
509 let actual = ser.finish();
510 println!("expected: {:x?}", expected);
511 println!("actual: {:x?}", actual);
512 assert_eq!(expected, actual);
513
514 let mut de = FogDeserializer::with_debug(&actual, " ");
515 let decoded = MapValidator::deserialize(&mut de).unwrap();
516 println!("{}", de.get_debug().unwrap());
517 assert_eq!(schema, decoded);
518 }
519
520 #[test]
521 fn same_len() {
522 let schema = MapValidator::new()
523 .values(ArrayValidator::new().build())
524 .same_len_add("a")
525 .same_len_add("b");
526
527 #[derive(Clone, Debug, Serialize, Deserialize)]
528 struct Test {
529 #[serde(skip_serializing_if = "Vec::is_empty")]
530 a: Vec<u8>,
531 #[serde(skip_serializing_if = "Vec::is_empty")]
532 b: Vec<u8>,
533 }
534
535 let test = Test {
537 a: vec![0, 1],
538 b: vec![2, 3],
539 };
540 let mut ser = FogSerializer::default();
541 test.serialize(&mut ser).unwrap();
542 let serialized = ser.finish();
543 let parser = Parser::new(&serialized);
544 assert!(schema.validate(&BTreeMap::new(), parser, None).is_ok());
545
546 let test = Test {
548 a: vec![],
549 b: vec![],
550 };
551 let mut ser = FogSerializer::default();
552 test.serialize(&mut ser).unwrap();
553 let serialized = ser.finish();
554 let parser = Parser::new(&serialized);
555 assert!(schema.validate(&BTreeMap::new(), parser, None).is_ok());
556
557 let test = Test {
559 a: vec![2, 3],
560 b: vec![],
561 };
562 let mut ser = FogSerializer::default();
563 test.serialize(&mut ser).unwrap();
564 let serialized = ser.finish();
565 let parser = Parser::new(&serialized);
566 assert!(schema.validate(&BTreeMap::new(), parser, None).is_err());
567
568 let test = Test {
570 a: vec![2, 3],
571 b: vec![1, 2, 3],
572 };
573 let mut ser = FogSerializer::default();
574 test.serialize(&mut ser).unwrap();
575 let serialized = ser.finish();
576 let parser = Parser::new(&serialized);
577 assert!(schema.validate(&BTreeMap::new(), parser, None).is_err());
578 }
579}