microfloat 0.1.1

8-bit and sub-byte floating point types
Documentation
use core::num::FpCategory;

use crate::{
    f4e2m1fn, f6e2m3fn, f6e3m2fn, f8e3m4, f8e4m3, f8e4m3b11fnuz, f8e4m3fn, f8e4m3fnuz, f8e5m2,
    f8e5m2fnuz, f8e8m0fnu,
};
use num_traits::{
    Bounded, FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Zero, float::FloatCore,
};

macro_rules! impl_common_num_traits {
    ($($type:ty),* $(,)?) => {
        $(
            impl ToPrimitive for $type {
                fn to_i64(&self) -> Option<i64> {
                    <$type>::to_f32(*self).to_i64()
                }

                fn to_u64(&self) -> Option<u64> {
                    <$type>::to_f32(*self).to_u64()
                }

                fn to_f32(&self) -> Option<f32> {
                    Some(<$type>::to_f32(*self))
                }

                fn to_f64(&self) -> Option<f64> {
                    Some(<$type>::to_f64(*self))
                }
            }

            impl FromPrimitive for $type {
                fn from_i64(n: i64) -> Option<Self> {
                    n.to_f32().map(Self::from_f32)
                }

                fn from_u64(n: u64) -> Option<Self> {
                    n.to_f32().map(Self::from_f32)
                }

                fn from_f32(n: f32) -> Option<Self> {
                    Some(Self::from_f32(n))
                }

                fn from_f64(n: f64) -> Option<Self> {
                    Some(Self::from_f64(n))
                }
            }

            impl NumCast for $type {
                fn from<T: ToPrimitive>(n: T) -> Option<Self> {
                    n.to_f32().map(Self::from_f32)
                }
            }

            impl Bounded for $type {
                fn min_value() -> Self {
                    Self::MIN
                }

                fn max_value() -> Self {
                    Self::MAX
                }
            }
        )*
    };
}

macro_rules! impl_zero_one_num_signed {
    ($($type:ty),* $(,)?) => {
        $(
            impl Zero for $type {
                fn zero() -> Self {
                    Self::ZERO
                }

                fn is_zero(&self) -> bool {
                    self.classify() == FpCategory::Zero
                }
            }

            impl One for $type {
                fn one() -> Self {
                    Self::ONE
                }
            }

            impl Num for $type {
                type FromStrRadixErr = <f32 as Num>::FromStrRadixErr;

                fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
                    f32::from_str_radix(str, radix).map(Self::from_f32)
                }
            }

            impl Signed for $type {
                fn abs(&self) -> Self {
                    <$type>::abs(*self)
                }

                fn abs_sub(&self, other: &Self) -> Self {
                    if *self <= *other {
                        Self::ZERO
                    } else {
                        *self - *other
                    }
                }

                fn signum(&self) -> Self {
                    <$type>::signum(*self)
                }

                fn is_positive(&self) -> bool {
                    self.is_sign_positive() && !self.is_zero()
                }

                fn is_negative(&self) -> bool {
                    self.is_sign_negative() && !self.is_zero()
                }
            }

            impl FloatCore for $type {
                fn infinity() -> Self {
                    Self::INFINITY
                }

                fn neg_infinity() -> Self {
                    Self::NEG_INFINITY
                }

                fn nan() -> Self {
                    Self::NAN
                }

                fn neg_zero() -> Self {
                    Self::NEG_ZERO
                }

                fn min_value() -> Self {
                    Self::MIN
                }

                fn min_positive_value() -> Self {
                    Self::MIN_POSITIVE
                }

                fn epsilon() -> Self {
                    Self::EPSILON
                }

                fn max_value() -> Self {
                    Self::MAX
                }

                fn is_nan(self) -> bool {
                    <$type>::is_nan(self)
                }

                fn is_infinite(self) -> bool {
                    <$type>::is_infinite(self)
                }

                fn is_finite(self) -> bool {
                    <$type>::is_finite(self)
                }

                fn is_normal(self) -> bool {
                    <$type>::is_normal(self)
                }

                fn classify(self) -> FpCategory {
                    <$type>::classify(self)
                }

                fn to_degrees(self) -> Self {
                    Self::from_f32(<$type>::to_f32(self).to_degrees())
                }

                fn to_radians(self) -> Self {
                    Self::from_f32(<$type>::to_f32(self).to_radians())
                }

                fn integer_decode(self) -> (u64, i16, i8) {
                    <f32 as FloatCore>::integer_decode(<$type>::to_f32(self))
                }
            }
        )*
    };
}

impl_common_num_traits!(
    f8e3m4,
    f8e4m3,
    f8e4m3b11fnuz,
    f8e4m3fn,
    f8e4m3fnuz,
    f8e5m2,
    f8e5m2fnuz,
    f8e8m0fnu,
    f4e2m1fn,
    f6e2m3fn,
    f6e3m2fn,
);

impl_zero_one_num_signed!(
    f8e3m4,
    f8e4m3,
    f8e4m3b11fnuz,
    f8e4m3fn,
    f8e4m3fnuz,
    f8e5m2,
    f8e5m2fnuz,
    f4e2m1fn,
    f6e2m3fn,
    f6e3m2fn,
);