use super::*;
use crate::element::*;
use crate::error::{Error, Result};
use crate::Timestamp;
use serde::{Deserialize, Serialize};
use std::default::Default;
#[inline]
fn is_false(v: &bool) -> bool {
!v
}
const MIN_TIME: Timestamp = Timestamp::min_value();
const MAX_TIME: Timestamp = Timestamp::max_value();
#[inline]
fn time_is_min(v: &Timestamp) -> bool {
*v == MIN_TIME
}
#[inline]
fn time_is_max(v: &Timestamp) -> bool {
*v == MAX_TIME
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct TimeValidator {
#[serde(skip_serializing_if = "String::is_empty")]
pub comment: String,
#[serde(skip_serializing_if = "time_is_max")]
pub max: Timestamp,
#[serde(skip_serializing_if = "time_is_min")]
pub min: Timestamp,
#[serde(skip_serializing_if = "is_false")]
pub ex_max: bool,
#[serde(skip_serializing_if = "is_false")]
pub ex_min: bool,
#[serde(rename = "in", skip_serializing_if = "Vec::is_empty")]
pub in_list: Vec<Timestamp>,
#[serde(rename = "nin", skip_serializing_if = "Vec::is_empty")]
pub nin_list: Vec<Timestamp>,
#[serde(skip_serializing_if = "is_false")]
pub query: bool,
#[serde(skip_serializing_if = "is_false")]
pub ord: bool,
}
impl Default for TimeValidator {
fn default() -> Self {
Self {
comment: String::new(),
max: MAX_TIME,
min: MIN_TIME,
ex_max: false,
ex_min: false,
in_list: Vec::new(),
nin_list: Vec::new(),
query: false,
ord: false,
}
}
}
impl TimeValidator {
pub fn new() -> Self {
Self::default()
}
pub fn comment(mut self, comment: impl Into<String>) -> Self {
self.comment = comment.into();
self
}
pub fn max(mut self, max: impl Into<Timestamp>) -> Self {
self.max = max.into();
self
}
pub fn min(mut self, min: impl Into<Timestamp>) -> Self {
self.min = min.into();
self
}
pub fn ex_max(mut self, ex_max: bool) -> Self {
self.ex_max = ex_max;
self
}
pub fn ex_min(mut self, ex_min: bool) -> Self {
self.ex_min = ex_min;
self
}
pub fn in_add(mut self, add: impl Into<Timestamp>) -> Self {
self.in_list.push(add.into());
self
}
pub fn nin_add(mut self, add: impl Into<Timestamp>) -> Self {
self.nin_list.push(add.into());
self
}
pub fn query(mut self, query: bool) -> Self {
self.query = query;
self
}
pub fn ord(mut self, ord: bool) -> Self {
self.ord = ord;
self
}
pub fn build(self) -> Validator {
Validator::Time(Box::new(self))
}
pub(crate) fn validate(&self, parser: &mut Parser) -> Result<()> {
let elem = parser
.next()
.ok_or_else(|| Error::FailValidate("Expected a timestamp".to_string()))??;
let val = if let Element::Timestamp(v) = elem {
v
} else {
return Err(Error::FailValidate(format!(
"Expected Time, got {}",
elem.name()
)));
};
let max_pass = if self.ex_max {
val < self.max
} else {
val <= self.max
};
let min_pass = if self.ex_min {
val > self.min
} else {
val >= self.min
};
if !max_pass {
return Err(Error::FailValidate(
"Timestamp greater than maximum allowed".to_string(),
));
}
if !min_pass {
return Err(Error::FailValidate(
"Timestamp less than minimum allowed".to_string(),
));
}
if !self.in_list.is_empty() && !self.in_list.iter().any(|v| *v == val) {
return Err(Error::FailValidate(
"Timestamp is not on `in` list".to_string(),
));
}
if self.nin_list.iter().any(|v| *v == val) {
return Err(Error::FailValidate(
"Timestamp is on `nin` list".to_string(),
));
}
Ok(())
}
fn query_check_self(&self, other: &Self) -> bool {
(self.query || (other.in_list.is_empty() && other.nin_list.is_empty()))
&& (self.ord
|| (!other.ex_min
&& !other.ex_max
&& time_is_min(&other.min)
&& time_is_max(&other.max)))
}
pub(crate) fn query_check(&self, other: &Validator) -> bool {
match other {
Validator::Time(other) => self.query_check_self(other),
Validator::Multi(list) => list.iter().all(|other| match other {
Validator::Time(other) => self.query_check_self(other),
_ => false,
}),
Validator::Any => true,
_ => false,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{de::FogDeserializer, ser::FogSerializer};
#[test]
fn default_ser() {
let schema = TimeValidator::default();
let mut ser = FogSerializer::default();
schema.serialize(&mut ser).unwrap();
let expected: Vec<u8> = vec![0x80];
let actual = ser.finish();
println!("expected: {:x?}", expected);
println!("actual: {:x?}", actual);
assert_eq!(expected, actual);
let mut de = FogDeserializer::new(&actual);
let decoded = TimeValidator::deserialize(&mut de).unwrap();
assert_eq!(schema, decoded);
}
#[test]
fn example_ser() {
let schema = TimeValidator {
comment: "The year 2020".to_string(),
min: Timestamp::from_utc(1577854800, 0).unwrap(),
max: Timestamp::from_utc(1609477200, 0).unwrap(),
ex_min: false,
ex_max: true,
in_list: Vec::new(),
nin_list: Vec::new(),
query: true,
ord: true,
};
let mut ser = FogSerializer::default();
schema.serialize(&mut ser).unwrap();
let mut expected: Vec<u8> = vec![0x86];
serialize_elem(&mut expected, Element::Str("comment"));
serialize_elem(&mut expected, Element::Str("The year 2020"));
serialize_elem(&mut expected, Element::Str("ex_max"));
serialize_elem(&mut expected, Element::Bool(true));
serialize_elem(&mut expected, Element::Str("max"));
serialize_elem(
&mut expected,
Element::Timestamp(Timestamp::from_utc(1609477200, 0).unwrap()),
);
serialize_elem(&mut expected, Element::Str("min"));
serialize_elem(
&mut expected,
Element::Timestamp(Timestamp::from_utc(1577854800, 0).unwrap()),
);
serialize_elem(&mut expected, Element::Str("ord"));
serialize_elem(&mut expected, Element::Bool(true));
serialize_elem(&mut expected, Element::Str("query"));
serialize_elem(&mut expected, Element::Bool(true));
let actual = ser.finish();
println!("expected: {:x?}", expected);
println!("actual: {:x?}", actual);
assert_eq!(expected, actual);
let mut de = FogDeserializer::with_debug(&actual, " ".to_string());
match TimeValidator::deserialize(&mut de) {
Ok(decoded) => assert_eq!(schema, decoded),
Err(e) => {
println!("{}", de.get_debug().unwrap());
println!("Error: {}", e);
panic!("Couldn't decode");
}
}
}
}