use std::fmt::Debug;
use std::ops::RangeInclusive;
use crate::direct_match::DirectMatchResult;
use crate::number::AsInteger;
use crate::number::NumberCriterium;
use crate::DirectMatch;
macro_rules! direct_direct_match {
($e:ty) => {
impl DirectMatch<$e> for NumberCriterium<$e> {
type Output = bool;
fn criterium_match(&self, data: &$e) -> bool {
match self {
Self::Equals(my) => data == my,
Self::LessThan(my) => data < my,
Self::LessThanOrEqual(my) => data <= my,
Self::GreaterThan(my) => data > my,
Self::GreaterThanOrEqual(my) => data >= my,
Self::InList(l) => l.contains(data),
Self::IsNone => false,
}
}
}
};
}
direct_direct_match!(f32);
direct_direct_match!(f64);
direct_direct_match!(u64);
direct_direct_match!(i128);
direct_direct_match!(u128);
direct_direct_match!(isize);
direct_direct_match!(usize);
impl<V, N> DirectMatch<V> for NumberCriterium<N>
where
V: AsInteger,
N: AsInteger,
{
type Output = bool;
fn criterium_match(&self, data: &V) -> bool {
match self {
Self::Equals(my) => data.as_criterium_i64() == my.as_criterium_i64(),
Self::LessThan(my) => data.as_criterium_i64() < my.as_criterium_i64(),
Self::LessThanOrEqual(my) => data.as_criterium_i64() <= my.as_criterium_i64(),
Self::GreaterThan(my) => data.as_criterium_i64() > my.as_criterium_i64(),
Self::GreaterThanOrEqual(my) => data.as_criterium_i64() >= my.as_criterium_i64(),
Self::InList(l) => {
let d = data.as_criterium_i64();
l.iter().any(|i| i.as_criterium_i64() == d)
}
Self::IsNone => false,
}
}
}
impl<V> DirectMatch<Option<V>> for NumberCriterium<V>
where
NumberCriterium<V>: DirectMatch<V>,
{
type Output = <NumberCriterium<V> as DirectMatch<V>>::Output;
fn criterium_match(&self, data: &Option<V>) -> Self::Output {
if let Some(n) = data {
self.criterium_match(n)
} else {
Self::Output::new(matches!(self, Self::IsNone))
}
}
}
impl<V> DirectMatch<RangeInclusive<V>> for NumberCriterium<V>
where
V: PartialOrd<V> + AsInteger + TryFrom<i64, Error: Debug>,
{
type Output = Option<bool>;
fn criterium_match(&self, range: &RangeInclusive<V>) -> Option<bool> {
if range.is_empty() {
return Some(false);
}
match &self {
Self::Equals(v) => {
if range.contains(v) {
if range.start() == range.end() {
return Some(true);
} else {
return None;
}
}
return Some(false);
}
Self::LessThan(v) => {
if range.end() < v {
return Some(true);
} else if range.start() >= v {
return Some(false);
} else {
return None;
}
}
Self::LessThanOrEqual(v) => {
if range.end() < v {
return Some(true);
} else if range.start() > v {
return Some(false);
} else {
return None;
}
}
Self::GreaterThan(v) => {
if range.start() > v {
return Some(true);
} else if range.end() <= v {
return Some(false);
} else {
return None;
}
}
Self::GreaterThanOrEqual(v) => {
if range.start() > v {
return Some(true);
} else if range.end() < v {
return Some(false);
} else {
return None;
}
}
Self::InList(list) => {
let start = range.start().as_criterium_i64();
let end = range.end().as_criterium_i64();
if list.is_empty() {
return Some(false);
} else if (end - start).try_into().unwrap_or(usize::MAX) < list.len() {
let mut had_matches: bool = false;
let mut had_mismatches: bool = false;
let mut i = range.start().as_criterium_i64();
while i <= end {
if list.contains(&i.try_into().expect("convert back to original type")) {
had_matches = true
} else {
had_mismatches = true;
}
if had_mismatches && had_matches {
break;
}
i += 1;
}
if !had_matches {
return Some(false);
} else if !had_mismatches {
return Some(true);
} else {
return None;
}
} else {
for v in list {
if range.contains(v) {
return None;
}
}
return Some(false);
}
}
Self::IsNone => {
return Some(false);
}
}
}
}