smallint 0.2.2

A library for optimized arbitrary precision integers.
Documentation
use crate::smallint::{SmallIntType, SmallUintType};
use crate::SmallInt;
use crate::SmallIntError;
use crate::SmallUint;
use core::mem::ManuallyDrop;

macro_rules! int_impl {
    ($itype:ty, $rt:tt, $rtt:tt, $n:tt) => {
        impl From<$itype> for $rt {
            fn from(a: $itype) -> Self {
                Self(<$rtt>::Inline($n::from(a)))
            }
        }

        impl TryFrom<$rt> for $itype {
            type Error = SmallIntError;

            fn try_from(s: $rt) -> Result<Self, Self::Error> {
                match s.0 {
                    $rtt::Inline(i) => {
                        <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError)
                    }
                    $rtt::Heap((_, _)) => Err(SmallIntError::ConversionError),
                }
            }
        }
    };
}

int_impl!(u8, SmallInt, SmallIntType, i128);
int_impl!(u16, SmallInt, SmallIntType, i128);
int_impl!(u32, SmallInt, SmallIntType, i128);
int_impl!(u64, SmallInt, SmallIntType, i128);
int_impl!(i8, SmallInt, SmallIntType, i128);
int_impl!(i16, SmallInt, SmallIntType, i128);
int_impl!(i32, SmallInt, SmallIntType, i128);
int_impl!(i64, SmallInt, SmallIntType, i128);
int_impl!(i128, SmallInt, SmallIntType, i128);

int_impl!(u8, SmallUint, SmallUintType, u128);
int_impl!(u16, SmallUint, SmallUintType, u128);
int_impl!(u32, SmallUint, SmallUintType, u128);
int_impl!(u64, SmallUint, SmallUintType, u128);
int_impl!(u128, SmallUint, SmallUintType, u128);

macro_rules! try_from_itou {
    ($itype:ty) => {
        impl TryFrom<$itype> for SmallUint {
            type Error = SmallIntError;

            fn try_from(a: $itype) -> Result<Self, Self::Error> {
                Ok(Self(SmallUintType::Inline(
                    u128::try_from(a).map_err(|_| SmallIntError::ConversionError)?,
                )))
            }
        }

        impl TryFrom<SmallUint> for $itype {
            type Error = SmallIntError;

            fn try_from(s: SmallUint) -> Result<Self, Self::Error> {
                match s.0 {
                    SmallUintType::Inline(i) => {
                        <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError)
                    }
                    SmallUintType::Heap((_, _)) => Err(SmallIntError::ConversionError),
                }
            }
        }
    };
}

try_from_itou!(i8);
try_from_itou!(i16);
try_from_itou!(i32);
try_from_itou!(i64);
try_from_itou!(i128);

impl From<u128> for SmallInt {
    fn from(a: u128) -> Self {
        match i128::try_from(a) {
            Ok(i) => Self(SmallIntType::Inline(i)),
            Err(_) => {
                let mut v = a;
                let mut vec = Vec::with_capacity(4);
                while v != 0 {
                    vec.push(v as u32);

                    v >>= 32;
                }
                let mut slice = ManuallyDrop::new(vec.into_boxed_slice());
                Self(SmallIntType::Heap((
                    slice.as_mut_ptr(),
                    isize::try_from(slice.len()).unwrap(),
                )))
            }
        }
    }
}

impl TryFrom<SmallInt> for u128 {
    type Error = SmallIntError;

    fn try_from(s: SmallInt) -> Result<Self, Self::Error> {
        match s.0 {
            SmallIntType::Inline(i) => {
                u128::try_from(i).map_err(|_| SmallIntError::ConversionError)
            }
            SmallIntType::Heap((r, s)) => {
                let mut ret: u128 = 0;
                let mut bits = 0;
                let size = usize::try_from(s.abs()).unwrap();
                let slice = unsafe { core::slice::from_raw_parts(r, size) };
                for i in slice {
                    if bits >= 128 {
                        return Err(SmallIntError::ConversionError);
                    }
                    ret |= u128::from(*i) << bits;
                    bits += 32;
                }

                Ok(ret)
            }
        }
    }
}

impl From<SmallUint> for SmallInt {
    fn from(s: SmallUint) -> Self {
        match s.0 {
            SmallUintType::Inline(i) => SmallInt::from(i),
            SmallUintType::Heap((r, s)) => {
                let slice = unsafe { core::slice::from_raw_parts(r, s) };
                let mut ret = vec![0; s];
                ret.clone_from_slice(slice);
                let mut val = ManuallyDrop::new(ret.into_boxed_slice());
                SmallInt(SmallIntType::Heap((
                    val.as_mut_ptr(),
                    isize::try_from(s).unwrap(),
                )))
            }
        }
    }
}

impl TryFrom<SmallInt> for SmallUint {
    type Error = SmallIntError;

    fn try_from(value: SmallInt) -> Result<Self, Self::Error> {
        match value.0 {
            SmallIntType::Inline(i) => Self::try_from(i),
            SmallIntType::Heap((r, s)) => {
                let size = usize::try_from(s).map_err(|_| SmallIntError::ConversionError)?;
                if size > 4 {
                    let slice = unsafe { core::slice::from_raw_parts(r, size) };
                    let mut ret = vec![0; size];
                    ret.clone_from_slice(slice);
                    let mut val = ManuallyDrop::new(ret.into_boxed_slice());
                    Ok(Self(SmallUintType::Heap((val.as_mut_ptr(), size))))
                } else {
                    Ok(Self(SmallUintType::Inline(u128::try_from(value)?)))
                }
            }
        }
    }
}

impl SmallUint {
    /// Converts a `SmallInt` into a `SmallUint` and drops the sign instead of throwing an error.
    pub fn from_smallint_unsigned(value: SmallInt) -> Self {
        match value.0 {
            SmallIntType::Inline(i) => Self::try_from(i.abs()).unwrap(),
            SmallIntType::Heap((r, s)) => {
                let size = usize::try_from(s.abs()).unwrap();
                if size > 4 {
                    let slice = unsafe { core::slice::from_raw_parts(r, size) };
                    let mut ret = vec![0; size];
                    ret.clone_from_slice(slice);
                    let mut val = ManuallyDrop::new(ret.into_boxed_slice());
                    Self(SmallUintType::Heap((val.as_mut_ptr(), size)))
                } else if s >= 0 {
                    Self(SmallUintType::Inline(u128::try_from(value).unwrap()))
                } else {
                    Self(SmallUintType::Inline(u128::try_from(-value).unwrap()))
                }
            }
        }
    }
}