use crate::prelude::*;
#[derive(Debug,Copy,Clone,PartialEq,PartialOrd)]
pub struct Space(pub f64);
#[derive(Debug,Copy,Clone,PartialEq,PartialOrd)]
pub struct Days(pub f64);
#[derive(Debug,Copy,Clone,PartialEq,PartialOrd)]
pub struct Lambda(pub f64);
#[derive(Debug,Copy,Clone,PartialEq,PartialOrd)]
pub struct DaysOrNever(f64);
macro_rules! impl_eq_ord { { $( $ty:ident )* } => { $(
impl Eq for $ty { }
#[allow(clippy::derive_ord_xor_partial_ord)]
impl Ord for $ty {
fn cmp(&self, other: &$ty) -> Ordering {
PartialOrd::partial_cmp(self, other).expect("was NaN!")
}
}
)* } }
macro_rules! impl_fromstr { { $( $ty:ident )* } => { $(
impl FromStr for $ty {
type Err = AE;
fn from_str(s: &str) -> AR<Self> {
let v: f64 = s.parse()?;
if ! v.is_finite() { return Err(anyhow!("NaN and Inf not allowed")); }
Ok($ty(v))
}
}
)* } }
macro_rules! impl_binary { { $Name:ident, $op:tt, $( $ty:ident )* } => {
$(
paste!{
impl ops::$Name<$ty> for $ty {
type Output = $ty;
fn [< $Name:lower >](self, other: $ty) -> Self {
$ty(self.0 $op other.0)
}
}
impl ops::[< $Name Assign >]<$ty> for $ty {
fn [< $Name:lower _assign >](&mut self, other: $ty) {
self.0 = self.0 $op other.0;
}
}
}
)*
} }
macro_rules! impl_unary { { $Name:ident, $op:tt, $( $ty:ident )* } => {
$(
paste!{
impl ops::$Name for $ty {
type Output = $ty;
fn [< $Name:lower >](self) -> Self {
$ty($op self.0)
}
}
}
)*
} }
macro_rules! impl_by_scalar { { $Name:ident, $op:tt, $( $ty:ident )* } => {
$(
paste!{
impl ops::$Name<f64> for $ty {
type Output = $ty;
fn [< $Name:lower >](self, other: f64) -> Self {
$ty(self.0 $op other)
}
}
impl ops::[< $Name Assign >]<f64> for $ty {
fn [< $Name:lower _assign >](&mut self, other: f64) {
self.0 = self.0 $op other;
}
}
}
)*
} }
impl_eq_ord! ( Days Lambda Space DaysOrNever);
impl_fromstr! ( Space);
impl_binary! (Add, +, Days Lambda);
impl_binary! (Sub, -, Days Lambda);
impl_unary! (Neg, -, Days Lambda);
impl_by_scalar! (Mul, *, Days);
impl FromStr for DaysOrNever {
type Err = AE;
fn from_str(s: &str) -> AR<Self> {
let v = if s == "never" {
DaysOrNever::never()
} else {
let v: f64 = s.parse()?;
if ! v.is_finite() { return Err(anyhow!("NaN and Inf not allowed")); }
DaysOrNever(v)
};
Ok(v)
}
}
impl FromStr for Days {
type Err = AE;
fn from_str(s: &str) -> AR<Self> {
let don: DaysOrNever = s.parse()?;
don.try_into()
.map_err(|NeverError| anyhow!(r#""never" not allowed here"#))
}
}
impl Display for Days {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let v = self.0;
if let Some(width) = f.width().or(
if f.alternate() { Some(7) } else { None }
) {
write!(f, "{:width$.2}", v, width=width)
} else if v.fract() == 0.0 {
write!(f, "{}", v)
} else {
write!(f, "{:.2}", v)
}
}
}
impl Display for DaysOrNever {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match Days::try_from(*self) {
Err(NeverError) => Display::fmt("never", f),
Ok(days) => Display::fmt(&days, f),
}
}
}
impl Display for Lambda {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let v = self.0;
write!(f, "{:6.2}%", v * 100.)
}
}
impl Display for Space {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let v = self.0;
let s = format!("{:.0}", v);
let s: String =
iter::once(None).chain(
IntoIterator::into_iter([None, None, Some('_')]).cycle()
)
.zip(
s.chars().rev()
)
.flat_map(|(d, c)| d.into_iter().chain(iter::once(c)))
.collect();
let s: String = s.chars().rev().collect();
f.pad_integral(true, "", &s)
}
}
#[derive(Debug, Clone)]
pub struct NeverError;
impl TryFrom<DaysOrNever> for Days {
type Error = NeverError;
fn try_from(don: DaysOrNever) -> Result<Days, NeverError> {
let v = don.0;
if v.is_finite() {
Ok(Days(v))
} else {
Err(NeverError)
}
}
}
impl From<Days> for DaysOrNever {
fn from(days: Days) -> DaysOrNever {
DaysOrNever(days.0)
}
}
impl DaysOrNever {
pub fn never() -> Self { DaysOrNever(f64::INFINITY) }
}
pub struct DaysRange(pub [Days; 2]);
impl DaysRange {
pub fn clamp(&self, days: Days) -> Days {
let [min, max] = self.0;
days.clamp(min, max)
}
pub fn mk_lambda(self, val: Days) -> Lambda {
let [min, max] = self.0;
let lambda = (val - min).0 / (max - min).0;
Lambda(lambda)
}
pub fn mk_days(self, lambda: Lambda) -> Days {
let [Days(min), Days(max)] = self.0;
let val = min + (max - min) * lambda.0;
Days(val)
}
}
impl From<[Days; 3]> for Lambda {
fn from([min, val, max]: [Days; 3]) -> Lambda {
Lambda(
(val - min).0 / (max - min).0
)
}
}