scalars 0.3.4

Minimal numeric traits: Zero, One, Inv, Sqrt, Exp, Logarithm, Trigonometry, Real, Integer
Documentation
use crate::{Clamp, Exp, Inv, InverseTrigonometry, Logarithm, One, Sqrt, Trigonometry, Zero};

macro_rules! impl_float {
    ($type:ty, $sqrt:path, $exp:path, $exp2:path, $ln:path, $log2:path, $pow:path, $sin:path, $cos:path, $tan:path,
     $asin:path, $acos:path, $atan:path, $atan2:path) => {
        impl Zero for $type {
            fn zero() -> Self {
                0.0
            }
            #[allow(clippy::float_cmp)]
            fn is_zero(&self) -> bool {
                *self == 0.0
            }
        }

        impl One for $type {
            fn one() -> Self {
                1.0
            }
            #[allow(clippy::float_cmp)]
            fn is_one(&self) -> bool {
                *self == 1.0
            }
        }

        impl Inv for $type {
            type Output = Self;
            fn inv(self) -> Self {
                1.0 / self
            }
        }

        impl Sqrt for $type {
            fn sqrt(self) -> Self {
                $sqrt(self)
            }
        }

        impl Exp for $type {
            type Output = Self;
            fn exp(self) -> Self {
                $exp(self)
            }
            fn exp2(self) -> Self {
                $exp2(self)
            }
        }

        impl Logarithm for $type {
            fn ln(self) -> Self {
                $ln(self)
            }
            fn log2(self) -> Self {
                $log2(self)
            }
            fn powf(self, exponent: Self) -> Self {
                $pow(self, exponent)
            }
        }

        impl Trigonometry for $type {
            fn sin_cos(self) -> [Self; 2] {
                [$sin(self), $cos(self)]
            }

            fn tan(self) -> Self {
                $tan(self)
            }
        }

        impl InverseTrigonometry for $type {
            fn asin(self) -> Self {
                $asin(self)
            }
            fn acos(self) -> Self {
                $acos(self)
            }
            fn atan(self) -> Self {
                $atan(self)
            }
            fn atan2(self, other: Self) -> Self {
                $atan2(self, other)
            }
        }

        impl Clamp for $type {
            fn min(self, other: Self) -> Self {
                if self < other { self } else { other }
            }

            fn max(self, other: Self) -> Self {
                if self > other { self } else { other }
            }
        }
    };
}

impl_float!(
    f32,
    libm::sqrtf,
    libm::expf,
    libm::exp2f,
    libm::logf,
    libm::log2f,
    libm::powf,
    libm::sinf,
    libm::cosf,
    libm::tanf,
    libm::asinf,
    libm::acosf,
    libm::atanf,
    libm::atan2f
);

impl_float!(
    f64,
    libm::sqrt,
    libm::exp,
    libm::exp2,
    libm::log,
    libm::log2,
    libm::pow,
    libm::sin,
    libm::cos,
    libm::tan,
    libm::asin,
    libm::acos,
    libm::atan,
    libm::atan2
);

#[cfg(feature = "std")]
mod from_str_radix {
    use crate::FromStrRadix;

    macro_rules! impl_from_str_radix_float {
        ($($type:ty),*) => {$(
            impl FromStrRadix for $type {
                type Error = core::num::ParseFloatError;

                #[allow(clippy::cast_possible_truncation)]
                fn from_str_radix(source: &str, radix: u32) -> Result<Self, Self::Error> {
                    if radix == 10 {
                        return source.parse();
                    }

                    let s = source.strip_prefix('-').unwrap_or(source);
                    let negative = s.len() < source.len();
                    let (int_part, frac_part) =
                        s.split_once('.').map_or((s, None), |(i, f)| (i, Some(f)));

                    // ponytail: to_digit panics for radix > 36 (like std int parsers); callers use 2..=36
                    let invalid = || "".parse::<f64>().unwrap_err();
                    let mut value = 0.0_f64;
                    for c in int_part.chars() {
                        value = value * f64::from(radix)
                            + f64::from(c.to_digit(radix).ok_or_else(invalid)?);
                    }
                    if let Some(frac) = frac_part {
                        let mut divisor = f64::from(radix);
                        for c in frac.chars() {
                            value += f64::from(c.to_digit(radix).ok_or_else(invalid)?) / divisor;
                            divisor *= f64::from(radix);
                        }
                    }

                    Ok(if negative { -value } else { value } as $type)
                }
            }
        )*};
    }

    impl_from_str_radix_float!(f32, f64);
}