1use crate::canon::CanonicalTypeId;
4use crate::engine::Engine;
5use crate::value::gc_type::{ArrayType, StructType};
6use crate::value::tag_type::TagType;
7
8#[derive(Clone, Debug, PartialEq, Eq, Hash)]
10pub enum ValType {
11 I32,
12 I64,
13 F32,
14 F64,
15 V128,
16 Ref(RefType),
17}
18
19#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
21pub enum Mutability {
22 Const,
23 Var,
24}
25
26#[derive(Clone, Debug, PartialEq, Eq, Hash)]
28pub struct RefType {
29 nullable: bool,
30 heap: HeapType,
31}
32
33impl RefType {
34 pub fn new(is_nullable: bool, heap_type: HeapType) -> RefType {
35 RefType {
36 nullable: is_nullable,
37 heap: heap_type,
38 }
39 }
40
41 pub(crate) const fn new_nullable(heap: HeapType) -> RefType {
44 RefType {
45 nullable: true,
46 heap,
47 }
48 }
49
50 pub fn is_nullable(&self) -> bool {
51 self.nullable
52 }
53
54 pub fn heap_type(&self) -> &HeapType {
55 &self.heap
56 }
57}
58
59#[derive(Clone, Debug, PartialEq, Eq, Hash)]
64#[non_exhaustive]
65pub enum HeapType {
66 Func,
67 NoFunc,
68 Extern,
69 NoExtern,
70 Any,
71 Eq,
72 I31,
73 Struct,
74 ConcreteStruct(StructType),
76 Array,
77 ConcreteArray(ArrayType),
79 Exn,
80 NoExn,
81 None,
82 ConcreteFunc(FuncType),
84}
85
86impl HeapType {
87 pub(crate) fn matches(&self, other: &HeapType) -> bool {
92 use HeapType as H;
93 if self == other {
94 return true;
95 }
96 matches!(
97 (self, other),
98 (H::NoFunc, H::Func | H::ConcreteFunc(_))
99 | (H::ConcreteFunc(_), H::Func)
100 | (H::NoExtern, H::Extern)
101 | (H::NoExn, H::Exn)
102 | (H::I31 | H::Struct | H::Array | H::Eq, H::Any)
103 | (H::I31 | H::Struct | H::Array, H::Eq)
104 | (H::ConcreteStruct(_), H::Struct | H::Eq | H::Any)
105 | (H::ConcreteArray(_), H::Array | H::Eq | H::Any)
106 | (
107 H::None,
108 H::Any
109 | H::Eq
110 | H::I31
111 | H::Struct
112 | H::Array
113 | H::ConcreteStruct(_)
114 | H::ConcreteArray(_)
115 )
116 )
117 }
118}
119
120impl RefType {
121 pub(crate) fn matches(&self, other: &RefType) -> bool {
124 (!self.nullable || other.nullable) && self.heap.matches(&other.heap)
125 }
126}
127
128impl ValType {
129 pub(crate) fn matches(&self, other: &ValType) -> bool {
131 match (self, other) {
132 (ValType::Ref(a), ValType::Ref(b)) => a.matches(b),
133 _ => self == other,
134 }
135 }
136}
137
138pub(crate) fn val_type_belongs_to_engine(ty: &ValType, engine: &Engine) -> bool {
141 let ValType::Ref(reference) = ty else {
142 return true;
143 };
144 match reference.heap_type() {
145 HeapType::ConcreteStruct(ty) => ty.engine().same(engine),
146 HeapType::ConcreteArray(ty) => ty.engine().same(engine),
147 HeapType::ConcreteFunc(ty) => ty.engine().same(engine),
148 _ => true,
149 }
150}
151
152pub struct FuncType {
159 engine: Engine,
160 id: CanonicalTypeId,
161}
162
163impl FuncType {
164 pub fn new(
165 engine: &Engine,
166 params: impl IntoIterator<Item = ValType>,
167 results: impl IntoIterator<Item = ValType>,
168 ) -> FuncType {
169 let params: Vec<ValType> = params.into_iter().collect();
170 let results: Vec<ValType> = results.into_iter().collect();
171 assert!(
172 params
173 .iter()
174 .chain(&results)
175 .all(|ty| val_type_belongs_to_engine(ty, engine)),
176 "function type contains a concrete type from a different engine"
177 );
178 let id = engine.intern_func_type(¶ms, &results);
180 FuncType {
181 engine: engine.clone(),
182 id,
183 }
184 }
185
186 pub(crate) fn from_id(engine: &Engine, id: CanonicalTypeId) -> FuncType {
189 engine.incref_type(id);
190 FuncType {
191 engine: engine.clone(),
192 id,
193 }
194 }
195
196 pub(crate) fn canonical_id(&self) -> CanonicalTypeId {
198 self.id
199 }
200
201 pub(crate) fn engine(&self) -> &Engine {
202 &self.engine
203 }
204
205 pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> {
206 self.signature().0.into_iter()
207 }
208
209 pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> {
210 self.signature().1.into_iter()
211 }
212
213 fn signature(&self) -> (Vec<ValType>, Vec<ValType>) {
216 self.engine
217 .func_sig(self.id)
218 .expect("live FuncType registration must retain its signature")
219 }
220}
221
222impl Clone for FuncType {
223 fn clone(&self) -> Self {
224 self.engine.incref_type(self.id);
225 FuncType {
226 engine: self.engine.clone(),
227 id: self.id,
228 }
229 }
230}
231
232impl Drop for FuncType {
233 fn drop(&mut self) {
234 self.engine.decref_type(self.id);
235 }
236}
237
238impl PartialEq for FuncType {
239 fn eq(&self, other: &Self) -> bool {
240 self.id == other.id
241 }
242}
243
244impl Eq for FuncType {}
245
246impl core::hash::Hash for FuncType {
247 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
248 self.id.hash(state);
249 }
250}
251
252impl core::fmt::Debug for FuncType {
253 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
254 f.debug_struct("FuncType")
255 .field("id", &self.id)
256 .finish_non_exhaustive()
257 }
258}
259
260#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
262pub struct MemoryType {
263 minimum: u64,
264 maximum: Option<u64>,
265 memory64: bool,
266}
267
268impl MemoryType {
269 pub fn new(minimum: u32, maximum: Option<u32>) -> MemoryType {
270 MemoryType {
271 minimum: u64::from(minimum),
272 maximum: maximum.map(u64::from),
273 memory64: false,
274 }
275 }
276
277 pub fn new64(minimum: u64, maximum: Option<u64>) -> MemoryType {
278 MemoryType {
279 minimum,
280 maximum,
281 memory64: true,
282 }
283 }
284
285 pub fn minimum(&self) -> u64 {
286 self.minimum
287 }
288
289 pub fn maximum(&self) -> Option<u64> {
290 self.maximum
291 }
292
293 pub fn is_64(&self) -> bool {
294 self.memory64
295 }
296}
297
298#[derive(Clone, Debug, PartialEq, Eq, Hash)]
300pub struct GlobalType {
301 content: ValType,
302 mutability: Mutability,
303}
304
305impl GlobalType {
306 pub fn new(content: ValType, mutability: Mutability) -> GlobalType {
307 GlobalType {
308 content,
309 mutability,
310 }
311 }
312
313 pub fn content(&self) -> &ValType {
314 &self.content
315 }
316
317 pub fn mutability(&self) -> Mutability {
318 self.mutability
319 }
320}
321
322#[derive(Clone, Debug, PartialEq, Eq, Hash)]
325pub struct TableType {
326 element: RefType,
327 minimum: u64,
328 maximum: Option<u64>,
329 table64: bool,
330}
331
332impl TableType {
333 pub fn new(element: RefType, min: u32, max: Option<u32>) -> TableType {
334 TableType {
335 element,
336 minimum: u64::from(min),
337 maximum: max.map(u64::from),
338 table64: false,
339 }
340 }
341
342 pub fn new64(element: RefType, min: u64, max: Option<u64>) -> TableType {
343 TableType {
344 element,
345 minimum: min,
346 maximum: max,
347 table64: true,
348 }
349 }
350
351 pub fn element(&self) -> &RefType {
352 &self.element
353 }
354
355 pub fn minimum(&self) -> u64 {
356 self.minimum
357 }
358
359 pub fn maximum(&self) -> Option<u64> {
360 self.maximum
361 }
362
363 pub fn is_64(&self) -> bool {
364 self.table64
365 }
366}
367
368#[derive(Clone, Debug)]
370pub enum ExternType {
371 Func(FuncType),
372 Memory(MemoryType),
373 Global(GlobalType),
374 Table(TableType),
375 Tag(TagType),
376}
377
378#[derive(Clone, Debug)]
380pub struct ImportType<'module> {
381 module: &'module str,
382 name: &'module str,
383 ty: ExternType,
384}
385
386impl<'module> ImportType<'module> {
387 pub(crate) fn new(module: &'module str, name: &'module str, ty: ExternType) -> Self {
388 ImportType { module, name, ty }
389 }
390
391 pub fn module(&self) -> &'module str {
392 self.module
393 }
394
395 pub fn name(&self) -> &'module str {
396 self.name
397 }
398
399 pub fn ty(&self) -> ExternType {
400 self.ty.clone()
401 }
402}
403
404#[derive(Clone, Debug)]
406pub struct ExportType<'module> {
407 name: &'module str,
408 ty: ExternType,
409}
410
411impl<'module> ExportType<'module> {
412 pub(crate) fn new(name: &'module str, ty: ExternType) -> Self {
413 ExportType { name, ty }
414 }
415
416 pub fn name(&self) -> &'module str {
417 self.name
418 }
419
420 pub fn ty(&self) -> ExternType {
421 self.ty.clone()
422 }
423}