tinywasm_types/
reference.rs1#[repr(u8)]
7#[derive(Clone, Copy, PartialEq, Eq, Hash)]
8#[cfg_attr(feature = "debug", derive(Debug))]
9#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
10pub enum AbstractHeapType {
11 Any,
12 Eq,
13 I31,
14 Struct,
15 Array,
16 None,
17
18 Func,
19 NoFunc,
20
21 Exn,
22 NoExn,
23
24 Extern,
25 NoExtern,
26}
27
28#[derive(Clone, Copy, PartialEq, Eq, Hash)]
42#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
43pub struct RefType(u32);
44
45#[cfg(feature = "debug")]
46impl core::fmt::Debug for RefType {
47 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48 if self.is_concrete() {
49 write!(f, "concrete({})", self.type_index().unwrap())
50 } else {
51 write!(f, "abstract({:?})", self.abstract_heap_type().unwrap())
52 }
53 }
54}
55
56impl RefType {
57 const NULLABLE: u32 = 1 << 31;
58 const CONCRETE: u32 = 1 << 30;
59 const PAYLOAD_MASK: u32 = Self::CONCRETE - 1;
60
61 pub const FUNCREF: Self = Self::new_abstract(true, AbstractHeapType::Func);
62 pub const EXTERNREF: Self = Self::new_abstract(true, AbstractHeapType::Extern);
63 pub const EXNREF: Self = Self::new_abstract(true, AbstractHeapType::Exn);
64
65 #[inline]
66 #[doc(hidden)]
67 pub const fn to_bits(self) -> u32 {
68 self.0
69 }
70
71 #[inline]
72 #[doc(hidden)]
73 pub const fn from_bits(bits: u32) -> Option<Self> {
74 let ty = Self(bits);
75 if ty.is_concrete() || ty.abstract_heap_type().is_some() { Some(ty) } else { None }
76 }
77
78 #[inline]
79 pub const fn new_abstract(nullable: bool, heap_type: AbstractHeapType) -> Self {
80 Self((nullable as u32) << 31 | heap_type as u32)
81 }
82
83 #[inline]
84 pub const fn new_concrete(nullable: bool, type_index: u32) -> Self {
85 assert!(type_index <= Self::PAYLOAD_MASK, "type index is too large for a reference type");
86 Self(((nullable as u32) << 31) | Self::CONCRETE | type_index)
87 }
88
89 #[inline]
90 pub const fn is_nullable(self) -> bool {
91 self.0 & Self::NULLABLE != 0
92 }
93
94 #[inline]
95 pub const fn is_concrete(self) -> bool {
96 self.0 & Self::CONCRETE != 0
97 }
98
99 #[inline]
100 pub const fn type_index(self) -> Option<u32> {
101 if self.is_concrete() { Some(self.0 & Self::PAYLOAD_MASK) } else { None }
102 }
103
104 #[inline]
105 pub const fn abstract_heap_type(self) -> Option<AbstractHeapType> {
106 if self.is_concrete() {
107 return None;
108 }
109
110 match self.0 & Self::PAYLOAD_MASK {
111 0 => Some(AbstractHeapType::Any),
112 1 => Some(AbstractHeapType::Eq),
113 2 => Some(AbstractHeapType::I31),
114 3 => Some(AbstractHeapType::Struct),
115 4 => Some(AbstractHeapType::Array),
116 5 => Some(AbstractHeapType::None),
117 6 => Some(AbstractHeapType::Func),
118 7 => Some(AbstractHeapType::NoFunc),
119 8 => Some(AbstractHeapType::Exn),
120 9 => Some(AbstractHeapType::NoExn),
121 10 => Some(AbstractHeapType::Extern),
122 11 => Some(AbstractHeapType::NoExtern),
123 _ => None,
124 }
125 }
126
127 #[inline]
128 pub const fn with_nullability(self, nullable: bool) -> Self {
129 Self((self.0 & !Self::NULLABLE) | ((nullable as u32) << 31))
130 }
131
132 #[inline]
133 pub const fn is_func(self) -> bool {
134 matches!(self.abstract_heap_type(), Some(AbstractHeapType::Func | AbstractHeapType::NoFunc))
135 }
136
137 #[inline]
138 pub const fn is_extern(self) -> bool {
139 matches!(self.abstract_heap_type(), Some(AbstractHeapType::Extern | AbstractHeapType::NoExtern))
140 }
141
142 #[inline]
143 pub const fn is_exn(self) -> bool {
144 matches!(self.abstract_heap_type(), Some(AbstractHeapType::Exn | AbstractHeapType::NoExn))
145 }
146}