wasmtime/runtime/vm/gc/
i31.rs

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