wasmer_types/
types.rs

1use crate::indexes::{FunctionIndex, GlobalIndex};
2use crate::lib::std::borrow::ToOwned;
3use crate::lib::std::boxed::Box;
4use crate::lib::std::fmt;
5use crate::lib::std::format;
6use crate::lib::std::string::{String, ToString};
7use crate::lib::std::vec::Vec;
8use crate::units::Pages;
9
10use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
11#[cfg(feature = "enable-serde")]
12use serde::{Deserialize, Serialize};
13
14// Type Representations
15
16// Value Types
17
18/// A list of all possible value types in WebAssembly.
19#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash)]
20#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
21#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
22#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
23#[rkyv(derive(Debug), compare(PartialEq))]
24#[repr(u8)]
25pub enum Type {
26    /// Signed 32 bit integer.
27    I32,
28    /// Signed 64 bit integer.
29    I64,
30    /// Floating point 32 bit integer.
31    F32,
32    /// Floating point 64 bit integer.
33    F64,
34    /// A 128 bit number.
35    V128,
36    /// A reference to opaque data in the Wasm instance.
37    ExternRef, /* = 128 */
38    /// A reference to a Wasm function.
39    FuncRef,
40    /// A reference to a Wasm exception.
41    ExceptionRef,
42}
43
44impl Type {
45    /// Returns true if `Type` matches any of the numeric types. (e.g. `I32`,
46    /// `I64`, `F32`, `F64`, `V128`).
47    pub fn is_num(self) -> bool {
48        matches!(
49            self,
50            Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128
51        )
52    }
53
54    /// Returns true if `Type` matches either of the reference types.
55    pub fn is_ref(self) -> bool {
56        matches!(self, Self::ExternRef | Self::FuncRef | Self::ExceptionRef)
57    }
58}
59
60impl fmt::Display for Type {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        write!(f, "{self:?}")
63    }
64}
65
66/// The WebAssembly V128 type
67#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
68#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
69#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
70#[rkyv(derive(Debug), compare(PartialEq))]
71pub struct V128(pub(crate) [u8; 16]);
72
73#[cfg(feature = "artifact-size")]
74impl loupe::MemoryUsage for V128 {
75    fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
76        16 * 8
77    }
78}
79
80impl V128 {
81    /// Get the bytes corresponding to the V128 value
82    pub fn bytes(&self) -> &[u8; 16] {
83        &self.0
84    }
85    /// Iterate over the bytes in the constant.
86    pub fn iter(&self) -> impl Iterator<Item = &u8> {
87        self.0.iter()
88    }
89
90    /// Convert the immediate into a vector.
91    pub fn to_vec(self) -> Vec<u8> {
92        self.0.to_vec()
93    }
94
95    /// Convert the immediate into a slice.
96    pub fn as_slice(&self) -> &[u8] {
97        &self.0[..]
98    }
99}
100
101impl From<[u8; 16]> for V128 {
102    fn from(array: [u8; 16]) -> Self {
103        Self(array)
104    }
105}
106
107impl From<&[u8]> for V128 {
108    fn from(slice: &[u8]) -> Self {
109        assert_eq!(slice.len(), 16);
110        let mut buffer = [0; 16];
111        buffer.copy_from_slice(slice);
112        Self(buffer)
113    }
114}
115
116// External Types
117
118/// A list of all possible types which can be externally referenced from a
119/// WebAssembly module.
120///
121/// This list can be found in [`ImportType`] or [`ExportType`], so these types
122/// can either be imported or exported.
123#[derive(Debug, Clone, PartialEq, Eq, Hash)]
124#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
125pub enum ExternType {
126    /// This external type is the type of a WebAssembly function.
127    Function(FunctionType),
128    /// This external type is the type of a WebAssembly global.
129    Global(GlobalType),
130    /// This external type is the type of a WebAssembly table.
131    Table(TableType),
132    /// This external type is the type of a WebAssembly memory.
133    Memory(MemoryType),
134    /// This external type is the type of a WebAssembly tag.
135    Tag(TagType),
136}
137
138fn is_global_compatible(exported: GlobalType, imported: GlobalType) -> bool {
139    let GlobalType {
140        ty: exported_ty,
141        mutability: exported_mutability,
142    } = exported;
143    let GlobalType {
144        ty: imported_ty,
145        mutability: imported_mutability,
146    } = imported;
147
148    exported_ty == imported_ty && imported_mutability == exported_mutability
149}
150
151fn is_table_element_type_compatible(exported_type: Type, imported_type: Type) -> bool {
152    match exported_type {
153        Type::FuncRef => true,
154        _ => imported_type == exported_type,
155    }
156}
157
158fn is_table_compatible(
159    exported: &TableType,
160    imported: &TableType,
161    imported_runtime_size: Option<u32>,
162) -> bool {
163    let TableType {
164        ty: exported_ty,
165        minimum: exported_minimum,
166        maximum: exported_maximum,
167    } = exported;
168    let TableType {
169        ty: imported_ty,
170        minimum: imported_minimum,
171        maximum: imported_maximum,
172    } = imported;
173
174    is_table_element_type_compatible(*exported_ty, *imported_ty)
175        && *imported_minimum <= imported_runtime_size.unwrap_or(*exported_minimum)
176        && (imported_maximum.is_none()
177            || (!exported_maximum.is_none()
178                && imported_maximum.unwrap() >= exported_maximum.unwrap()))
179}
180
181fn is_memory_compatible(
182    exported: &MemoryType,
183    imported: &MemoryType,
184    imported_runtime_size: Option<u32>,
185) -> bool {
186    let MemoryType {
187        minimum: exported_minimum,
188        maximum: exported_maximum,
189        shared: exported_shared,
190    } = exported;
191    let MemoryType {
192        minimum: imported_minimum,
193        maximum: imported_maximum,
194        shared: imported_shared,
195    } = imported;
196
197    imported_minimum.0 <= imported_runtime_size.unwrap_or(exported_minimum.0)
198        && (imported_maximum.is_none()
199            || (!exported_maximum.is_none()
200                && imported_maximum.unwrap() >= exported_maximum.unwrap()))
201        && exported_shared == imported_shared
202}
203
204macro_rules! accessors {
205    ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
206        /// Attempt to return the underlying type of this external type,
207        /// returning `None` if it is a different type.
208        pub fn $get(&self) -> Option<&$ty> {
209            if let Self::$variant(e) = self {
210                Some(e)
211            } else {
212                None
213            }
214        }
215
216        /// Returns the underlying descriptor of this [`ExternType`], panicking
217        /// if it is a different type.
218        ///
219        /// # Panics
220        ///
221        /// Panics if `self` is not of the right type.
222        pub fn $unwrap(&self) -> &$ty {
223            self.$get().expect(concat!("expected ", stringify!($ty)))
224        }
225    )*)
226}
227
228impl ExternType {
229    accessors! {
230        (Function(FunctionType) func unwrap_func)
231        (Global(GlobalType) global unwrap_global)
232        (Table(TableType) table unwrap_table)
233        (Memory(MemoryType) memory unwrap_memory)
234    }
235    /// Check if two externs are compatible
236    pub fn is_compatible_with(&self, other: &Self, runtime_size: Option<u32>) -> bool {
237        match (self, other) {
238            (Self::Function(a), Self::Function(b)) => a == b,
239            (Self::Global(a), Self::Global(b)) => is_global_compatible(*a, *b),
240            (Self::Table(a), Self::Table(b)) => is_table_compatible(a, b, runtime_size),
241            (Self::Memory(a), Self::Memory(b)) => is_memory_compatible(a, b, runtime_size),
242            (Self::Tag(a), Self::Tag(b)) => a == b,
243            // The rest of possibilities, are not compatible
244            _ => false,
245        }
246    }
247}
248
249// TODO: `shrink_to_fit` these or change it to `Box<[Type]>` if not using
250// Cow or something else
251/// The signature of a function that is either implemented
252/// in a Wasm module or exposed to Wasm by the host.
253///
254/// WebAssembly functions can have 0 or more parameters and results.
255#[derive(Debug, Clone, PartialEq, Eq, Hash)]
256#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
257#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
258#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
259#[rkyv(derive(Debug))]
260pub struct FunctionType {
261    /// The parameters of the function
262    params: Box<[Type]>,
263    /// The return values of the function
264    results: Box<[Type]>,
265}
266
267impl FunctionType {
268    /// Creates a new Function Type with the given parameter and return types.
269    pub fn new<Params, Returns>(params: Params, returns: Returns) -> Self
270    where
271        Params: Into<Box<[Type]>>,
272        Returns: Into<Box<[Type]>>,
273    {
274        Self {
275            params: params.into(),
276            results: returns.into(),
277        }
278    }
279
280    /// Parameter types.
281    pub fn params(&self) -> &[Type] {
282        &self.params
283    }
284
285    /// Return types.
286    pub fn results(&self) -> &[Type] {
287        &self.results
288    }
289}
290
291impl fmt::Display for FunctionType {
292    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
293        let params = self
294            .params
295            .iter()
296            .map(|p| format!("{p:?}"))
297            .collect::<Vec<_>>()
298            .join(", ");
299        let results = self
300            .results
301            .iter()
302            .map(|p| format!("{p:?}"))
303            .collect::<Vec<_>>()
304            .join(", ");
305        write!(f, "[{params}] -> [{results}]")
306    }
307}
308
309// Macro needed until https://rust-lang.github.io/rfcs/2000-const-generics.html is stable.
310// See https://users.rust-lang.org/t/how-to-implement-trait-for-fixed-size-array-of-any-size/31494
311macro_rules! implement_from_pair_to_functiontype {
312    ($($N:literal,$M:literal)+) => {
313        $(
314            impl From<([Type; $N], [Type; $M])> for FunctionType {
315                fn from(pair: ([Type; $N], [Type; $M])) -> Self {
316                    Self::new(pair.0, pair.1)
317                }
318            }
319        )+
320    }
321}
322
323implement_from_pair_to_functiontype! {
324    0,0 0,1 0,2 0,3 0,4 0,5 0,6 0,7 0,8 0,9
325    1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 1,8 1,9
326    2,0 2,1 2,2 2,3 2,4 2,5 2,6 2,7 2,8 2,9
327    3,0 3,1 3,2 3,3 3,4 3,5 3,6 3,7 3,8 3,9
328    4,0 4,1 4,2 4,3 4,4 4,5 4,6 4,7 4,8 4,9
329    5,0 5,1 5,2 5,3 5,4 5,5 5,6 5,7 5,8 5,9
330    6,0 6,1 6,2 6,3 6,4 6,5 6,6 6,7 6,8 6,9
331    7,0 7,1 7,2 7,3 7,4 7,5 7,6 7,7 7,8 7,9
332    8,0 8,1 8,2 8,3 8,4 8,5 8,6 8,7 8,8 8,9
333    9,0 9,1 9,2 9,3 9,4 9,5 9,6 9,7 9,8 9,9
334}
335
336impl From<&Self> for FunctionType {
337    fn from(as_ref: &Self) -> Self {
338        as_ref.clone()
339    }
340}
341
342/// Indicator of whether a global is mutable or not
343#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
344#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
345#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
346#[rkyv(derive(Debug), compare(PartialOrd, PartialEq))]
347#[repr(u8)]
348pub enum Mutability {
349    /// The global is constant and its value does not change
350    Const,
351    /// The value of the global can change over time
352    Var,
353}
354
355impl Mutability {
356    /// Returns a boolean indicating if the enum is set to mutable.
357    pub fn is_mutable(self) -> bool {
358        self.into()
359    }
360}
361
362impl From<bool> for Mutability {
363    fn from(value: bool) -> Self {
364        if value { Self::Var } else { Self::Const }
365    }
366}
367
368impl From<Mutability> for bool {
369    fn from(value: Mutability) -> Self {
370        match value {
371            Mutability::Var => true,
372            Mutability::Const => false,
373        }
374    }
375}
376
377/// WebAssembly global.
378#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
379#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
380#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
381#[rkyv(derive(Debug), compare(PartialEq))]
382pub struct GlobalType {
383    /// The type of the value stored in the global.
384    pub ty: Type,
385    /// A flag indicating whether the value may change at runtime.
386    pub mutability: Mutability,
387}
388
389// Global Types
390
391/// A WebAssembly global descriptor.
392///
393/// This type describes an instance of a global in a WebAssembly
394/// module. Globals are local to an `Instance` and are either
395/// immutable or mutable.
396impl GlobalType {
397    /// Create a new Global variable
398    /// # Usage:
399    /// ```
400    /// use wasmer_types::{GlobalType, Type, Mutability};
401    ///
402    /// // An I32 constant global
403    /// let global = GlobalType::new(Type::I32, Mutability::Const);
404    /// // An I64 mutable global
405    /// let global = GlobalType::new(Type::I64, Mutability::Var);
406    /// ```
407    pub fn new(ty: Type, mutability: Mutability) -> Self {
408        Self { ty, mutability }
409    }
410}
411
412impl fmt::Display for GlobalType {
413    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
414        let mutability = match self.mutability {
415            Mutability::Const => "constant",
416            Mutability::Var => "mutable",
417        };
418        write!(f, "{} ({})", self.ty, mutability)
419    }
420}
421
422/// A serializable sequence of operators for init expressions in globals,
423/// element offsets and data offsets.
424#[derive(Debug, Clone, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
425#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
426#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
427#[rkyv(derive(Debug), compare(PartialEq))]
428pub struct InitExpr {
429    /// Operators in stack-machine order, excluding the terminating `end`.
430    pub ops: Box<[InitExprOp]>,
431}
432
433impl InitExpr {
434    /// Creates a new init expression.
435    pub fn new<Ops>(ops: Ops) -> Self
436    where
437        Ops: Into<Box<[InitExprOp]>>,
438    {
439        Self { ops: ops.into() }
440    }
441
442    /// Returns the operators that form this expression.
443    pub fn ops(&self) -> &[InitExprOp] {
444        &self.ops
445    }
446}
447
448/// Supported operators in serialized init expressions.
449#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
450#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
451#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
452#[rkyv(derive(Debug), compare(PartialEq))]
453#[repr(u8)]
454pub enum InitExprOp {
455    /// A `global.get` of an `i32` global.
456    GlobalGetI32(GlobalIndex),
457    /// A `global.get` of an `i64` global.
458    GlobalGetI64(GlobalIndex),
459    /// An `i32.const`.
460    I32Const(i32),
461    /// An `i32.add`.
462    I32Add,
463    /// An `i32.sub`.
464    I32Sub,
465    /// An `i32.mul`.
466    I32Mul,
467    /// An `i64.const`.
468    I64Const(i64),
469    /// An `i64.add`.
470    I64Add,
471    /// An `i64.sub`.
472    I64Sub,
473    /// An `i64.mul`.
474    I64Mul,
475}
476
477impl InitExprOp {
478    /// Return true if the expression is 32-bit
479    pub fn is_32bit_expression(&self) -> bool {
480        match self {
481            Self::GlobalGetI32(..)
482            | Self::I32Const(_)
483            | Self::I32Add
484            | Self::I32Sub
485            | Self::I32Mul => true,
486            Self::GlobalGetI64(_)
487            | Self::I64Const(_)
488            | Self::I64Add
489            | Self::I64Sub
490            | Self::I64Mul => false,
491        }
492    }
493}
494
495/// Globals are initialized via `const` operators, references, or a serialized
496/// expression.
497#[derive(Debug, Clone, PartialEq, RkyvSerialize, RkyvDeserialize, Archive)]
498#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
499#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
500#[rkyv(derive(Debug), compare(PartialEq))]
501#[repr(u8)]
502pub enum GlobalInit {
503    /// An `i32.const`.
504    I32Const(i32),
505    /// An `i64.const`.
506    I64Const(i64),
507    /// An `f32.const`.
508    F32Const(f32),
509    /// An `f64.const`.
510    F64Const(f64),
511    /// A `v128.const`.
512    V128Const(V128),
513    /// A `global.get` of another global.
514    GetGlobal(GlobalIndex),
515    // TODO(reftypes): `ref.null func` and `ref.null extern` seem to be 2 different
516    // things: we need to handle both. Perhaps this handled in context by the
517    // global knowing its own type?
518    /// A `ref.null`.
519    RefNullConst,
520    /// A `ref.func <index>`.
521    RefFunc(FunctionIndex),
522    /// A serialized init expression.
523    Expr(InitExpr),
524}
525
526// Tag Types
527
528/// The kind of a tag.
529///
530/// Currently, tags can only express exceptions.
531#[derive(Debug, Clone, PartialEq, Eq, Hash)]
532#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
533#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
534#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
535#[rkyv(derive(Debug))]
536pub enum TagKind {
537    /// This tag's event is an exception.
538    Exception,
539}
540
541/// The signature of a tag that is either implemented
542/// in a Wasm module or exposed to Wasm by the host.
543#[derive(Debug, Clone, PartialEq, Eq, Hash)]
544#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
545#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
546#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
547#[rkyv(derive(Debug))]
548pub struct TagType {
549    /// The kind of the tag.
550    pub kind: TagKind,
551    /// The parameters of the tag
552    pub params: Box<[Type]>,
553}
554
555impl TagType {
556    /// Creates a new [`TagType`] with the given kind, parameter and return types.
557    pub fn new<Params>(kind: TagKind, params: Params) -> Self
558    where
559        Params: Into<Box<[Type]>>,
560    {
561        Self {
562            kind,
563            params: params.into(),
564        }
565    }
566
567    /// Parameter types.
568    pub fn params(&self) -> &[Type] {
569        &self.params
570    }
571
572    /// Create a new [`TagType`] with the given kind and the associated type.
573    pub fn from_fn_type(kind: TagKind, ty: FunctionType) -> Self {
574        Self {
575            kind,
576            params: ty.params().into(),
577        }
578    }
579}
580
581impl fmt::Display for TagType {
582    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
583        write!(f, "({:?}) {:?}", self.kind, self.params(),)
584    }
585}
586
587// Table Types
588
589/// A descriptor for a table in a WebAssembly module.
590///
591/// Tables are contiguous chunks of a specific element, typically a `funcref` or
592/// an `externref`. The most common use for tables is a function table through
593/// which `call_indirect` can invoke other functions.
594#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
595#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
596#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
597#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
598#[rkyv(derive(Debug))]
599pub struct TableType {
600    /// The type of data stored in elements of the table.
601    pub ty: Type,
602    /// The minimum number of elements in the table.
603    pub minimum: u32,
604    /// The maximum number of elements in the table.
605    pub maximum: Option<u32>,
606}
607
608impl TableType {
609    /// Creates a new table descriptor which will contain the specified
610    /// `element` and have the `limits` applied to its length.
611    pub fn new(ty: Type, minimum: u32, maximum: Option<u32>) -> Self {
612        Self {
613            ty,
614            minimum,
615            maximum,
616        }
617    }
618}
619
620impl fmt::Display for TableType {
621    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
622        if let Some(maximum) = self.maximum {
623            write!(f, "{} ({}..{})", self.ty, self.minimum, maximum)
624        } else {
625            write!(f, "{} ({}..)", self.ty, self.minimum)
626        }
627    }
628}
629
630// Memory Types
631
632/// A descriptor for a WebAssembly memory type.
633///
634/// Memories are described in units of pages (64KB) and represent contiguous
635/// chunks of addressable memory.
636#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
637#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
638#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
639#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
640#[rkyv(derive(Debug))]
641pub struct MemoryType {
642    /// The minimum number of pages in the memory.
643    pub minimum: Pages,
644    /// The maximum number of pages in the memory.
645    pub maximum: Option<Pages>,
646    /// Whether the memory may be shared between multiple threads.
647    pub shared: bool,
648}
649
650impl MemoryType {
651    /// Creates a new descriptor for a WebAssembly memory given the specified
652    /// limits of the memory.
653    pub fn new<IntoPages>(minimum: IntoPages, maximum: Option<IntoPages>, shared: bool) -> Self
654    where
655        IntoPages: Into<Pages>,
656    {
657        Self {
658            minimum: minimum.into(),
659            maximum: maximum.map(Into::into),
660            shared,
661        }
662    }
663}
664
665impl fmt::Display for MemoryType {
666    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
667        let shared = if self.shared { "shared" } else { "not shared" };
668        if let Some(maximum) = self.maximum {
669            write!(f, "{} ({:?}..{:?})", shared, self.minimum, maximum)
670        } else {
671            write!(f, "{} ({:?}..)", shared, self.minimum)
672        }
673    }
674}
675
676// Import Types
677
678/// A descriptor for an imported value into a wasm module.
679///
680/// This type is primarily accessed from the `Module::imports`
681/// API. Each `ImportType` describes an import into the wasm module
682/// with the module/name that it's imported from as well as the type
683/// of item that's being imported.
684#[derive(Debug, Clone, PartialEq, Eq, Hash)]
685#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
686pub struct ImportType<T = ExternType> {
687    module: String,
688    name: String,
689    ty: T,
690}
691
692impl<T> ImportType<T> {
693    /// Creates a new import descriptor which comes from `module` and `name` and
694    /// is of type `ty`.
695    pub fn new(module: &str, name: &str, ty: T) -> Self {
696        Self {
697            module: module.to_owned(),
698            name: name.to_owned(),
699            ty,
700        }
701    }
702
703    /// Returns the module name that this import is expected to come from.
704    pub fn module(&self) -> &str {
705        &self.module
706    }
707
708    /// Returns the field name of the module that this import is expected to
709    /// come from.
710    pub fn name(&self) -> &str {
711        &self.name
712    }
713
714    /// Returns the expected type of this import.
715    pub fn ty(&self) -> &T {
716        &self.ty
717    }
718}
719
720// Export Types
721
722/// A descriptor for an exported WebAssembly value.
723///
724/// This type is primarily accessed from the `Module::exports`
725/// accessor and describes what names are exported from a wasm module
726/// and the type of the item that is exported.
727///
728/// The `<T>` refefers to `ExternType`, however it can also refer to use
729/// `MemoryType`, `TableType`, `FunctionType` and `GlobalType` for ease of
730/// use.
731#[derive(Debug, Clone, PartialEq, Eq, Hash)]
732#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
733pub struct ExportType<T = ExternType> {
734    name: String,
735    ty: T,
736}
737
738impl<T> ExportType<T> {
739    /// Creates a new export which is exported with the given `name` and has the
740    /// given `ty`.
741    pub fn new(name: &str, ty: T) -> Self {
742        Self {
743            name: name.to_string(),
744            ty,
745        }
746    }
747
748    /// Returns the name by which this export is known by.
749    pub fn name(&self) -> &str {
750        &self.name
751    }
752
753    /// Returns the type of this export.
754    pub fn ty(&self) -> &T {
755        &self.ty
756    }
757}
758
759#[cfg(test)]
760mod tests {
761    use super::*;
762
763    const VOID_TO_VOID: ([Type; 0], [Type; 0]) = ([], []);
764    const I32_I32_TO_VOID: ([Type; 2], [Type; 0]) = ([Type::I32, Type::I32], []);
765    const V128_I64_TO_I32: ([Type; 2], [Type; 1]) = ([Type::V128, Type::I64], [Type::I32]);
766    const NINE_V128_TO_NINE_I32: ([Type; 9], [Type; 9]) = ([Type::V128; 9], [Type::I32; 9]);
767
768    #[test]
769    fn convert_tuple_to_functiontype() {
770        let ty: FunctionType = VOID_TO_VOID.into();
771        assert_eq!(ty.params().len(), 0);
772        assert_eq!(ty.results().len(), 0);
773
774        let ty: FunctionType = I32_I32_TO_VOID.into();
775        assert_eq!(ty.params().len(), 2);
776        assert_eq!(ty.params()[0], Type::I32);
777        assert_eq!(ty.params()[1], Type::I32);
778        assert_eq!(ty.results().len(), 0);
779
780        let ty: FunctionType = V128_I64_TO_I32.into();
781        assert_eq!(ty.params().len(), 2);
782        assert_eq!(ty.params()[0], Type::V128);
783        assert_eq!(ty.params()[1], Type::I64);
784        assert_eq!(ty.results().len(), 1);
785        assert_eq!(ty.results()[0], Type::I32);
786
787        let ty: FunctionType = NINE_V128_TO_NINE_I32.into();
788        assert_eq!(ty.params().len(), 9);
789        assert_eq!(ty.results().len(), 9);
790    }
791}