wasmtime/runtime/vm/gc/
i31.rs

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