var_num 0.4.2

Variable length number implementation that can be used as a drop in replacement for any number primitive.
Documentation
use crate::var_num::ParseError;
use crate::{VarInt, VarUInt};
use derive_more::{Display, Neg};
use std::fmt;
use std::fmt::Binary;
use std::hash::{Hash, Hasher};
use std::ops::{BitAnd, BitOr, BitXor, Not, Rem, Shl, Shr};
use std::str::FromStr;

#[derive(Copy, Clone, Debug, Display, PartialEq, Neg, PartialOrd)]
pub enum VarFloat {
    F32(f32),
    F64(f64),
}

impl Hash for VarFloat {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            VarFloat::F32(f) => state.write_u32(f.to_bits()),
            VarFloat::F64(f) => state.write_u64(f.to_bits())
        }
    }
}

impl Eq for VarFloat {

}

impl FromStr for VarFloat {
    type Err = ParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let f: f64 = match s.parse() {
            Ok(f) => f,
            Err(e) => return Err(ParseError::InvalidNumber(format!("Invalid Float: {}", e))),
        };
        Ok(f.into())
    }
}

#[cfg(feature = "serde")]
impl serde::Serialize for VarFloat {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        match self {
            VarFloat::F32(v) => serializer.serialize_f32(*v),
            VarFloat::F64(v) => serializer.serialize_f64(*v),
        }
    }
}

#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for VarFloat {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        Ok(f64::deserialize(deserializer)?.into())
    }
}

impl VarFloat {
    #[inline]
    pub fn reverse(&self) -> Self {
        match self {
            VarFloat::F32(f) => {
                VarFloat::F32(f32::from_bits(f.to_bits().reverse_bits()))
            }
            VarFloat::F64(f) => {
                VarFloat::F64(f64::from_bits(f.to_bits().reverse_bits()))
            }
        }
    }

    #[inline]
    pub fn zero() -> Self {
        VarFloat::F32(0.0)
    }

    #[inline]
    pub fn one() -> Self {
        VarFloat::F32(1.0)
    }

    #[inline]
    pub fn is_non_zero(&self) -> bool {
        match self {
            VarFloat::F32(f) => *f != 0.0,
            VarFloat::F64(f) => *f != 0.0
        }
    }

    #[inline]
    pub fn is_zero(&self) -> bool {
        match self {
            VarFloat::F32(f) => *f == 0.0,
            VarFloat::F64(f) => *f == 0.0
        }
    }

    #[inline]
    pub fn is_one(&self) -> bool {
        match self {
            VarFloat::F32(f) => *f == 1.0,
            VarFloat::F64(f) => *f == 1.0
        }
    }

    #[inline]
    pub fn to_int(&self) -> VarInt {
        match self {
            VarFloat::F32(v) => (*v as i32).into(),
            VarFloat::F64(v) => (*v as i64).into(),
        }
    }

    #[inline]
    pub fn to_uint(&self) -> VarUInt {
        match self {
            VarFloat::F32(v) => (*v as u32).into(),
            VarFloat::F64(v) => (*v as u64).into(),
        }
    }

    #[inline]
    pub fn upgrade(&self) -> Self {
        match self {
            Self::F32(v) => Self::F64(*v as f64),
            Self::F64(v) => panic!("cannot upgrade f64 value: {}", v),
        }
    }

    #[inline]
    pub fn downgrade(&self) -> Self {
        match self {
            Self::F32(v) => panic!("cannot downgrade f32 value: {}", v),
            Self::F64(v) => Self::F32(*v as f32),
        }
    }

    #[inline]
    pub fn to_bytes(&self) -> Vec<u8> {
        match self {
            Self::F32(v) => v.to_be_bytes().to_vec(),
            Self::F64(v) => v.to_be_bytes().to_vec(),
        }
    }

