Skip to content

Commit

Permalink
fix small integer
Browse files Browse the repository at this point in the history
Co-authored-by: Aapo Alasuutari <[email protected]>
  • Loading branch information
sno2 and aapoalas committed Jul 24, 2023
1 parent b60617c commit 25fddb8
Showing 1 changed file with 52 additions and 14 deletions.
66 changes: 52 additions & 14 deletions nova_vm/src/small_integer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// 56-bit signed integer.
#[derive(Clone, Copy)]
#[derive(Clone, Copy, PartialEq)]
pub struct SmallInteger {
data: [u8; 7],
}
Expand All @@ -11,18 +11,23 @@ impl std::fmt::Debug for SmallInteger {
}

impl SmallInteger {
pub const MIN: i64 = -(2 as i64).pow(56) / 2 + 1;
pub const MAX: i64 = (2 as i64).pow(56) / 2 - 1;
pub const MIN: i64 = -(2 as i64).pow(53) / 2 + 1;
pub const MAX: i64 = (2 as i64).pow(53) / 2 - 1;

pub(crate) fn from_i64_unchecked(value: i64) -> SmallInteger {
debug_assert!(value >= Self::MIN && value <= Self::MAX);
let mut data: [u8; 7] = [0, 0, 0, 0, 0, 0, 0];
let bytes = i64::to_ne_bytes(value);
if cfg!(target_endian = "little") {
data.copy_from_slice(&bytes[0..7]);

let data = if cfg!(target_endian = "little") {
[
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
]
} else {
data.copy_from_slice(&bytes[1..8]);
}
[
bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
]
};

Self { data }
}
}
Expand All @@ -41,12 +46,45 @@ impl TryFrom<i64> for SmallInteger {
impl Into<i64> for SmallInteger {
fn into(self) -> i64 {
let Self { data } = self;
let mut bytes: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
bytes.copy_from_slice(&data);
if cfg!(target_endian = "big") {
bytes.copy_within(0..7, 1);

#[repr(u8)]
enum Repr {
Data([u8; 7]),
}

// SAFETY: This matches the format on the endian platform.
let number: i64 = unsafe { std::mem::transmute(Repr::Data(data)) };

if cfg!(target_endian = "little") {
number >> 8
} else {
number << 8 >> 8
}
// SAFETY: The format is guaranteed to match `from_i64_unchecked`.
unsafe { std::mem::transmute(bytes) }
}
}

#[test]
fn valid_small_integers() {
assert_eq!(0i64, SmallInteger::try_from(0).unwrap().into());
assert_eq!(5i64, SmallInteger::try_from(5).unwrap().into());
assert_eq!(23i64, SmallInteger::try_from(23).unwrap().into());
assert_eq!(
SmallInteger::MAX,
SmallInteger::try_from(SmallInteger::MAX).unwrap().into()
);

assert_eq!(-5i64, SmallInteger::try_from(-5).unwrap().into());
assert_eq!(-59i64, SmallInteger::try_from(-59).unwrap().into());
assert_eq!(
SmallInteger::MIN,
SmallInteger::try_from(SmallInteger::MIN).unwrap().into()
);
}

#[test]
fn invalid_small_integers() {
assert_eq!(SmallInteger::try_from(SmallInteger::MAX + 1), Err(()));
assert_eq!(SmallInteger::try_from(i64::MAX), Err(()));
assert_eq!(SmallInteger::try_from(SmallInteger::MIN - 1), Err(()));
assert_eq!(SmallInteger::try_from(i64::MIN), Err(()));
}

0 comments on commit 25fddb8

Please sign in to comment.