1use crate::canon::CanonicalTypeId;
6use crate::engine::Engine;
7use crate::value::{FuncType, HeapType, Mutability, TagType, ValType};
8use crate::Result;
9
10#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
12pub enum Finality {
13 Final,
14 NonFinal,
15}
16
17#[derive(Clone, Debug, PartialEq, Eq, Hash)]
19pub enum StorageType {
20 I8,
21 I16,
22 ValType(ValType),
23}
24
25impl StorageType {
26 pub fn is_val_type(&self) -> bool {
28 matches!(self, StorageType::ValType(_))
29 }
30}
31
32#[derive(Clone, Debug, PartialEq, Eq, Hash)]
34pub struct FieldType {
35 mutability: Mutability,
36 element_type: StorageType,
37}
38
39impl FieldType {
40 pub fn new(mutability: Mutability, element_type: StorageType) -> Self {
41 FieldType {
42 mutability,
43 element_type,
44 }
45 }
46
47 pub fn mutability(&self) -> Mutability {
48 self.mutability
49 }
50
51 pub fn element_type(&self) -> &StorageType {
52 &self.element_type
53 }
54}
55
56pub struct StructType {
59 engine: Engine,
60 id: CanonicalTypeId,
61}
62
63impl StructType {
64 pub fn new(engine: &Engine, fields: impl IntoIterator<Item = FieldType>) -> Result<Self> {
65 Self::with_finality_and_supertype(engine, Finality::Final, None, fields)
66 }
67
68 pub fn with_finality_and_supertype(
69 engine: &Engine,
70 finality: Finality,
71 supertype: Option<&Self>,
72 fields: impl IntoIterator<Item = FieldType>,
73 ) -> Result<Self> {
74 let fields: Vec<FieldType> = fields.into_iter().collect();
75 assert!(
76 supertype.is_none_or(|ty| ty.engine().same(engine)),
77 "struct supertype belongs to a different engine"
78 );
79 assert!(
80 fields
81 .iter()
82 .all(|field| field_belongs_to_engine(field, engine)),
83 "struct field contains a concrete type from a different engine"
84 );
85 let id =
86 engine.intern_struct_type(finality, supertype.map(StructType::canonical_id), &fields);
87 Ok(StructType {
88 engine: engine.clone(),
89 id,
90 })
91 }
92
93 pub(crate) fn from_id(engine: &Engine, id: CanonicalTypeId) -> Self {
94 engine.incref_type(id);
95 StructType {
96 engine: engine.clone(),
97 id,
98 }
99 }
100
101 pub(crate) fn canonical_id(&self) -> CanonicalTypeId {
102 self.id
103 }
104
105 pub(crate) fn engine(&self) -> &Engine {
106 &self.engine
107 }
108
109 pub fn field(&self, i: usize) -> Option<FieldType> {
110 self.fields().nth(i)
111 }
112
113 pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldType> {
116 self.engine
117 .struct_fields(self.id)
118 .expect("live StructType registration must retain its fields")
119 .into_iter()
120 }
121}
122
123pub struct ArrayType {
126 engine: Engine,
127 id: CanonicalTypeId,
128}
129
130impl ArrayType {
131 pub fn new(engine: &Engine, field_type: FieldType) -> Self {
132 Self::with_finality_and_supertype(engine, Finality::Final, None, field_type)
133 .expect("array type without a supertype never fails")
134 }
135
136 pub fn with_finality_and_supertype(
137 engine: &Engine,
138 finality: Finality,
139 supertype: Option<&Self>,
140 field_type: FieldType,
141 ) -> Result<Self> {
142 assert!(
143 supertype.is_none_or(|ty| ty.engine().same(engine)),
144 "array supertype belongs to a different engine"
145 );
146 assert!(
147 field_belongs_to_engine(&field_type, engine),
148 "array field contains a concrete type from a different engine"
149 );
150 let id = engine.intern_array_type(
151 finality,
152 supertype.map(ArrayType::canonical_id),
153 &field_type,
154 );
155 Ok(ArrayType {
156 engine: engine.clone(),
157 id,
158 })
159 }
160
161 pub(crate) fn from_id(engine: &Engine, id: CanonicalTypeId) -> Self {
162 engine.incref_type(id);
163 ArrayType {
164 engine: engine.clone(),
165 id,
166 }
167 }
168
169 pub(crate) fn canonical_id(&self) -> CanonicalTypeId {
170 self.id
171 }
172
173 pub(crate) fn engine(&self) -> &Engine {
174 &self.engine
175 }
176
177 pub fn field_type(&self) -> FieldType {
180 self.engine
181 .array_field(self.id)
182 .expect("live ArrayType registration must retain its field")
183 }
184
185 pub fn element_type(&self) -> StorageType {
186 self.field_type().element_type().clone()
187 }
188}
189
190fn field_belongs_to_engine(field: &FieldType, engine: &Engine) -> bool {
191 match field.element_type() {
192 StorageType::I8 | StorageType::I16 => true,
193 StorageType::ValType(ty) => crate::value::val_type_belongs_to_engine(ty, engine),
194 }
195}
196
197macro_rules! handle_id_traits {
198 ($ty:ident) => {
199 impl Clone for $ty {
200 fn clone(&self) -> Self {
201 self.engine.incref_type(self.id);
202 $ty {
203 engine: self.engine.clone(),
204 id: self.id,
205 }
206 }
207 }
208 impl Drop for $ty {
209 fn drop(&mut self) {
210 self.engine.decref_type(self.id);
211 }
212 }
213 impl PartialEq for $ty {
214 fn eq(&self, other: &Self) -> bool {
215 self.id == other.id
216 }
217 }
218 impl Eq for $ty {}
219 impl core::hash::Hash for $ty {
220 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
221 self.id.hash(state);
222 }
223 }
224 impl core::fmt::Debug for $ty {
225 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
226 f.debug_struct(stringify!($ty))
227 .field("id", &self.id)
228 .finish_non_exhaustive()
229 }
230 }
231 };
232}
233
234handle_id_traits!(StructType);
235handle_id_traits!(ArrayType);
236
237impl From<StructType> for HeapType {
238 fn from(t: StructType) -> Self {
239 HeapType::ConcreteStruct(t)
240 }
241}
242
243impl From<ArrayType> for HeapType {
244 fn from(t: ArrayType) -> Self {
245 HeapType::ConcreteArray(t)
246 }
247}
248
249impl From<FuncType> for HeapType {
250 fn from(t: FuncType) -> Self {
251 HeapType::ConcreteFunc(t)
252 }
253}
254
255#[derive(Clone, Debug, PartialEq, Eq, Hash)]
258pub struct ExnType {
259 func: FuncType,
260}
261
262impl ExnType {
263 pub fn new(engine: &Engine, fields: impl IntoIterator<Item = ValType>) -> Result<ExnType> {
264 Ok(ExnType {
265 func: FuncType::new(engine, fields, []),
266 })
267 }
268
269 pub fn from_tag_type(tag: &TagType) -> Result<ExnType> {
270 Ok(ExnType {
271 func: tag.ty().clone(),
272 })
273 }
274
275 pub fn tag_type(&self) -> TagType {
277 TagType::new(self.func.clone())
278 }
279
280 pub fn field(&self, i: usize) -> Option<FieldType> {
281 self.func.params().nth(i).map(exn_field)
282 }
283
284 pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldType> {
285 self.func.params().map(exn_field)
286 }
287
288 pub fn engine(&self) -> &Engine {
289 self.func.engine()
290 }
291
292 pub fn matches(&self, other: &ExnType) -> bool {
293 self.func == other.func
294 }
295
296 pub(crate) fn func(&self) -> &FuncType {
297 &self.func
298 }
299}
300
301fn exn_field(ty: ValType) -> FieldType {
303 FieldType::new(Mutability::Const, StorageType::ValType(ty))
304}
305
306#[derive(Clone, Debug)]
309pub struct RecGroupType {
310 _private: (),
311}