dusk_wasmtime_runtime/gc/
i31.rs

1//! Implementation of unboxed 31-bit integers.
2
3use super::VMGcRef;
4
5/// A 31-bit integer for use with `i31ref`.
6#[derive(Clone, Copy, PartialEq, Eq, Hash)]
7pub struct I31(pub(super) u32);
8
9impl Default for I31 {
10    #[inline]
11    fn default() -> Self {
12        Self::wrapping_u32(0)
13    }
14}
15
16impl std::fmt::Debug for I31 {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        f.debug_struct("I31")
19            .field("as_u32", &self.get_u32())
20            .field("as_i32", &self.get_i32())
21            .finish()
22    }
23}
24
25impl I31 {
26    const DISCRIMINANT: u32 = VMGcRef::I31_REF_DISCRIMINANT;
27
28    /// Construct a new `I31` from the given unsigned value.
29    ///
30    /// Returns `None` if the value does not fit in the bottom 31 bits.
31    #[inline]
32    pub fn new_u32(value: u32) -> Option<Self> {
33        if ((value << 1) >> 1) == value {
34            let i31 = Self::wrapping_u32(value);
35            debug_assert_eq!(i31.get_u32(), value);
36            Some(i31)
37        } else {
38            None
39        }
40    }
41
42    /// Construct a new `I31` from the given signed value.
43    ///
44    /// Returns `None` if the value does not fit in the bottom 31 bits.
45    #[inline]
46    pub fn new_i32(value: i32) -> Option<Self> {
47        if ((value << 1) >> 1) == value {
48            let i31 = Self::wrapping_i32(value);
49            debug_assert_eq!(i31.get_i32(), value);
50            Some(i31)
51        } else {
52            None
53        }
54    }
55
56    /// Construct a new `I31` from the given unsigned value.
57    ///
58    /// If the value doesn't fit in the bottom 31 bits, it is wrapped such that
59    /// the wrapped value does.
60    #[inline]
61    pub fn wrapping_u32(value: u32) -> Self {
62        Self((value << 1) | Self::DISCRIMINANT)
63    }
64
65    /// Construct a new `I31` from the given signed value.
66    ///
67    /// If the value doesn't fit in the bottom 31 bits, it is wrapped such that
68    /// the wrapped value does.
69    #[inline]
70    #[allow(clippy::cast_sign_loss)]
71    pub fn wrapping_i32(value: i32) -> Self {
72        Self::wrapping_u32(value as u32)
73    }
74
75    /// Get this `I31`'s value as an unsigned integer.
76    #[inline]
77    pub fn get_u32(&self) -> u32 {
78        self.0 >> 1
79    }
80
81    /// Get this `I31`'s value as ansigned integer.
82    #[inline]
83    pub fn get_i32(&self) -> i32 {
84        (self.0 as i32) >> 1
85    }
86}