var_num 0.4.2

Variable length number implementation that can be used as a drop in replacement for any number primitive.
Documentation
pub mod inner;
pub mod var_num;

pub use crate::inner::{VarFloat, VarInt, VarUInt};
pub use crate::var_num::VarNum;
use std::ops::{
    AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, MulAssign, RemAssign, ShlAssign,
    ShrAssign, SubAssign,
};
macro_rules! impl_assign {
    ($($ty:ty => [$($trait:ident($fn:ident $op:tt)),*]),*) => {
        $(
            $(
                impl $trait for $ty {
                    fn $fn(&mut self, other: Self) {
                        *self = *self $op other;
                    }
                }
            )*
        )*
    }
}

macro_rules! impl_assignments {
    ($($ty:ty),*) => {
        $(
            impl_assign! {
                $ty => [
                    AddAssign(add_assign +),
                    SubAssign(sub_assign -),
                    MulAssign(mul_assign *),
                    DivAssign(div_assign /),
                    RemAssign(rem_assign %),
                    BitAndAssign(bitand_assign &),
                    BitOrAssign(bitor_assign |),
                    BitXorAssign(bitxor_assign ^),
                    ShlAssign(shl_assign <<),
                    ShrAssign(shr_assign >>)
                ]
            }
        )*
    }
}

impl_assignments! { VarInt, VarUInt, VarFloat, VarNum }

#[cfg(test)]
mod var_num_tests {
    use super::*;

    #[test]
    fn it_works() {
        let a: VarNum = 2.into();
        let b: VarNum = 2.0.into();
        let c: VarNum = a + b;
        assert_eq!(c, VarNum::Int(VarInt::I8(4)));
    }

    macro_rules! generate_tests_unary {
        ($($group_name:ident > $ty:ty: $op:tt),*) => {
            $(
                #[test]
                fn $group_name() {
                    let a: $ty = <$ty>::MAX / (2 as $ty);
                    let a_n: VarNum = a.into();
                    assert_eq!($op a, ($op a_n).into());
                }
            )*
        }
    }

    generate_tests_unary! {
        u8_not > u8: !,
        u16_not > u16: !,
        u32_not > u32: !,
        u64_not > u64: !,
        u128_not > u128: !,
        i8_not > i8: !,
        i16_not > i16: !,
        i32_not > i32: !,
        i64_not > i64: !,
        i128_not > i128: !,
        i8_neg > i8: -,
        i16_neg > i16: -,
        i32_neg > i32: -,
        i64_neg > i64: -,
        i128_neg > i128: -,
        f32_neg > f32: -,
        f64_neg > f64: -
    }

    macro_rules! generate_tests_binary {
        ($($group_name:ident > $ty:ty: $op:tt),*) => {
            $(
                #[test]
                fn $group_name() {
                    let a: $ty = 6 as $ty;
                    let b: $ty = 2 as $ty;
                    let a_n: VarNum = a.into();
                    let b_n: VarNum = b.into();
                    assert_eq!(a $op b, (a_n $op b_n).into());
                }
            )*
        }
    }

    generate_tests_binary! {
        u8_add > u8: +,
        f32_add > f32: +,
        f64_add > f64: +,
        u64_sub > u64: -,
        u128_sub > u128: -,
        i8_sub > i8: -,
        i16_sub > i16: -,
        u16_mul > u16: *,
        u32_mul > u32: *,
        u64_mul > u64: *,
        u128_mul > u128: *,
        i8_mul > i8: *,
        i16_mul > i16: *,
        f64_mul > f64: *,
        u128_div > u128: /,
        i8_div > i8: /,
        i32_div > i32: /,
        f64_div > f64: /,
        u64_rem > u64: %,
        i16_rem > i16: %,
        i32_rem > i32: %
    }
}