diff --git a/Cargo.toml b/Cargo.toml index 1a8c81e..dcbc052 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" authors = ["artofrev"] description = "A library for optimized arbitrary precision integers." license = "MIT" +repository = "https://github.com/artofrev/smallint" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/lib.rs b/src/lib.rs index 1e20fa6..2d3f54f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,26 +2,25 @@ #![warn(clippy::all)] //! A crate for small integer optimization. Provides the [`SmallInt`] type. When possible this will -//! inline an integer and store it on the stack if that integer is small. However, for larger values, +//! inline an integer and store it on the stack if that integer is small. However, for larger values, //! this will be instead stored on the heap as a pointer to a `u32` slice, a length, and a sign. - // Invariant: If a small integer is within the bounds of an inline value, it must be inline. // Invariant: If a small integer is on the heap, the size is the minimum digits required to // represent it. -#[cfg(feature="num-bigint")] +#[cfg(feature = "num-bigint")] use num_bigint::BigInt; -#[cfg(feature="num-bigint")] +#[cfg(feature = "num-bigint")] use num_bigint::BigUint; -#[cfg(feature="num-bigint")] +#[cfg(feature = "num-bigint")] use num_bigint::Sign; use core::mem::ManuallyDrop; -/// An error that occurred when processing a SmallInt. +/// An error that occurred when processing a `SmallInt`. #[derive(Debug, Clone, PartialEq, Eq)] pub enum SmallIntError { /// Conversion error when converting from SmallInt to other integer types. @@ -37,32 +36,28 @@ impl core::fmt::Display for SmallIntError { } } - /// An integer-like type that will store small integers up to `i128` inline. Larger integers are /// represented as a slice to a sequence of base 232 digits represented as a `*mut u32`. #[derive(Clone, PartialEq, Eq)] pub struct SmallInt(SmallIntType); - /// An integer-like type that will store small integers up to `u128` inline. Larger integers are /// represented as a slice to a sequence of base 232 digits represented as a `*mut u32`. #[derive(Clone, PartialEq, Eq)] pub struct SmallUint(SmallUintType); - #[derive(Clone, PartialEq, Eq)] enum SmallIntType { Inline(i128), - Heap((*mut u32, isize)) + Heap((*mut u32, isize)), } #[derive(Clone, PartialEq, Eq)] enum SmallUintType { Inline(u128), - Heap((*mut u32, usize)) + Heap((*mut u32, usize)), } - impl Drop for SmallInt { fn drop(&mut self) { if let Self(SmallIntType::Heap((r, s))) = self { @@ -71,7 +66,6 @@ impl Drop for SmallInt { unsafe { std::mem::drop(Box::from_raw(slice)) } } } - } impl Drop for SmallUint { @@ -81,7 +75,6 @@ impl Drop for SmallUint { unsafe { std::mem::drop(Box::from_raw(slice)) } } } - } macro_rules! int_impl { @@ -93,58 +86,61 @@ macro_rules! int_impl { } impl TryFrom<$rt> for $itype { - type Error = SmallIntError; fn try_from(s: $rt) -> Result { match s.0 { - $rtt::Inline(i) => <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError), + $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!(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!(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 { - Ok(Self(SmallUintType::Inline(u128::try_from(a).map_err(|_| SmallIntError::ConversionError)?))) + Ok(Self(SmallUintType::Inline( + u128::try_from(a).map_err(|_| SmallIntError::ConversionError)?, + ))) } } impl TryFrom for $itype { - type Error = SmallIntError; fn try_from(s: SmallUint) -> Result { match s.0 { - SmallUintType::Inline(i) => <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError), + SmallUintType::Inline(i) => { + <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError) + } SmallUintType::Heap((_, _)) => Err(SmallIntError::ConversionError), } } } - } + }; } try_from_itou!(i8); @@ -153,7 +149,6 @@ try_from_itou!(i32); try_from_itou!(i64); try_from_itou!(i128); - impl From for SmallInt { fn from(a: u128) -> Self { match i128::try_from(a) { @@ -167,19 +162,23 @@ impl From for SmallInt { v >>= 32; } let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); - Self(SmallIntType::Heap((slice.as_mut_ptr(), isize::try_from(slice.len()).unwrap()))) + Self(SmallIntType::Heap(( + slice.as_mut_ptr(), + isize::try_from(slice.len()).unwrap(), + ))) } } } } impl TryFrom for u128 { - type Error = SmallIntError; fn try_from(s: SmallInt) -> Result { match s.0 { - SmallIntType::Inline(i) => u128::try_from(i).map_err(|_| SmallIntError::ConversionError), + SmallIntType::Inline(i) => { + u128::try_from(i).map_err(|_| SmallIntError::ConversionError) + } SmallIntType::Heap((r, s)) => { let mut ret: u128 = 0; let mut bits = 0; @@ -203,14 +202,14 @@ impl From for SmallInt { fn from(s: SmallUint) -> Self { match s.0 { SmallUintType::Inline(i) => SmallInt::from(i), - SmallUintType::Heap((r, s)) => SmallInt(SmallIntType::Heap((r, isize::try_from(s).unwrap()))) + SmallUintType::Heap((r, s)) => { + SmallInt(SmallIntType::Heap((r, isize::try_from(s).unwrap()))) + } } - } } impl TryFrom for SmallUint { - type Error = SmallIntError; fn try_from(value: SmallInt) -> Result { @@ -226,11 +225,9 @@ impl TryFrom for SmallUint { } } } - } - -#[cfg(feature="num-bigint")] +#[cfg(feature = "num-bigint")] impl From for SmallInt { fn from(b: BigInt) -> Self { match (&b).try_into() { @@ -240,15 +237,18 @@ impl From for SmallInt { let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); let size = match sign { Sign::Minus => -isize::try_from(slice.len()).unwrap(), - Sign::NoSign => panic!("Shouldn't happen; BigInts which store zero should convert to inline."), - Sign::Plus => isize::try_from(slice.len()).unwrap() + Sign::NoSign => panic!( + "Shouldn't happen; BigInts which store zero should convert to inline." + ), + Sign::Plus => isize::try_from(slice.len()).unwrap(), }; - Self(SmallIntType::Heap((slice.as_mut_ptr(), size))) } + Self(SmallIntType::Heap((slice.as_mut_ptr(), size))) + } } } } -#[cfg(feature="num-bigint")] +#[cfg(feature = "num-bigint")] impl From for BigInt { fn from(s: SmallInt) -> Self { match s.0 { @@ -270,7 +270,7 @@ impl From for BigInt { } } -#[cfg(feature="num-bigint")] +#[cfg(feature = "num-bigint")] impl From for SmallUint { fn from(b: BigUint) -> Self { match (&b).try_into() { @@ -279,12 +279,13 @@ impl From for SmallUint { let vec = b.to_u32_digits(); let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); let size = slice.len(); - Self(SmallUintType::Heap((slice.as_mut_ptr(), size))) } + Self(SmallUintType::Heap((slice.as_mut_ptr(), size))) + } } } } -#[cfg(feature="num-bigint")] +#[cfg(feature = "num-bigint")] impl From for BigUint { fn from(s: SmallUint) -> Self { match s.0 { @@ -298,14 +299,12 @@ impl From for BigUint { } } - - #[cfg(test)] mod conversion_tests { use crate::SmallInt; - #[cfg(feature="num-bigint")] + #[cfg(feature = "num-bigint")] use num_bigint::{BigInt, Sign}; macro_rules! conversion_tests { @@ -320,8 +319,7 @@ mod conversion_tests { let s = SmallInt::from(i); assert_eq!(<$t>::try_from(s).unwrap(), i); } - - } + }; } conversion_tests!(u8, test_u8); @@ -336,12 +334,13 @@ mod conversion_tests { conversion_tests!(i128, test_i128); #[test] - #[cfg(feature="num-bigint")] + #[cfg(feature = "num-bigint")] fn test_bigint() { let i = BigInt::new(Sign::Plus, vec![5, 4, 8, 3, 2, 9, 3]); let s = SmallInt::from(i); - assert_eq!(BigInt::from(s).to_u32_digits(), (Sign::Plus, vec![5, 4, 8, 3, 2, 9, 3])); + assert_eq!( + BigInt::from(s).to_u32_digits(), + (Sign::Plus, vec![5, 4, 8, 3, 2, 9, 3]) + ); } - } -