smallint 0.2.2

A library for optimized arbitrary precision integers.
Documentation
use crate::smallint::SmallUintType;
use crate::SmallUint;
use core::mem::ManuallyDrop;
use core::ops::{BitAnd, BitOr, BitXor};

macro_rules! basic_op {
    ($imp:ident, $typ:ty, $fun:ident) => {
        impl<'a, 'b> $imp<&'a $typ> for &'b $typ {
            type Output = $typ;

            fn $fun(self, rhs: &$typ) -> Self::Output {
                $fun(self, rhs)
            }
        }

        impl<'a> $imp<$typ> for &'a $typ {
            type Output = $typ;

            fn $fun(self, rhs: $typ) -> Self::Output {
                self.$fun(&rhs)
            }
        }

        impl<'a> $imp<&'a $typ> for $typ {
            type Output = $typ;

            fn $fun(self, rhs: &$typ) -> Self::Output {
                (&self).$fun(rhs)
            }
        }

        impl $imp<$typ> for $typ {
            type Output = $typ;

            fn $fun(self, rhs: $typ) -> Self::Output {
                (&self).$fun(&rhs)
            }
        }
    };
}

fn bitand(a: &SmallUint, b: &SmallUint) -> SmallUint {
    match (&a.0, &b.0) {
        (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => {
            SmallUint(SmallUintType::Inline(i & j))
        }

        (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s)))
        | (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => {
            let slice = unsafe { core::slice::from_raw_parts(r, s) };
            let mut j = 0u128;
            for i in 0..4 {
                j <<= 32;

                j |= slice[3 - i] as u128;
            }
            SmallUint(SmallUintType::Inline(i & j))
        }

        (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => {
            let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
            let slice2 = unsafe { core::slice::from_raw_parts(i, j) };

            let min = std::cmp::min(slice1.len(), slice2.len());

            let mut res = Vec::with_capacity(min);

            for l in 0..min {
                res.push(slice1[l] & slice2[l]);
            }

            while res.len() != 1 && res[res.len() - 1] == 0 {
                res.pop();
            }

            if res.len() <= 4 {
                let mut r = 0u128;
                for t in 0..res.len() {
                    r <<= 32;
                    r |= res[res.len() - 1 - t] as u128;
                }
                SmallUint(SmallUintType::Inline(r))
            } else {
                let mut slice = ManuallyDrop::new(res.into_boxed_slice());
                SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len())))
            }
        }
    }
}

basic_op!(BitAnd, SmallUint, bitand);

fn bitor(a: &SmallUint, b: &SmallUint) -> SmallUint {
    match (&a.0, &b.0) {
        (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => {
            SmallUint(SmallUintType::Inline(i | j))
        }
        (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s)))
        | (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => {
            let slice = unsafe { core::slice::from_raw_parts(r, s) };

            let mut retvec = slice.to_vec();

            let mut v = i;
            #[allow(clippy::needless_range_loop)]
            for r in 0..4 {
                retvec[r] |= v as u32;

                v >>= 32;
            }

            let mut retslice = ManuallyDrop::new(retvec.into_boxed_slice());

            SmallUint(SmallUintType::Heap((retslice.as_mut_ptr(), retslice.len())))
        }

        (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => {
            let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
            let slice2 = unsafe { core::slice::from_raw_parts(i, j) };

            let m = std::cmp::min(slice1.len(), slice2.len());

            let mut retvec;
            if slice1.len() > slice2.len() {
                retvec = slice1.to_vec();
            } else {
                retvec = slice2.to_vec();
            }

            for t in 0..m {
                retvec[t] = slice1[t] | slice2[t];
            }

            let mut slice = ManuallyDrop::new(retvec.into_boxed_slice());

            SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len())))
        }
    }
}

basic_op!(BitOr, SmallUint, bitor);

fn bitxor(a: &SmallUint, b: &SmallUint) -> SmallUint {
    match (&a.0, &b.0) {
        (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => {
            SmallUint(SmallUintType::Inline(i ^ j))
        }
        (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s)))
        | (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => {
            let slice = unsafe { core::slice::from_raw_parts(r, s) };

            let mut retvec = slice.to_vec();

            let mut v = i;
            #[allow(clippy::needless_range_loop)]
            for r in 0..4 {
                retvec[r] ^= v as u32;

                v >>= 32;
            }

            let mut retslice = ManuallyDrop::new(retvec.into_boxed_slice());

            SmallUint(SmallUintType::Heap((retslice.as_mut_ptr(), retslice.len())))
        }

        (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => {
            let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
            let slice2 = unsafe { core::slice::from_raw_parts(i, j) };

            let m = std::cmp::min(slice1.len(), slice2.len());

            let mut res;
            if slice1.len() > slice2.len() {
                res = slice1.to_vec();
            } else {
                res = slice2.to_vec();
            }

            for t in 0..m {
                res[t] = slice1[t] ^ slice2[t];
            }

            while res.len() != 1 && res[res.len() - 1] == 0 {
                res.pop();
            }

            if res.len() <= 4 {
                let mut r = 0u128;
                for t in 0..res.len() {
                    r <<= 32;
                    r |= res[res.len() - 1 - t] as u128;
                }
                SmallUint(SmallUintType::Inline(r))
            } else {
                let mut slice = ManuallyDrop::new(res.into_boxed_slice());
                SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len())))
            }
        }
    }
}

basic_op!(BitXor, SmallUint, bitxor);