diff --git a/src/ops.rs b/src/ops.rs index 8431556..6f8780a 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -9,7 +9,15 @@ impl Neg for SmallInt { fn neg(self) -> Self::Output { match self.0 { - SmallIntType::Inline(i) => SmallInt(SmallIntType::Inline(-i)), + SmallIntType::Inline(i) => { + if let Some(n) = i.checked_neg() { + SmallInt(SmallIntType::Inline(n)) + } else { + // -i128::MIN = i128::MAX + 1 = 0x8000... + let mut val = ManuallyDrop::new(Box::new([0, 0, 0, 0x80_00_00_00])); + SmallInt(SmallIntType::Heap((val.as_mut_ptr(), 4))) + } + }, SmallIntType::Heap((r, s)) => { let size = usize::try_from(s.abs()).unwrap(); let slice = unsafe { core::slice::from_raw_parts(r, size) }; diff --git a/src/tests.rs b/src/tests.rs index a8a3c8e..f7d3666 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -320,9 +320,13 @@ fn test_op_neg() { let q = -i; assert_eq!(BigInt::from(&q), -BigInt::from(u128::MAX)); - let i = SmallInt::from(i64::MIN); + let i = SmallInt::from(i128::MAX); let q = -i; - assert_eq!(BigInt::from(&q), -BigInt::from(i64::MIN)); + assert_eq!(BigInt::from(&q), -BigInt::from(i128::MAX)); + + let i = SmallInt::from(i128::MIN); + let q = -i; + assert_eq!(BigInt::from(&q), -BigInt::from(i128::MIN)); } #[test]