1use crate::indexes::{FunctionIndex, GlobalIndex};
2use crate::lib::std::borrow::ToOwned;
3use crate::lib::std::fmt;
4use crate::lib::std::format;
5use crate::lib::std::string::{String, ToString};
6use crate::lib::std::vec::Vec;
7use crate::units::Pages;
8
9use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
10#[cfg(feature = "enable-serde")]
11use serde::{Deserialize, Serialize};
12
13#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash)]
19#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
20#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
21#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
22#[rkyv(derive(Debug), compare(PartialEq))]
23#[repr(u8)]
24pub enum Type {
25 I32,
27 I64,
29 F32,
31 F64,
33 V128,
35 ExternRef, FuncRef,
39 ExceptionRef,
41}
42
43impl Type {
44 pub fn is_num(self) -> bool {
47 matches!(
48 self,
49 Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128
50 )
51 }
52
53 pub fn is_ref(self) -> bool {
55 matches!(self, Self::ExternRef | Self::FuncRef | Self::ExceptionRef)
56 }
57}
58
59impl fmt::Display for Type {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 write!(f, "{self:?}")
62 }
63}
64
65#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
67#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
68#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
69#[rkyv(derive(Debug), compare(PartialEq))]
70pub struct V128(pub(crate) [u8; 16]);
71
72#[cfg(feature = "artifact-size")]
73impl loupe::MemoryUsage for V128 {
74 fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
75 16 * 8
76 }
77}
78
79impl V128 {
80 pub fn bytes(&self) -> &[u8; 16] {
82 &self.0
83 }
84 pub fn iter(&self) -> impl Iterator<Item = &u8> {
86 self.0.iter()
87 }
88
89 pub fn to_vec(self) -> Vec<u8> {
91 self.0.to_vec()
92 }
93
94 pub fn as_slice(&self) -> &[u8] {
96 &self.0[..]
97 }
98}
99
100impl From<[u8; 16]> for V128 {
101 fn from(array: [u8; 16]) -> Self {
102 Self(array)
103 }
104}
105
106impl From<&[u8]> for V128 {
107 fn from(slice: &[u8]) -> Self {
108 assert_eq!(slice.len(), 16);
109 let mut buffer = [0; 16];
110 buffer.copy_from_slice(slice);
111 Self(buffer)
112 }
113}
114
115#[derive(Debug, Clone, PartialEq, Eq, Hash)]
123#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
124pub enum ExternType {
125 Function(FunctionType),
127 Global(GlobalType),
129 Table(TableType),
131 Memory(MemoryType),
133 Tag(TagType),
135}
136
137fn is_global_compatible(exported: GlobalType, imported: GlobalType) -> bool {
138 let GlobalType {
139 ty: exported_ty,
140 mutability: exported_mutability,
141 } = exported;
142 let GlobalType {
143 ty: imported_ty,
144 mutability: imported_mutability,
145 } = imported;
146
147 exported_ty == imported_ty && imported_mutability == exported_mutability
148}
149
150fn is_table_element_type_compatible(exported_type: Type, imported_type: Type) -> bool {
151 match exported_type {
152 Type::FuncRef => true,
153 _ => imported_type == exported_type,
154 }
155}
156
157fn is_table_compatible(
158 exported: &TableType,
159 imported: &TableType,
160 imported_runtime_size: Option<u32>,
161) -> bool {
162 let TableType {
163 ty: exported_ty,
164 minimum: exported_minimum,
165 maximum: exported_maximum,
166 } = exported;
167 let TableType {
168 ty: imported_ty,
169 minimum: imported_minimum,
170 maximum: imported_maximum,
171 } = imported;
172
173 is_table_element_type_compatible(*exported_ty, *imported_ty)
174 && *imported_minimum <= imported_runtime_size.unwrap_or(*exported_minimum)
175 && (imported_maximum.is_none()
176 || (!exported_maximum.is_none()
177 && imported_maximum.unwrap() >= exported_maximum.unwrap()))
178}
179
180fn is_memory_compatible(
181 exported: &MemoryType,
182 imported: &MemoryType,
183 imported_runtime_size: Option<u32>,
184) -> bool {
185 let MemoryType {
186 minimum: exported_minimum,
187 maximum: exported_maximum,
188 shared: exported_shared,
189 } = exported;
190 let MemoryType {
191 minimum: imported_minimum,
192 maximum: imported_maximum,
193 shared: imported_shared,
194 } = imported;
195
196 imported_minimum.0 <= imported_runtime_size.unwrap_or(exported_minimum.0)
197 && (imported_maximum.is_none()
198 || (!exported_maximum.is_none()
199 && imported_maximum.unwrap() >= exported_maximum.unwrap()))
200 && exported_shared == imported_shared
201}
202
203macro_rules! accessors {
204 ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
205 pub fn $get(&self) -> Option<&$ty> {
208 if let Self::$variant(e) = self {
209 Some(e)
210 } else {
211 None
212 }
213 }
214
215 pub fn $unwrap(&self) -> &$ty {
222 self.$get().expect(concat!("expected ", stringify!($ty)))
223 }
224 )*)
225}
226
227impl ExternType {
228 accessors! {
229 (Function(FunctionType) func unwrap_func)
230 (Global(GlobalType) global unwrap_global)
231 (Table(TableType) table unwrap_table)
232 (Memory(MemoryType) memory unwrap_memory)
233 }
234 pub fn is_compatible_with(&self, other: &Self, runtime_size: Option<u32>) -> bool {
236 match (self, other) {
237 (Self::Function(a), Self::Function(b)) => a == b,
238 (Self::Global(a), Self::Global(b)) => is_global_compatible(*a, *b),
239 (Self::Table(a), Self::Table(b)) => is_table_compatible(a, b, runtime_size),
240 (Self::Memory(a), Self::Memory(b)) => is_memory_compatible(a, b, runtime_size),
241 (Self::Tag(a), Self::Tag(b)) => a == b,
242 _ => false,
244 }
245 }
246}
247
248#[derive(Debug, Clone, PartialEq, Eq, Hash)]
255#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
256#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
257#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
258#[rkyv(derive(Debug))]
259pub struct FunctionType {
260 params: Box<[Type]>,
262 results: Box<[Type]>,
264}
265
266impl FunctionType {
267 pub fn new<Params, Returns>(params: Params, returns: Returns) -> Self
269 where
270 Params: Into<Box<[Type]>>,
271 Returns: Into<Box<[Type]>>,
272 {
273 Self {
274 params: params.into(),
275 results: returns.into(),
276 }
277 }
278
279 pub fn params(&self) -> &[Type] {
281 &self.params
282 }
283
284 pub fn results(&self) -> &[Type] {
286 &self.results
287 }
288}
289
290impl fmt::Display for FunctionType {
291 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
292 let params = self
293 .params
294 .iter()
295 .map(|p| format!("{p:?}"))
296 .collect::<Vec<_>>()
297 .join(", ");
298 let results = self
299 .results
300 .iter()
301 .map(|p| format!("{p:?}"))
302 .collect::<Vec<_>>()
303 .join(", ");
304 write!(f, "[{params}] -> [{results}]")
305 }
306}
307
308macro_rules! implement_from_pair_to_functiontype {
311 ($($N:literal,$M:literal)+) => {
312 $(
313 impl From<([Type; $N], [Type; $M])> for FunctionType {
314 fn from(pair: ([Type; $N], [Type; $M])) -> Self {
315 Self::new(pair.0, pair.1)
316 }
317 }
318 )+
319 }
320}
321
322implement_from_pair_to_functiontype! {
323 0,0 0,1 0,2 0,3 0,4 0,5 0,6 0,7 0,8 0,9
324 1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 1,8 1,9
325 2,0 2,1 2,2 2,3 2,4 2,5 2,6 2,7 2,8 2,9
326 3,0 3,1 3,2 3,3 3,4 3,5 3,6 3,7 3,8 3,9
327 4,0 4,1 4,2 4,3 4,4 4,5 4,6 4,7 4,8 4,9
328 5,0 5,1 5,2 5,3 5,4 5,5 5,6 5,7 5,8 5,9
329 6,0 6,1 6,2 6,3 6,4 6,5 6,6 6,7 6,8 6,9
330 7,0 7,1 7,2 7,3 7,4 7,5 7,6 7,7 7,8 7,9
331 8,0 8,1 8,2 8,3 8,4 8,5 8,6 8,7 8,8 8,9
332 9,0 9,1 9,2 9,3 9,4 9,5 9,6 9,7 9,8 9,9
333}
334
335impl From<&Self> for FunctionType {
336 fn from(as_ref: &Self) -> Self {
337 as_ref.clone()
338 }
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
343#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
344#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
345#[rkyv(derive(Debug), compare(PartialOrd, PartialEq))]
346#[repr(u8)]
347pub enum Mutability {
348 Const,
350 Var,
352}
353
354impl Mutability {
355 pub fn is_mutable(self) -> bool {
357 self.into()
358 }
359}
360
361impl From<bool> for Mutability {
362 fn from(value: bool) -> Self {
363 if value { Self::Var } else { Self::Const }
364 }
365}
366
367impl From<Mutability> for bool {
368 fn from(value: Mutability) -> Self {
369 match value {
370 Mutability::Var => true,
371 Mutability::Const => false,
372 }
373 }
374}
375
376#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
378#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
379#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
380#[rkyv(derive(Debug), compare(PartialEq))]
381pub struct GlobalType {
382 pub ty: Type,
384 pub mutability: Mutability,
386}
387
388impl GlobalType {
396 pub fn new(ty: Type, mutability: Mutability) -> Self {
407 Self { ty, mutability }
408 }
409}
410
411impl fmt::Display for GlobalType {
412 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
413 let mutability = match self.mutability {
414 Mutability::Const => "constant",
415 Mutability::Var => "mutable",
416 };
417 write!(f, "{} ({})", self.ty, mutability)
418 }
419}
420
421#[derive(Debug, Clone, Copy, PartialEq, RkyvSerialize, RkyvDeserialize, Archive)]
423#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
424#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
425#[rkyv(derive(Debug), compare(PartialEq))]
426#[repr(u8)]
427pub enum GlobalInit {
428 I32Const(i32),
430 I64Const(i64),
432 F32Const(f32),
434 F64Const(f64),
436 V128Const(V128),
438 GetGlobal(GlobalIndex),
440 RefNullConst,
445 RefFunc(FunctionIndex),
447}
448
449#[derive(Debug, Clone, PartialEq, Eq, Hash)]
455#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
456#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
457#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
458#[rkyv(derive(Debug))]
459pub enum TagKind {
460 Exception,
462}
463
464#[derive(Debug, Clone, PartialEq, Eq, Hash)]
467#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
468#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
469#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
470#[rkyv(derive(Debug))]
471pub struct TagType {
472 pub kind: TagKind,
474 pub params: Box<[Type]>,
476}
477
478impl TagType {
479 pub fn new<Params>(kind: TagKind, params: Params) -> Self
481 where
482 Params: Into<Box<[Type]>>,
483 {
484 Self {
485 kind,
486 params: params.into(),
487 }
488 }
489
490 pub fn params(&self) -> &[Type] {
492 &self.params
493 }
494
495 pub fn from_fn_type(kind: TagKind, ty: FunctionType) -> Self {
497 Self {
498 kind,
499 params: ty.params().into(),
500 }
501 }
502}
503
504impl fmt::Display for TagType {
505 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
506 write!(f, "({:?}) {:?}", self.kind, self.params(),)
507 }
508}
509
510#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
518#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
519#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
520#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
521#[rkyv(derive(Debug))]
522pub struct TableType {
523 pub ty: Type,
525 pub minimum: u32,
527 pub maximum: Option<u32>,
529}
530
531impl TableType {
532 pub fn new(ty: Type, minimum: u32, maximum: Option<u32>) -> Self {
535 Self {
536 ty,
537 minimum,
538 maximum,
539 }
540 }
541}
542
543impl fmt::Display for TableType {
544 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
545 if let Some(maximum) = self.maximum {
546 write!(f, "{} ({}..{})", self.ty, self.minimum, maximum)
547 } else {
548 write!(f, "{} ({}..)", self.ty, self.minimum)
549 }
550 }
551}
552
553#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
560#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
561#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
562#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
563#[rkyv(derive(Debug))]
564pub struct MemoryType {
565 pub minimum: Pages,
567 pub maximum: Option<Pages>,
569 pub shared: bool,
571}
572
573impl MemoryType {
574 pub fn new<IntoPages>(minimum: IntoPages, maximum: Option<IntoPages>, shared: bool) -> Self
577 where
578 IntoPages: Into<Pages>,
579 {
580 Self {
581 minimum: minimum.into(),
582 maximum: maximum.map(Into::into),
583 shared,
584 }
585 }
586}
587
588impl fmt::Display for MemoryType {
589 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
590 let shared = if self.shared { "shared" } else { "not shared" };
591 if let Some(maximum) = self.maximum {
592 write!(f, "{} ({:?}..{:?})", shared, self.minimum, maximum)
593 } else {
594 write!(f, "{} ({:?}..)", shared, self.minimum)
595 }
596 }
597}
598
599#[derive(Debug, Clone, PartialEq, Eq, Hash)]
608#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
609pub struct ImportType<T = ExternType> {
610 module: String,
611 name: String,
612 ty: T,
613}
614
615impl<T> ImportType<T> {
616 pub fn new(module: &str, name: &str, ty: T) -> Self {
619 Self {
620 module: module.to_owned(),
621 name: name.to_owned(),
622 ty,
623 }
624 }
625
626 pub fn module(&self) -> &str {
628 &self.module
629 }
630
631 pub fn name(&self) -> &str {
634 &self.name
635 }
636
637 pub fn ty(&self) -> &T {
639 &self.ty
640 }
641}
642
643#[derive(Debug, Clone, PartialEq, Eq, Hash)]
655#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
656pub struct ExportType<T = ExternType> {
657 name: String,
658 ty: T,
659}
660
661impl<T> ExportType<T> {
662 pub fn new(name: &str, ty: T) -> Self {
665 Self {
666 name: name.to_string(),
667 ty,
668 }
669 }
670
671 pub fn name(&self) -> &str {
673 &self.name
674 }
675
676 pub fn ty(&self) -> &T {
678 &self.ty
679 }
680}
681
682#[cfg(test)]
683mod tests {
684 use super::*;
685
686 const VOID_TO_VOID: ([Type; 0], [Type; 0]) = ([], []);
687 const I32_I32_TO_VOID: ([Type; 2], [Type; 0]) = ([Type::I32, Type::I32], []);
688 const V128_I64_TO_I32: ([Type; 2], [Type; 1]) = ([Type::V128, Type::I64], [Type::I32]);
689 const NINE_V128_TO_NINE_I32: ([Type; 9], [Type; 9]) = ([Type::V128; 9], [Type::I32; 9]);
690
691 #[test]
692 fn convert_tuple_to_functiontype() {
693 let ty: FunctionType = VOID_TO_VOID.into();
694 assert_eq!(ty.params().len(), 0);
695 assert_eq!(ty.results().len(), 0);
696
697 let ty: FunctionType = I32_I32_TO_VOID.into();
698 assert_eq!(ty.params().len(), 2);
699 assert_eq!(ty.params()[0], Type::I32);
700 assert_eq!(ty.params()[1], Type::I32);
701 assert_eq!(ty.results().len(), 0);
702
703 let ty: FunctionType = V128_I64_TO_I32.into();
704 assert_eq!(ty.params().len(), 2);
705 assert_eq!(ty.params()[0], Type::V128);
706 assert_eq!(ty.params()[1], Type::I64);
707 assert_eq!(ty.results().len(), 1);
708 assert_eq!(ty.results()[0], Type::I32);
709
710 let ty: FunctionType = NINE_V128_TO_NINE_I32.into();
711 assert_eq!(ty.params().len(), 9);
712 assert_eq!(ty.results().len(), 9);
713 }
714}