    #[inline]
    pub fn from_bytes(raw: Vec<u8>) -> Self {
        match raw.len() {
            4 => {
                let mut bytes = [0; 4];
                bytes.copy_from_slice(&raw);
                Self::F32(f32::from_be_bytes(bytes))
            }
            8 => {
                let mut bytes = [0; 8];
                bytes.copy_from_slice(&raw);
                Self::F64(f64::from_be_bytes(bytes))
            }
            _ => panic!("invalid byte length: {}", raw.len()),
        }
    }

    pub fn normalize(lhs: Self, rhs: Self) -> (Self, Self) {
        match (lhs, rhs) {
            (Self::F32(lhs), Self::F32(rhs)) => (Self::F32(lhs), Self::F32(rhs)),
            (Self::F32(lhs), rhs) => Self::normalize(Self::F32(lhs).upgrade(), rhs),
            (lhs, Self::F32(rhs)) => Self::normalize(lhs, Self::F32(rhs).upgrade()),
            (Self::F64(lhs), Self::F64(rhs)) => (Self::F64(lhs), Self::F64(rhs)),
        }
    }
}

impl Binary for VarFloat {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            VarFloat::F32(v) => fmt::Binary::fmt(&(v.to_bits()), f),
            VarFloat::F64(v) => fmt::Binary::fmt(&(v.to_bits()), f),
        }
    }
}

impl Rem for VarFloat {
    type Output = VarFloat;

    fn rem(self, rhs: Self) -> Self::Output {
        let (lhs, rhs) = VarFloat::normalize(self, rhs);
        match (lhs, rhs) {
            (VarFloat::F32(lhs), VarFloat::F32(rhs)) => ((lhs as u32) % (rhs as u32)).into(),
            (VarFloat::F64(lhs), VarFloat::F64(rhs)) => ((lhs as u64) % (rhs as u64)).into(),
            (lhs, rhs) => panic!("normalization failed: {} % {}", lhs, rhs),
        }
    }
}

macro_rules! impl_bin_var_float_to_bits {
    ($($trait:ident: $method:ident($op:tt),)*) => {
        $(
            impl $trait for VarFloat {
                type Output = VarFloat;

                fn $method(self, rhs: Self) -> Self::Output {
                    match VarFloat::normalize(self, rhs) {
                        (VarFloat::F32(lhs), VarFloat::F32(rhs)) => VarFloat::F32(f32::from_bits(lhs.to_bits() $op rhs.to_bits())),
                        (VarFloat::F64(lhs), VarFloat::F64(rhs)) => VarFloat::F64(f64::from_bits(lhs.to_bits() $op rhs.to_bits())),
                        (lhs, rhs) => panic!("normalization failed: {} {} {}", lhs, stringify!($op), rhs),
                    }
                }
            }
        )*
    };
}

impl_bin_var_float_to_bits! {
    BitAnd: bitand(&),
    BitOr: bitor(|),
    BitXor: bitxor(^),
    Shl: shl(<<),
    Shr: shr(>>),
}

impl Not for VarFloat {
    type Output = VarFloat;

    fn not(self) -> Self::Output {
        match self {
            VarFloat::F32(v) => (!(v as u32)).into(),
            VarFloat::F64(v) => (!(v as u64)).into(),
        }
    }
}

macro_rules! from_primitive_var_float {
    ($($type:ty)*) => {
        $(
            impl From<$type> for VarFloat {
                fn from(value: $type) -> Self {
                    VarFloat::F32(value as f32)
                }
            }
        )*
    };
}

macro_rules! from_primitive_var_float64 {
    ($($type:ty)*) => {
        $(
            impl From<$type> for VarFloat {
                fn from(value: $type) -> Self {
                    if value <= f32::MAX as $type {
                        VarFloat::F32(value as f32)
                    } else {
                        VarFloat::F64(value as f64)
                    }
                }
            }
        )*
    };
}

from_primitive_var_float! { f32 u8 u16 u32 i8 i16 i32 }
from_primitive_var_float64! { f64 u64 i64 usize isize }