diff --git a/src/convert.rs b/src/convert.rs index c389848..40ac480 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -98,10 +98,10 @@ impl From for SmallInt { } } -impl TryFrom for u128 { +impl TryFrom<&SmallInt> for u128 { type Error = SmallIntError; - fn try_from(s: SmallInt) -> Result { + fn try_from(s: &SmallInt) -> Result { match s.0 { SmallIntType::Inline(i) => { u128::try_from(i).map_err(|_| SmallIntError::ConversionError) @@ -125,6 +125,14 @@ impl TryFrom for u128 { } } +impl TryFrom for u128 { + type Error = SmallIntError; + + fn try_from(value: SmallInt) -> Result { + Self::try_from(&value) + } +} + impl From for SmallInt { fn from(s: SmallUint) -> Self { match s.0 { @@ -143,10 +151,10 @@ impl From for SmallInt { } } -impl TryFrom for SmallUint { +impl TryFrom<&SmallInt> for SmallUint { type Error = SmallIntError; - fn try_from(value: SmallInt) -> Result { + fn try_from(value: &SmallInt) -> Result { match value.0 { SmallIntType::Inline(i) => Self::try_from(i), SmallIntType::Heap((r, s)) => { @@ -165,11 +173,19 @@ impl TryFrom for SmallUint { } } -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::from(i.unsigned_abs()), +impl TryFrom for SmallUint { + type Error = SmallIntError; + + fn try_from(value: SmallInt) -> Result { + 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 { @@ -177,11 +193,11 @@ impl SmallUint { 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))) + SmallUint(SmallUintType::Heap((val.as_mut_ptr(), size))) } else if s >= 0 { - Self(SmallUintType::Inline(u128::try_from(value).unwrap())) + SmallUint(SmallUintType::Inline(u128::try_from(self).unwrap())) } else { - Self(SmallUintType::Inline(u128::try_from(-value).unwrap())) + SmallUint(SmallUintType::Inline(u128::try_from(-self).unwrap())) } } } diff --git a/src/ops.rs b/src/ops.rs index 5895afa..e87624a 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -4,10 +4,10 @@ use core::mem::ManuallyDrop; use core::ops::{Add, Div, Mul, Neg, Sub}; use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign}; -impl Neg for SmallInt { - type Output = Self; +impl Neg for &SmallInt { + type Output = SmallInt; - fn neg(self) -> Self::Output { + fn neg(self) -> SmallInt { match self.0 { SmallIntType::Inline(i) => { if let Some(n) = i.checked_neg() { @@ -30,6 +30,14 @@ impl Neg for SmallInt { } } +impl Neg for SmallInt { + type Output = SmallInt; + + fn neg(self) -> SmallInt { + (&self).neg() + } +} + macro_rules! basic_op { ($imp:ident, $lower:ident, $typ:ty, $fun:ident) => { impl<'a, 'b> $imp<&'a $typ> for &'b $typ { @@ -178,17 +186,17 @@ fn add_signed(a: &SmallInt, b: &SmallInt) -> SmallInt { match (a_sign, b_sign) { x if (x.0 >= 0 && x.1 >= 0) => SmallInt::from( - SmallUint::from_smallint_unsigned(a.clone()) - + SmallUint::from_smallint_unsigned(b.clone()), + a.unsigned_abs() + + b.unsigned_abs(), ), x if (x.0 < 0 && x.1 < 0) => -SmallInt::from( - SmallUint::from_smallint_unsigned(a.clone()) - + SmallUint::from_smallint_unsigned(b.clone()), + a.unsigned_abs() + + b.unsigned_abs(), ), x if (x.0 >= 0 && x.1 < 0) => { - let s = SmallUint::from_smallint_unsigned(a.clone()); - let b = SmallUint::from_smallint_unsigned(b.clone()); + let s = a.unsigned_abs(); + let b = b.unsigned_abs(); if b <= s { SmallInt::from(s - b) } else { @@ -197,8 +205,8 @@ fn add_signed(a: &SmallInt, b: &SmallInt) -> SmallInt { } x if (x.0 < 0 && x.1 >= 0) => { - let s = SmallUint::from_smallint_unsigned(a.clone()); - let b = SmallUint::from_smallint_unsigned(b.clone()); + let s = a.unsigned_abs(); + let b = b.unsigned_abs(); if s <= b { SmallInt::from(b - s) } else { @@ -552,22 +560,22 @@ fn mul_signed(a: &SmallInt, b: &SmallInt) -> SmallInt { match (a_sign, b_sign) { x if (x.0 >= 0 && x.1 >= 0) => SmallInt::from( - SmallUint::from_smallint_unsigned(a.clone()) - * SmallUint::from_smallint_unsigned(b.clone()), + a.unsigned_abs() + * b.unsigned_abs(), ), x if (x.0 < 0 && x.1 < 0) => SmallInt::from( - SmallUint::from_smallint_unsigned(a.clone()) - * SmallUint::from_smallint_unsigned(b.clone()), + a.unsigned_abs() + * b.unsigned_abs(), ), x if (x.0 >= 0 && x.1 < 0) => -SmallInt::from( - SmallUint::from_smallint_unsigned(a.clone()) - * SmallUint::from_smallint_unsigned(b.clone()), + a.unsigned_abs() + * b.unsigned_abs(), ), x if (x.0 < 0 && x.1 >= 0) => -SmallInt::from( - SmallUint::from_smallint_unsigned(a.clone()) - * SmallUint::from_smallint_unsigned(b.clone()), + a.unsigned_abs() + * b.unsigned_abs(), ), (_, _) => { diff --git a/src/ord.rs b/src/ord.rs index ccb5259..01f6d1b 100644 --- a/src/ord.rs +++ b/src/ord.rs @@ -6,23 +6,12 @@ use std::cmp::Ordering; impl PartialEq for SmallUint { fn eq(&self, other: &SmallUint) -> bool { match (&self.0, &other.0) { - (SmallUintType::Inline(i), SmallUintType::Inline(j)) => i.eq(j), - (SmallUintType::Heap((r, s)), SmallUintType::Heap((i, j))) => match j.cmp(s) { - Ordering::Greater => false, - Ordering::Less => false, - Ordering::Equal => { - let slice1 = unsafe { core::slice::from_raw_parts(*r, *s) }; - let slice2 = unsafe { core::slice::from_raw_parts(*i, *j) }; - for i in 0..*s { - match slice1[s - 1 - i].cmp(&slice2[s - 1 - i]) { - Ordering::Less => return false, - Ordering::Greater => return false, - _ => {} - } - } - true - } - }, + (SmallUintType::Inline(i), SmallUintType::Inline(j)) => i == j, + (SmallUintType::Heap((p, s)), SmallUintType::Heap((q, t))) => { + let slice1 = unsafe { core::slice::from_raw_parts(*p, *s) }; + let slice2 = unsafe { core::slice::from_raw_parts(*q, *t) }; + slice1 == slice2 + } (_, _) => false, } } @@ -32,57 +21,45 @@ impl Eq for SmallUint {} impl PartialOrd for SmallUint { fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for SmallUint { + fn cmp(&self, other: &Self) -> Ordering { match (&self.0, &other.0) { - (SmallUintType::Inline(i), SmallUintType::Inline(j)) => Some(i.cmp(j)), - (SmallUintType::Inline(_), SmallUintType::Heap((_, _))) => Some(Ordering::Less), - (SmallUintType::Heap((_, _)), SmallUintType::Inline(_)) => Some(Ordering::Greater), - (SmallUintType::Heap((r, s)), SmallUintType::Heap((i, j))) => match j.cmp(s) { - Ordering::Greater => Some(Ordering::Less), - Ordering::Less => Some(Ordering::Greater), + (SmallUintType::Inline(i), SmallUintType::Inline(j)) => i.cmp(j), + (SmallUintType::Inline(_), SmallUintType::Heap((_, _))) => Ordering::Less, + (SmallUintType::Heap((_, _)), SmallUintType::Inline(_)) => Ordering::Greater, + (SmallUintType::Heap((p, s)), SmallUintType::Heap((q, t))) => match s.cmp(t) { Ordering::Equal => { - let slice1 = unsafe { core::slice::from_raw_parts(*r, *s) }; - let slice2 = unsafe { core::slice::from_raw_parts(*i, *j) }; + let slice1 = unsafe { core::slice::from_raw_parts(*p, *s) }; + let slice2 = unsafe { core::slice::from_raw_parts(*q, *t) }; for i in 0..*s { match slice1[s - 1 - i].cmp(&slice2[s - 1 - i]) { - Ordering::Less => return Some(Ordering::Less), - Ordering::Greater => return Some(Ordering::Greater), - _ => {} + Ordering::Equal => {} + o => return o, } } - Some(Ordering::Equal) + Ordering::Equal } - }, + o => o, + } } } } impl PartialEq for SmallInt { - fn eq(&self, other: &Self) -> bool { + fn eq(&self, other: &SmallInt) -> bool { match (&self.0, &other.0) { - (SmallIntType::Inline(i), SmallIntType::Inline(j)) => i.eq(j), - (SmallIntType::Heap((r, s)), SmallIntType::Heap((i, j))) => { - if s.signum() != j.signum() { + (SmallIntType::Inline(i), SmallIntType::Inline(j)) => i == j, + (SmallIntType::Heap((p, s)), SmallIntType::Heap((q, t))) => { + if s != t { // need to compare signs, at minimum return false; } - - match j.cmp(s) { - Ordering::Greater => false, - Ordering::Less => false, - Ordering::Equal => { - let us = s.unsigned_abs(); - let uj = j.unsigned_abs(); - let slice1 = unsafe { core::slice::from_raw_parts(*r, us) }; - let slice2 = unsafe { core::slice::from_raw_parts(*i, uj) }; - for i in 0..*s { - match slice1[(s - 1 - i) as usize].cmp(&slice2[(s - 1 - i) as usize]) { - Ordering::Less => return false, - Ordering::Greater => return false, - _ => {} - } - } - true - } - } + let slice1 = unsafe { core::slice::from_raw_parts(*p, s.unsigned_abs()) }; + let slice2 = unsafe { core::slice::from_raw_parts(*q, t.unsigned_abs()) }; + slice1 == slice2 } (_, _) => false, } @@ -93,36 +70,27 @@ impl Eq for SmallInt {} impl PartialOrd for SmallInt { fn partial_cmp(&self, other: &Self) -> Option { - let a_sign; - match &self.0 { - SmallIntType::Inline(i) => a_sign = i.signum() as i8, - SmallIntType::Heap((_, s)) => a_sign = s.signum() as i8, - } - - let b_sign; - match &other.0 { - SmallIntType::Inline(i) => b_sign = i.signum() as i8, - SmallIntType::Heap((_, s)) => b_sign = s.signum() as i8, - } - - match (a_sign, b_sign) { - x if (x.0 >= 0 && x.1 < 0) => Some(Ordering::Greater), - - x if (x.0 < 0 && x.1 >= 0) => Some(Ordering::Less), - - x if (x.0 >= 0 && x.1 >= 0) => SmallUint::from_smallint_unsigned(self.clone()) - .partial_cmp(&SmallUint::from_smallint_unsigned(other.clone())), - - x if (x.0 < 0 && x.1 < 0) => SmallUint::from_smallint_unsigned(other.clone()) - .partial_cmp(&SmallUint::from_smallint_unsigned(self.clone())), - - (_, _) => None, - } + Some(self.cmp(other)) } } impl Ord for SmallInt { fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).expect("This should not happen.") + let a_sign = match &self.0 { + SmallIntType::Inline(i) => i.cmp(&0), + SmallIntType::Heap((_, s)) => s.cmp(&0), + }; + let b_sign = match &other.0 { + SmallIntType::Inline(j) => j.cmp(&0), + SmallIntType::Heap((_, t)) => t.cmp(&0), + }; + match a_sign.cmp(&b_sign) { + Ordering::Equal => match a_sign { + Ordering::Less => other.unsigned_abs().cmp(&self.unsigned_abs()), + Ordering::Equal => Ordering::Equal, + Ordering::Greater => self.unsigned_abs().cmp(&other.unsigned_abs()), + }, + o => o, + } } } diff --git a/src/tests.rs b/src/tests.rs index 8ce5168..7a6d9fc 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -260,7 +260,7 @@ fn test_op_neg() { #[cfg(feature = "num-bigint")] fn test_conversion_sign_drop() { run_tests_i_1( - |i| BigUint::from(&SmallUint::from_smallint_unsigned(i)), + |i| BigUint::from(&SmallInt::unsigned_abs(&i)), |i| i.magnitude().clone() ); }