1use super::*;
2use crate::element::*;
3use crate::error::{Error, Result};
4use crate::Hash;
5use serde::{Deserialize, Deserializer, Serialize};
6use std::default::Default;
7
8#[inline]
9fn is_false(v: &bool) -> bool {
10 !v
11}
12
13fn get_validator<'de, D: Deserializer<'de>>(
14 deserializer: D,
15) -> Result<Option<Box<Validator>>, D::Error> {
16 Ok(Some(Box::new(Validator::deserialize(deserializer)?)))
19}
20
21#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
68#[serde(deny_unknown_fields, default)]
69pub struct HashValidator {
70 #[serde(skip_serializing_if = "String::is_empty")]
72 pub comment: String,
73 #[serde(
76 skip_serializing_if = "Option::is_none",
77 deserialize_with = "get_validator"
78 )]
79 pub link: Option<Box<Validator>>,
80 #[serde(skip_serializing_if = "Vec::is_empty")]
84 pub schema: Vec<Option<Hash>>,
85 #[serde(rename = "in", skip_serializing_if = "Vec::is_empty")]
87 pub in_list: Vec<Hash>,
88 #[serde(rename = "nin", skip_serializing_if = "Vec::is_empty")]
90 pub nin_list: Vec<Hash>,
91 #[serde(skip_serializing_if = "is_false")]
93 pub query: bool,
94 #[serde(skip_serializing_if = "is_false")]
96 pub link_ok: bool,
97 #[serde(skip_serializing_if = "is_false")]
99 pub schema_ok: bool,
100}
101
102impl HashValidator {
103 pub fn new() -> Self {
105 Self::default()
106 }
107
108 pub fn link(mut self, link: Validator) -> Self {
110 self.link = Some(Box::new(link));
111 self
112 }
113
114 pub fn schema_add(mut self, add: impl Into<Hash>) -> Self {
116 self.schema.push(Some(add.into()));
117 self
118 }
119
120 pub fn schema_self(mut self) -> Self {
122 self.schema.push(None);
123 self
124 }
125
126 pub fn in_add(mut self, add: impl Into<Hash>) -> Self {
128 self.in_list.push(add.into());
129 self
130 }
131
132 pub fn nin_add(mut self, add: impl Into<Hash>) -> Self {
134 self.nin_list.push(add.into());
135 self
136 }
137
138 pub fn query(mut self, query: bool) -> Self {
140 self.query = query;
141 self
142 }
143
144 pub fn link_ok(mut self, link_ok: bool) -> Self {
146 self.link_ok = link_ok;
147 self
148 }
149
150 pub fn schema_ok(mut self, schema_ok: bool) -> Self {
152 self.schema_ok = schema_ok;
153 self
154 }
155
156 pub fn build(self) -> Validator {
158 Validator::Hash(Box::new(self))
159 }
160
161 pub(crate) fn validate<'c>(
162 &'c self,
163 parser: &mut Parser,
164 checklist: &mut Option<Checklist<'c>>,
165 ) -> Result<()> {
166 let elem = parser
167 .next()
168 .ok_or_else(|| Error::FailValidate("Expected a hash".to_string()))??;
169 let val = if let Element::Hash(v) = elem {
170 v
171 } else {
172 return Err(Error::FailValidate(format!(
173 "Expected Hash, got {}",
174 elem.name()
175 )));
176 };
177
178 if !self.in_list.is_empty() && !self.in_list.iter().any(|v| *v == val) {
180 return Err(Error::FailValidate(
181 "Timestamp is not on `in` list".to_string(),
182 ));
183 }
184 if self.nin_list.iter().any(|v| *v == val) {
185 return Err(Error::FailValidate(
186 "Timestamp is on `nin` list".to_string(),
187 ));
188 }
189
190 if let Some(checklist) = checklist {
191 match (self.schema.is_empty(), self.link.as_ref()) {
192 (false, Some(link)) => checklist.insert(val, Some(&self.schema), Some(link)),
193 (false, None) => checklist.insert(val, Some(&self.schema), None),
194 (true, Some(link)) => checklist.insert(val, None, Some(link)),
195 _ => (),
196 }
197 }
198
199 Ok(())
200 }
201
202 fn query_check_self(&self, types: &BTreeMap<String, Validator>, other: &HashValidator) -> bool {
203 let initial_check = (self.query || (other.in_list.is_empty() && other.nin_list.is_empty()))
204 && (self.link_ok || other.link.is_none())
205 && (self.schema_ok || other.schema.is_empty());
206 if !initial_check {
207 return false;
208 }
209 if self.link_ok {
210 match (&self.link, &other.link) {
211 (None, None) => true,
212 (Some(_), None) => true,
213 (None, Some(_)) => false,
214 (Some(s), Some(o)) => s.query_check(types, o.as_ref()),
215 }
216 } else {
217 true
218 }
219 }
220
221 pub(crate) fn query_check(
222 &self,
223 types: &BTreeMap<String, Validator>,
224 other: &Validator,
225 ) -> bool {
226 match other {
227 Validator::Hash(other) => self.query_check_self(types, other),
228 Validator::Multi(list) => list.iter().all(|other| match other {
229 Validator::Hash(other) => self.query_check_self(types, other),
230 _ => false,
231 }),
232 Validator::Any => true,
233 _ => false,
234 }
235 }
236}
237
238#[cfg(test)]
239mod test {
240 use super::*;
241 use crate::{de::FogDeserializer, ser::FogSerializer};
242
243 #[test]
244 fn ser_default() {
245 let schema = HashValidator::default();
247 let mut ser = FogSerializer::default();
248 schema.serialize(&mut ser).unwrap();
249 let expected: Vec<u8> = vec![0x80];
250 let actual = ser.finish();
251 println!("expected: {:x?}", expected);
252 println!("actual: {:x?}", actual);
253 assert_eq!(expected, actual);
254
255 let mut de = FogDeserializer::with_debug(&actual, " ");
256 let decoded = HashValidator::deserialize(&mut de).unwrap();
257 println!("{}", de.get_debug().unwrap());
258 assert_eq!(schema, decoded);
259 }
260
261 #[test]
262 fn verify_simple() {
263 let mut schema = HashValidator {
264 link: Some(Box::new(HashValidator::default().build())),
265 ..HashValidator::default()
266 };
267 schema
268 .schema
269 .push(Some(Hash::new(b"Pretend I am a real schema")));
270 schema.schema.push(None);
271 let mut ser = FogSerializer::default();
272
273 Hash::new(b"Data to make a hash")
274 .serialize(&mut ser)
275 .unwrap();
276 let encoded = ser.finish();
277 let mut parser = Parser::new(&encoded);
278 let fake_schema = Hash::new(b"Pretend I, too, am a real schema");
279 let fake_types = BTreeMap::new();
280 let mut checklist = Some(Checklist::new(&fake_schema, &fake_types));
281 schema
282 .validate(&mut parser, &mut checklist)
283 .expect("should succeed as a validator");
284 }
285}