1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use super::GlobalIdx;
use crate::{collections::map::Iter as MapIter, Error, ExternType, Module};
use std::boxed::Box;

/// The index of a function declaration within a [`Module`].
///
/// [`Module`]: [`super::Module`]
#[derive(Debug, Copy, Clone)]
pub struct FuncIdx(u32);

impl From<u32> for FuncIdx {
    fn from(index: u32) -> Self {
        Self(index)
    }
}

impl FuncIdx {
    /// Returns the [`FuncIdx`] as `u32`.
    pub fn into_u32(self) -> u32 {
        self.0
    }
}

/// The index of a table declaration within a [`Module`].
///
/// [`Module`]: [`super::Module`]
#[derive(Debug, Copy, Clone)]
pub struct TableIdx(u32);

impl From<u32> for TableIdx {
    fn from(index: u32) -> Self {
        Self(index)
    }
}

impl TableIdx {
    /// Returns the [`TableIdx`] as `u32`.
    pub fn into_u32(self) -> u32 {
        self.0
    }
}

/// The index of a linear memory declaration within a [`Module`].
///
/// [`Module`]: [`super::Module`]
#[derive(Debug, Copy, Clone)]
pub struct MemoryIdx(u32);

impl From<u32> for MemoryIdx {
    fn from(index: u32) -> Self {
        Self(index)
    }
}

impl MemoryIdx {
    /// Returns the [`MemoryIdx`] as `u32`.
    pub fn into_u32(self) -> u32 {
        self.0
    }
}

/// An external item of an [`ExportType`] definition within a [`Module`].
///
/// [`Module`]: [`crate::Module`]
#[derive(Debug, Copy, Clone)]
pub enum ExternIdx {
    /// An exported function and its index within the [`Module`].
    ///
    /// [`Module`]: [`super::Module`]
    Func(FuncIdx),
    /// An exported table and its index within the [`Module`].
    ///
    /// [`Module`]: [`super::Module`]
    Table(TableIdx),
    /// An exported linear memory and its index within the [`Module`].
    ///
    /// [`Module`]: [`super::Module`]
    Memory(MemoryIdx),
    /// An exported global variable and its index within the [`Module`].
    ///
    /// [`Module`]: [`super::Module`]
    Global(GlobalIdx),
}

impl ExternIdx {
    /// Create a new [`ExternIdx`] from the given [`wasmparser::ExternalKind`] and `index`.
    ///
    /// # Errors
    ///
    /// If an unsupported external definition is encountered.
    pub fn new(kind: wasmparser::ExternalKind, index: u32) -> Result<Self, Error> {
        match kind {
            wasmparser::ExternalKind::Func => Ok(ExternIdx::Func(FuncIdx(index))),
            wasmparser::ExternalKind::Table => Ok(ExternIdx::Table(TableIdx(index))),
            wasmparser::ExternalKind::Memory => Ok(ExternIdx::Memory(MemoryIdx(index))),
            wasmparser::ExternalKind::Global => Ok(ExternIdx::Global(GlobalIdx::from(index))),
            wasmparser::ExternalKind::Tag => {
                panic!("wasmi does not support the `exception-handling` Wasm proposal")
            }
        }
    }
}

/// An iterator over the exports of a [`Module`].
///
/// [`Module`]: [`super::Module`]
#[derive(Debug)]
pub struct ModuleExportsIter<'module> {
    exports: MapIter<'module, Box<str>, ExternIdx>,
    module: &'module Module,
}

/// A descriptor for an exported WebAssembly value of a [`Module`].
///
/// This type is primarily accessed from the [`Module::exports`] method and describes
/// what names are exported from a Wasm [`Module`] and the type of the item that is exported.
#[derive(Debug)]
pub struct ExportType<'module> {
    name: &'module str,
    ty: ExternType,
}

impl<'module> ExportType<'module> {
    /// Returns the name by which the export is known.
    pub fn name(&self) -> &'module str {
        self.name
    }

    /// Returns the type of the exported item.
    pub fn ty(&self) -> &ExternType {
        &self.ty
    }
}

impl<'module> ModuleExportsIter<'module> {
    /// Creates a new [`ModuleExportsIter`] from the given [`Module`].
    pub(super) fn new(module: &'module Module) -> Self {
        Self {
            exports: module.header.inner.exports.iter(),
            module,
        }
    }
}

impl<'module> Iterator for ModuleExportsIter<'module> {
    type Item = ExportType<'module>;

    fn next(&mut self) -> Option<Self::Item> {
        self.exports.next().map(|(name, idx)| {
            let ty = self.module.get_extern_type(*idx);
            ExportType { name, ty }
        })
    }
}