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