use core::fmt; use std::{ marker::PhantomData, ops::{Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive}, path::PathBuf, str::FromStr, }; pub struct Formula { pub(crate) check_fn: Option<(String, Box bool>)>, pub(crate) failure: String, pub(crate) missing: Option, phantom: PhantomData, } impl Formula { pub fn new>(failure: S) -> Self { Self { check_fn: None, failure: failure.into(), missing: None, phantom: PhantomData::default(), } } pub fn check, F>(mut self, fail: S, check: F) -> Self where F: FnMut(&T) -> bool + 'static, { self.check_fn = Some((fail.into(), Box::new(check))); self } pub fn required>(mut self, missing: S) -> Self { self.missing = Some(missing.into()); self } } impl From for Formula { fn from(value: String) -> Self { Formula::new(value) } } impl From<&str> for Formula { fn from(value: &str) -> Self { Formula::new(value) } } impl From for Formula { fn from(value: UsizeFormula) -> Self { let UsizeFormula { 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 } } } 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 } } } impl From for Formula { fn from(_value: PathFormula) -> Self { Formula::new("Failed to parse [opt] as a path") } } 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 } } pub struct UsizeFormula { bounds: Option>, } impl UsizeFormula { pub fn new() -> Self { Self { bounds: None } } pub fn bounds>>(mut self, bounds: R) -> Self { self.bounds = Some(bounds.into()); self } } 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), } } } pub struct PathFormula; impl PathFormula { pub fn new() -> Self { Self {} } }