mirror of
https://gitlab.com/artofrev/smallint.git
synced 2025-04-02 12:16:38 -04:00
206 lines
6.6 KiB
Rust
206 lines
6.6 KiB
Rust
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 = s.unsigned_abs();
|
|
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 TryFrom<SmallInt> for u128 {
|
|
type Error = SmallIntError;
|
|
|
|
fn try_from(value: SmallInt) -> Result<Self, Self::Error> {
|
|
Self::try_from(&value)
|
|
}
|
|
}
|
|
|
|
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 TryFrom<SmallInt> for SmallUint {
|
|
type Error = SmallIntError;
|
|
|
|
fn try_from(value: SmallInt) -> Result<Self, Self::Error> {
|
|
Self::try_from(&value)
|
|
}
|
|
}
|
|
|
|
impl SmallInt {
|
|
/// Returns the absolute value of the `SmallInt` as a `SmallUint`.
|
|
pub fn unsigned_abs(&self) -> SmallUint {
|
|
match self.0 {
|
|
SmallIntType::Inline(i) => SmallUint::from(i.unsigned_abs()),
|
|
SmallIntType::Heap((r, s)) => {
|
|
let size = s.unsigned_abs();
|
|
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());
|
|
SmallUint(SmallUintType::Heap((val.as_mut_ptr(), size)))
|
|
} else if s >= 0 {
|
|
SmallUint(SmallUintType::Inline(u128::try_from(self).unwrap()))
|
|
} else {
|
|
SmallUint(SmallUintType::Inline(u128::try_from(-self).unwrap()))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|