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