1use core::mem;
17
18use crate::{
19 BinaryReader, BinaryReaderError, ExternalKind, FromReader, GlobalType, MemoryType, Result,
20 SectionLimited, SectionLimitedIntoIterWithOffsets, TableType, TagType,
21};
22
23#[derive(Debug, Clone, Copy, Eq, PartialEq)]
25pub enum TypeRef {
26 Func(u32),
28 Table(TableType),
30 Memory(MemoryType),
32 Global(GlobalType),
34 Tag(TagType),
40 FuncExact(u32),
42}
43
44#[derive(Debug, Clone)]
46pub enum Imports<'a> {
47 Single(usize, Import<'a>),
49 Compact1 {
51 module: &'a str,
53 items: SectionLimited<'a, ImportItemCompact<'a>>,
55 },
56 Compact2 {
58 module: &'a str,
60 ty: TypeRef,
62 names: SectionLimited<'a, &'a str>,
64 },
65}
66
67#[derive(Debug, Copy, Clone, Eq, PartialEq)]
69pub struct Import<'a> {
70 pub module: &'a str,
72 pub name: &'a str,
74 pub ty: TypeRef,
76}
77
78#[derive(Debug, Copy, Clone, Eq, PartialEq)]
80pub struct ImportItemCompact<'a> {
81 pub name: &'a str,
83 pub ty: TypeRef,
85}
86
87pub type ImportSectionReader<'a> = SectionLimited<'a, Imports<'a>>;
89
90impl<'a> FromReader<'a> for Imports<'a> {
91 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
92 let start = reader.original_position();
93 let module = reader.read_string()?;
94 let single_item_name = reader.read_string()?;
95 let discriminator = reader.peek_bytes(1)?[0];
96 match (single_item_name, discriminator) {
97 ("", 0x7F) => {
98 if !reader.compact_imports() {
99 bail!(
100 reader.original_position(),
101 "invalid leading byte 0x7F with compact imports \
102 proposal disabled"
103 );
104 }
105 reader.read_bytes(1)?;
107 let items = reader.skip(|reader| {
109 let count = reader.read_var_u32()?;
110 for _ in 0..count {
111 reader.skip_string()?;
112 reader.read::<TypeRef>()?;
113 }
114 Ok(())
115 })?;
116 Ok(Imports::Compact1 {
117 module,
118 items: SectionLimited::new(items)?,
119 })
120 }
121 ("", 0x7E) => {
122 if !reader.compact_imports() {
123 bail!(
124 reader.original_position(),
125 "invalid leading byte 0x7E with compact imports \
126 proposal disabled"
127 );
128 }
129 reader.read_bytes(1)?;
131 let ty: TypeRef = reader.read()?;
132 let names = reader.skip(|reader| {
134 let count = reader.read_var_u32()?;
135 for _ in 0..count {
136 reader.skip_string()?;
137 }
138 Ok(())
139 })?;
140 Ok(Imports::Compact2 {
141 module,
142 ty,
143 names: SectionLimited::new(names)?,
144 })
145 }
146 _ => Ok(Imports::Single(
147 start,
148 Import {
149 module: module,
150 name: single_item_name,
151 ty: reader.read()?,
152 },
153 )),
154 }
155 }
156}
157
158impl<'a> FromReader<'a> for Import<'a> {
159 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
160 Ok(Import {
161 module: reader.read()?,
162 name: reader.read()?,
163 ty: reader.read()?,
164 })
165 }
166}
167
168impl<'a> FromReader<'a> for ImportItemCompact<'a> {
169 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
170 Ok(ImportItemCompact {
171 name: reader.read()?,
172 ty: reader.read()?,
173 })
174 }
175}
176
177impl<'a> FromReader<'a> for TypeRef {
178 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
179 Ok(match reader.read()? {
180 ExternalKind::Func => TypeRef::Func(reader.read_var_u32()?),
181 ExternalKind::FuncExact => TypeRef::FuncExact(reader.read_var_u32()?),
182 ExternalKind::Table => TypeRef::Table(reader.read()?),
183 ExternalKind::Memory => TypeRef::Memory(reader.read()?),
184 ExternalKind::Global => TypeRef::Global(reader.read()?),
185 ExternalKind::Tag => TypeRef::Tag(reader.read()?),
186 })
187 }
188}
189
190impl<'a> SectionLimited<'a, Imports<'a>> {
194 pub fn into_imports(self) -> impl Iterator<Item = Result<Import<'a>>> {
197 self.into_imports_with_offsets()
198 .map(|res| res.map(|(_, import)| import))
199 }
200
201 pub fn into_imports_with_offsets(self) -> impl Iterator<Item = Result<(usize, Import<'a>)>> {
204 self.into_iter().flat_map(|res| match res {
205 Ok(imports) => imports.into_iter(),
206 Err(e) => ImportsIter {
207 state: ImportsIterState::Error(e),
208 },
209 })
210 }
211}
212
213impl<'a> IntoIterator for Imports<'a> {
214 type Item = Result<(usize, Import<'a>)>;
215 type IntoIter = ImportsIter<'a>;
216
217 fn into_iter(self) -> Self::IntoIter {
218 ImportsIter {
219 state: match self {
220 Imports::Single(start, import) => ImportsIterState::Single(start, import),
221 Imports::Compact1 { module, items } => ImportsIterState::Compact1 {
222 module: module,
223 iter: items.into_iter_with_offsets(),
224 },
225 Imports::Compact2 {
226 module,
227 ty,
228 names: items,
229 } => ImportsIterState::Compact2 {
230 module: module,
231 ty: ty,
232 iter: items.into_iter_with_offsets(),
233 },
234 },
235 }
236 }
237}
238
239pub struct ImportsIter<'a> {
241 state: ImportsIterState<'a>,
242}
243
244enum ImportsIterState<'a> {
245 Done,
246 Error(BinaryReaderError),
247 Single(usize, Import<'a>),
248 Compact1 {
249 module: &'a str,
250 iter: SectionLimitedIntoIterWithOffsets<'a, ImportItemCompact<'a>>,
251 },
252 Compact2 {
253 module: &'a str,
254 ty: TypeRef,
255 iter: SectionLimitedIntoIterWithOffsets<'a, &'a str>,
256 },
257}
258
259impl<'a> Iterator for ImportsIter<'a> {
260 type Item = Result<(usize, Import<'a>)>;
261
262 fn next(&mut self) -> Option<Self::Item> {
263 match &mut self.state {
264 ImportsIterState::Done => None,
265 ImportsIterState::Error(_) => {
266 let ImportsIterState::Error(e) =
267 mem::replace(&mut self.state, ImportsIterState::Done)
268 else {
269 unreachable!()
270 };
271 Some(Err(e))
272 }
273
274 ImportsIterState::Single(offset, i) => {
275 let ret = Some(Ok((*offset, *i)));
276 self.state = ImportsIterState::Done;
277 ret
278 }
279 ImportsIterState::Compact1 { module, iter } => {
280 let item = iter.next()?;
281 Some(item.map(|(offset, item)| {
282 (
283 offset,
284 Import {
285 module,
286 name: item.name,
287 ty: item.ty,
288 },
289 )
290 }))
291 }
292 ImportsIterState::Compact2 { module, ty, iter } => {
293 let item = iter.next()?;
294 Some(item.map(|(offset, name)| {
295 (
296 offset,
297 Import {
298 module,
299 name,
300 ty: *ty,
301 },
302 )
303 }))
304 }
305 }
306 }
307}