use core::fmt; use std::ops::{Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive}; use crate::formula::Formula; //MARK: Ranges pub enum Ranges { Exlusive(Range), Inclusive(RangeInclusive), From(RangeFrom), To(RangeTo), ToInclusive(RangeToInclusive), } impl From> for Ranges { fn from(value: Range) -> Self { Ranges::Exlusive(value) } } impl From> for Ranges { fn from(value: RangeFrom) -> Self { Ranges::From(value) } } impl From> for Ranges { fn from(value: RangeTo) -> Self { Ranges::To(value) } } impl From> for Ranges { fn from(value: RangeInclusive) -> Self { Ranges::Inclusive(value) } } impl From> for Ranges { fn from(value: RangeToInclusive) -> Self { Ranges::ToInclusive(value) } } impl fmt::Display for Ranges { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Ranges::Exlusive(range) => { write!(f, "from {} and less than {}", range.start, range.end) } Ranges::Inclusive(range) => write!(f, "from {} to {}", range.start(), range.end()), Ranges::From(range) => write!(f, "greater than {}", range.start), Ranges::To(range) => write!(f, "less than {}", range.end), Ranges::ToInclusive(range) => write!(f, "from 0 to {}", range.end), } } } impl Ranges { pub fn contains(&self, item: &U) -> bool where T: PartialOrd, U: PartialOrd + ?Sized, { match self { Ranges::Exlusive(range) => range.contains(item), Ranges::Inclusive(range) => range.contains(item), Ranges::From(range) => range.contains(item), Ranges::To(range) => range.contains(item), Ranges::ToInclusive(range) => range.contains(item), } } } impl From for Formula { fn from(value: F32Formula) -> Self { let F32Formula { bounds } = value; let form = Formula::new("Failed to parse [opt] as a number"); if let Some(bounds) = bounds { let fail = format!("[opt] must be {bounds}"); form.check(fail, move |u| bounds.contains(&u)) } else { form } } } pub struct F32Formula { bounds: Option>, } impl F32Formula { pub fn new() -> Self { Self { bounds: None } } pub fn bounds>>(mut self, bounds: R) -> Self { self.bounds = Some(bounds.into()); self } } //MARK: Signed/Unsigned Formula impl macro_rules! int_formula_impl { ($meow:ident $woof:ty) => { pub struct $meow { bounds: Option>, } impl $meow { pub fn new() -> Self { Self { bounds: None } } pub fn bounds>>(mut self, bounds: R) -> Self { self.bounds = Some(bounds.into()); self } } impl From<$meow> for Formula<$woof> { fn from(value: $meow) -> Self { let $meow { bounds } = value; let form = Formula::new("Failed to parse [opt] as an integer"); if let Some(bounds) = bounds { let fail = format!("[opt] must be {bounds}"); form.check(fail, move |u| bounds.contains(&u)) } else { form } } } }; } int_formula_impl!(U8Formula u8); int_formula_impl!(U16Formula u16); int_formula_impl!(U32Formula u32); int_formula_impl!(U64Formula u64); int_formula_impl!(UsizeFormula usize); int_formula_impl!(I8Formula i8); int_formula_impl!(I16Formula i16); int_formula_impl!(I32Formula i32); int_formula_impl!(I64Formula i64); int_formula_impl!(IsizeFormula isize);