fog_pack/validator/multi.rs
1use super::*;
2use crate::error::{Error, Result};
3use serde::{Deserialize, Serialize};
4use std::default::Default;
5
6/// "Multi" validator that checks with several validators at once.
7///
8/// This validator will accept any value that passes at least one of its contained validators. This
9/// can be used like an "any of" operator, or a logical OR of validators.
10///
11/// When this validator is used, the contained validators are checked in order, passing when the
12/// first contained validator passes. When performing [`Entry`][crate::entry::Entry] validation, this can mean that a
13/// linked document may be added to the list of documents needed for final validation, even if
14/// another contained validator (later in the list) would also pass without it.
15///
16/// When going through the contained validators, some rules are followed to avoid possible cyclic
17/// references:
18///
19/// - Contained Multi-validators are skipped
20/// - Contained Ref validators that refer to a Multi-validator are skipped.
21/// - Contained Ref validators that refer to a Ref validator are skipped.
22///
23/// More succintly, the banned sequences are: Multi->Multi, Multi->Ref->Multi, Multi->Ref->Ref.
24///
25/// # Query Checking
26///
27/// The validator for a query must be accepted by at least one of the validators in the
28/// Multi-validator. Contained validators that violate the cyclic reference rules are skipped (see
29/// above).
30///
31#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
32pub struct MultiValidator(pub Vec<Validator>);
33
34impl MultiValidator {
35 /// Make a new validator with the default configuration.
36 pub fn new() -> Self {
37 Self::default()
38 }
39
40 /// Add a new validator to the list.
41 pub fn push(mut self, validator: Validator) -> Self {
42 self.0.push(validator);
43 self
44 }
45
46 /// Build this into a [`Validator`] enum.
47 pub fn build(self) -> Validator {
48 Validator::Multi(self)
49 }
50
51 /// Iterate over all the contained validators.
52 pub fn iter(&self) -> std::slice::Iter<Validator> {
53 self.0.iter()
54 }
55
56 pub(crate) fn validate<'de, 'c>(
57 &'c self,
58 types: &'c BTreeMap<String, Validator>,
59 parser: Parser<'de>,
60 checklist: Option<Checklist<'c>>,
61 ) -> Result<(Parser<'de>, Option<Checklist<'c>>)> {
62 // Iterate through Multi list, but skip any validators that could potentially be
63 // cyclic. Banned: Multi->Multi, Multi->Ref->Multi, Multi->Ref->Ref.
64 for validator in self.0.iter() {
65 let new_parser = parser.clone();
66 let new_checklist = checklist.clone();
67 let new_result = match validator {
68 Validator::Ref(ref_name) => match types.get(ref_name) {
69 None => continue,
70 Some(validator) => match validator {
71 Validator::Ref(_) => continue,
72 Validator::Multi(_) => continue,
73 _ => validator.validate(types, new_parser, new_checklist),
74 },
75 },
76 Validator::Multi(_) => {
77 continue;
78 }
79 _ => validator.validate(types, new_parser, new_checklist),
80 };
81 // We clone the parser each time because the validator modifies its state while
82 // processing. On a pass, we return the parser state that passed
83 if new_result.is_ok() {
84 return new_result;
85 }
86 }
87 Err(Error::FailValidate(
88 "validator Multi had no passing validators".to_string(),
89 ))
90 }
91
92 pub(crate) fn query_check(
93 &self,
94 types: &BTreeMap<String, Validator>,
95 other: &Validator,
96 ) -> bool {
97 self.0.iter().any(|validator| match validator {
98 Validator::Ref(ref_name) => match types.get(ref_name) {
99 None => false,
100 Some(validator) => match validator {
101 Validator::Ref(_) => false,
102 Validator::Multi(_) => false,
103 _ => validator.query_check(types, other),
104 },
105 },
106 Validator::Multi(_) => false,
107 _ => validator.query_check(types, other),
108 })
109 }
110}