use super::*;
use crate::element::*;
use crate::error::{Error, Result};
use crate::*;
use serde::{Deserialize, Serialize};
#[inline]
fn is_false(v: &bool) -> bool {
!v
}
#[inline]
fn u64_is_zero(v: &u64) -> bool {
*v == 0
}
#[inline]
fn int_is_max(v: &Integer) -> bool {
v.as_u64().map(|v| v == u64::MAX).unwrap_or(false)
}
#[inline]
fn int_is_min(v: &Integer) -> bool {
v.as_i64().map(|v| v == i64::MIN).unwrap_or(false)
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct IntValidator {
#[serde(skip_serializing_if = "String::is_empty")]
pub comment: String,
#[serde(skip_serializing_if = "u64_is_zero")]
pub bits_clr: u64,
#[serde(skip_serializing_if = "u64_is_zero")]
pub bits_set: u64,
#[serde(skip_serializing_if = "int_is_max")]
pub max: Integer,
#[serde(skip_serializing_if = "int_is_min")]
pub min: Integer,
#[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<Integer>,
#[serde(rename = "nin", skip_serializing_if = "Vec::is_empty")]
pub nin_list: Vec<Integer>,
#[serde(skip_serializing_if = "is_false")]
pub query: bool,
#[serde(skip_serializing_if = "is_false")]
pub bit: bool,
#[serde(skip_serializing_if = "is_false")]
pub ord: bool,
}
impl std::default::Default for IntValidator {
fn default() -> Self {
Self {
comment: String::new(),
bits_clr: 0,
bits_set: 0,
max: Integer::max_value(),
min: Integer::min_value(),
ex_max: false,
ex_min: false,
in_list: Vec::new(),
nin_list: Vec::new(),
query: false,
bit: false,
ord: false,
}
}
}
impl IntValidator {
pub fn new() -> Self {
Self::default()
}
pub fn comment(mut self, comment: impl Into<String>) -> Self {
self.comment = comment.into();
self
}
pub fn bits_set(mut self, bits_set: u64) -> Self {
self.bits_set = bits_set;
self
}
pub fn bits_clr(mut self, bits_clr: u64) -> Self {
self.bits_clr = bits_clr;
self
}
pub fn max(mut self, max: impl Into<Integer>) -> Self {
self.max = max.into();
self
}
pub fn min(mut self, min: impl Into<Integer>) -> 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<Integer>) -> Self {
self.in_list.push(add.into());
self
}
pub fn nin_add(mut self, add: impl Into<Integer>) -> Self {
self.nin_list.push(add.into());
self
}
pub fn query(mut self, query: bool) -> Self {
self.query = query;
self
}
pub fn bit(mut self, bit: bool) -> Self {
self.bit = bit;
self
}
pub fn ord(mut self, ord: bool) -> Self {
self.ord = ord;
self
}
pub fn build(self) -> Validator {
Validator::Int(Box::new(self))
}
pub(crate) fn validate(&self, parser: &mut Parser) -> Result<()> {
let elem = parser
.next()
.ok_or_else(|| Error::FailValidate("Expected a integer".to_string()))??;
let int = if let Element::Int(v) = elem {
v
} else {
return Err(Error::FailValidate(format!(
"Expected Int, got {}",
elem.name()
)));
};
let bits = int.as_bits();
if !self.in_list.is_empty() && !self.in_list.iter().any(|v| *v == int) {
return Err(Error::FailValidate(
"Integer is not on `in` list".to_string(),
));
}
if self.nin_list.iter().any(|v| *v == int) {
return Err(Error::FailValidate("Integer is on `nin` list".to_string()));
}
if (bits & self.bits_clr) != 0 {
return Err(Error::FailValidate(
"Integer does not have all required bits cleared".to_string(),
));
}
if (bits & self.bits_set) != self.bits_set {
return Err(Error::FailValidate(
"Integer does not have all required bits set".to_string(),
));
}
match int.cmp(&self.max) {
std::cmp::Ordering::Equal if self.ex_max => {
return Err(Error::FailValidate(
"Integer greater than maximum allowed".to_string(),
))
}
std::cmp::Ordering::Greater => {
return Err(Error::FailValidate(
"Integer greater than maximum allowed".to_string(),
))
}
_ => (),
}
match int.cmp(&self.min) {
std::cmp::Ordering::Equal if self.ex_min => {
return Err(Error::FailValidate(
"Integer less than minimum allowed".to_string(),
))
}
std::cmp::Ordering::Less => {
return Err(Error::FailValidate(
"Integer less than minimum allowed".to_string(),
))
}
_ => (),
}
Ok(())
}
fn query_check_int(&self, other: &Self) -> bool {
(self.query || (other.in_list.is_empty() && other.nin_list.is_empty()))
&& (self.bit || (other.bits_clr == 0 && other.bits_set == 0))
&& (self.ord
|| (!other.ex_min
&& !other.ex_max
&& int_is_max(&other.max)
&& int_is_min(&other.min)))
}
pub(crate) fn query_check(&self, other: &Validator) -> bool {
match other {
Validator::Int(other) => self.query_check_int(other),
Validator::Multi(list) => list.iter().all(|other| match other {
Validator::Int(other) => self.query_check_int(other),
_ => false,
}),
Validator::Any => true,
_ => false,
}
}
}