wasmparser_nostd/readers/component/
types.rs

1use crate::limits::*;
2use crate::{
3    BinaryReader, ComponentAlias, ComponentImport, ComponentTypeRef, FromReader, FuncType, Import,
4    Result, SectionLimited, Type, TypeRef,
5};
6use ::alloc::boxed::Box;
7
8/// Represents the kind of an outer core alias in a WebAssembly component.
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum OuterAliasKind {
11    /// The alias is to a core type.
12    Type,
13}
14
15/// Represents a core type in a WebAssembly component.
16#[derive(Debug, Clone)]
17pub enum CoreType<'a> {
18    /// The type is for a core function.
19    Func(FuncType),
20    /// The type is for a core module.
21    Module(Box<[ModuleTypeDeclaration<'a>]>),
22}
23
24impl<'a> FromReader<'a> for CoreType<'a> {
25    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
26        Ok(match reader.read_u8()? {
27            0x60 => CoreType::Func(reader.read()?),
28            0x50 => CoreType::Module(
29                reader
30                    .read_iter(MAX_WASM_MODULE_TYPE_DECLS, "module type declaration")?
31                    .collect::<Result<_>>()?,
32            ),
33            x => return reader.invalid_leading_byte(x, "core type"),
34        })
35    }
36}
37
38/// Represents a module type declaration in a WebAssembly component.
39#[derive(Debug, Clone)]
40pub enum ModuleTypeDeclaration<'a> {
41    /// The module type definition is for a type.
42    Type(Type),
43    /// The module type definition is for an export.
44    Export {
45        /// The name of the exported item.
46        name: &'a str,
47        /// The type reference of the export.
48        ty: TypeRef,
49    },
50    /// The module type declaration is for an outer alias.
51    OuterAlias {
52        /// The alias kind.
53        kind: OuterAliasKind,
54        /// The outward count, starting at zero for the current type.
55        count: u32,
56        /// The index of the item within the outer type.
57        index: u32,
58    },
59    /// The module type definition is for an import.
60    Import(Import<'a>),
61}
62
63impl<'a> FromReader<'a> for ModuleTypeDeclaration<'a> {
64    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
65        Ok(match reader.read_u8()? {
66            0x00 => ModuleTypeDeclaration::Import(reader.read()?),
67            0x01 => ModuleTypeDeclaration::Type(reader.read()?),
68            0x02 => {
69                let kind = match reader.read_u8()? {
70                    0x10 => OuterAliasKind::Type,
71                    x => {
72                        return reader.invalid_leading_byte(x, "outer alias kind");
73                    }
74                };
75                match reader.read_u8()? {
76                    0x01 => ModuleTypeDeclaration::OuterAlias {
77                        kind,
78                        count: reader.read()?,
79                        index: reader.read()?,
80                    },
81                    x => {
82                        return reader.invalid_leading_byte(x, "outer alias target");
83                    }
84                }
85            }
86            0x03 => ModuleTypeDeclaration::Export {
87                name: reader.read()?,
88                ty: reader.read()?,
89            },
90            x => return reader.invalid_leading_byte(x, "type definition"),
91        })
92    }
93}
94
95/// A reader for the core type section of a WebAssembly component.
96///
97/// # Examples
98/// ```
99/// use wasmparser_nostd::CoreTypeSectionReader;
100/// # let data: &[u8] = &[0x01, 0x60, 0x00, 0x00];
101/// let mut reader = CoreTypeSectionReader::new(data, 0).unwrap();
102/// for ty in reader {
103///     println!("Type {:?}", ty.expect("type"));
104/// }
105/// ```
106pub type CoreTypeSectionReader<'a> = SectionLimited<'a, CoreType<'a>>;
107
108/// Represents a value type in a WebAssembly component.
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110pub enum ComponentValType {
111    /// The value type is a primitive type.
112    Primitive(PrimitiveValType),
113    /// The value type is a reference to a defined type.
114    Type(u32),
115}
116
117impl<'a> FromReader<'a> for ComponentValType {
118    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
119        if let Some(ty) = PrimitiveValType::from_byte(reader.peek()?) {
120            reader.position += 1;
121            return Ok(ComponentValType::Primitive(ty));
122        }
123
124        Ok(ComponentValType::Type(reader.read_var_s33()? as u32))
125    }
126}
127
128impl<'a> FromReader<'a> for Option<ComponentValType> {
129    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
130        match reader.read_u8()? {
131            0x0 => Ok(None),
132            0x1 => Ok(Some(reader.read()?)),
133            x => reader.invalid_leading_byte(x, "optional component value type"),
134        }
135    }
136}
137
138/// Represents a primitive value type.
139#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140pub enum PrimitiveValType {
141    /// The type is a boolean.
142    Bool,
143    /// The type is a signed 8-bit integer.
144    S8,
145    /// The type is an unsigned 8-bit integer.
146    U8,
147    /// The type is a signed 16-bit integer.
148    S16,
149    /// The type is an unsigned 16-bit integer.
150    U16,
151    /// The type is a signed 32-bit integer.
152    S32,
153    /// The type is an unsigned 32-bit integer.
154    U32,
155    /// The type is a signed 64-bit integer.
156    S64,
157    /// The type is an unsigned 64-bit integer.
158    U64,
159    /// The type is a 32-bit floating point number.
160    Float32,
161    /// The type is a 64-bit floating point number.
162    Float64,
163    /// The type is a Unicode character.
164    Char,
165    /// The type is a string.
166    String,
167}
168
169impl PrimitiveValType {
170    fn from_byte(byte: u8) -> Option<PrimitiveValType> {
171        Some(match byte {
172            0x7f => PrimitiveValType::Bool,
173            0x7e => PrimitiveValType::S8,
174            0x7d => PrimitiveValType::U8,
175            0x7c => PrimitiveValType::S16,
176            0x7b => PrimitiveValType::U16,
177            0x7a => PrimitiveValType::S32,
178            0x79 => PrimitiveValType::U32,
179            0x78 => PrimitiveValType::S64,
180            0x77 => PrimitiveValType::U64,
181            0x76 => PrimitiveValType::Float32,
182            0x75 => PrimitiveValType::Float64,
183            0x74 => PrimitiveValType::Char,
184            0x73 => PrimitiveValType::String,
185            _ => return None,
186        })
187    }
188
189    pub(crate) fn requires_realloc(&self) -> bool {
190        matches!(self, Self::String)
191    }
192
193    /// Determines if primitive value type `a` is a subtype of `b`.
194    pub fn is_subtype_of(a: Self, b: Self) -> bool {
195        // Note that this intentionally diverges from the upstream specification
196        // at this time and only considers exact equality for subtyping
197        // relationships.
198        //
199        // More information can be found in the subtyping implementation for
200        // component functions.
201        a == b
202    }
203}
204
205/// Represents a type in a WebAssembly component.
206#[derive(Debug, Clone)]
207pub enum ComponentType<'a> {
208    /// The type is a component defined type.
209    Defined(ComponentDefinedType<'a>),
210    /// The type is a function type.
211    Func(ComponentFuncType<'a>),
212    /// The type is a component type.
213    Component(Box<[ComponentTypeDeclaration<'a>]>),
214    /// The type is an instance type.
215    Instance(Box<[InstanceTypeDeclaration<'a>]>),
216}
217
218impl<'a> FromReader<'a> for ComponentType<'a> {
219    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
220        Ok(match reader.read_u8()? {
221            0x40 => {
222                let params = reader
223                    .read_iter(MAX_WASM_FUNCTION_PARAMS, "component function parameters")?
224                    .collect::<Result<_>>()?;
225                let results = reader.read()?;
226                ComponentType::Func(ComponentFuncType { params, results })
227            }
228            0x41 => ComponentType::Component(
229                reader
230                    .read_iter(MAX_WASM_COMPONENT_TYPE_DECLS, "component type declaration")?
231                    .collect::<Result<_>>()?,
232            ),
233            0x42 => ComponentType::Instance(
234                reader
235                    .read_iter(MAX_WASM_INSTANCE_TYPE_DECLS, "instance type declaration")?
236                    .collect::<Result<_>>()?,
237            ),
238            x => {
239                if let Some(ty) = PrimitiveValType::from_byte(x) {
240                    ComponentType::Defined(ComponentDefinedType::Primitive(ty))
241                } else {
242                    ComponentType::Defined(ComponentDefinedType::read(reader, x)?)
243                }
244            }
245        })
246    }
247}
248
249/// Represents part of a component type declaration in a WebAssembly component.
250#[derive(Debug, Clone)]
251pub enum ComponentTypeDeclaration<'a> {
252    /// The component type declaration is for a core type.
253    CoreType(CoreType<'a>),
254    /// The component type declaration is for a type.
255    Type(ComponentType<'a>),
256    /// The component type declaration is for an alias.
257    Alias(ComponentAlias<'a>),
258    /// The component type declaration is for an export.
259    Export {
260        /// The name of the export.
261        name: &'a str,
262        /// The optional URL of the export.
263        url: &'a str,
264        /// The type reference for the export.
265        ty: ComponentTypeRef,
266    },
267    /// The component type declaration is for an import.
268    Import(ComponentImport<'a>),
269}
270
271impl<'a> FromReader<'a> for ComponentTypeDeclaration<'a> {
272    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
273        // Component types are effectively instance types with the additional
274        // variant of imports; check for imports here or delegate to
275        // `InstanceTypeDeclaration` with the appropriate conversions.
276        if reader.peek()? == 0x03 {
277            reader.position += 1;
278            return Ok(ComponentTypeDeclaration::Import(reader.read()?));
279        }
280
281        Ok(match reader.read()? {
282            InstanceTypeDeclaration::CoreType(t) => ComponentTypeDeclaration::CoreType(t),
283            InstanceTypeDeclaration::Type(t) => ComponentTypeDeclaration::Type(t),
284            InstanceTypeDeclaration::Alias(a) => ComponentTypeDeclaration::Alias(a),
285            InstanceTypeDeclaration::Export { name, url, ty } => {
286                ComponentTypeDeclaration::Export { name, url, ty }
287            }
288        })
289    }
290}
291
292/// Represents an instance type declaration in a WebAssembly component.
293#[derive(Debug, Clone)]
294pub enum InstanceTypeDeclaration<'a> {
295    /// The component type declaration is for a core type.
296    CoreType(CoreType<'a>),
297    /// The instance type declaration is for a type.
298    Type(ComponentType<'a>),
299    /// The instance type declaration is for an alias.
300    Alias(ComponentAlias<'a>),
301    /// The instance type declaration is for an export.
302    Export {
303        /// The name of the export.
304        name: &'a str,
305        /// The URL for the export.
306        url: &'a str,
307        /// The type reference for the export.
308        ty: ComponentTypeRef,
309    },
310}
311
312impl<'a> FromReader<'a> for InstanceTypeDeclaration<'a> {
313    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
314        Ok(match reader.read_u8()? {
315            0x00 => InstanceTypeDeclaration::CoreType(reader.read()?),
316            0x01 => InstanceTypeDeclaration::Type(reader.read()?),
317            0x02 => InstanceTypeDeclaration::Alias(reader.read()?),
318            0x04 => InstanceTypeDeclaration::Export {
319                name: reader.read()?,
320                url: reader.read()?,
321                ty: reader.read()?,
322            },
323            x => return reader.invalid_leading_byte(x, "component or instance type declaration"),
324        })
325    }
326}
327
328/// Represents the result type of a component function.
329#[derive(Debug, Clone)]
330pub enum ComponentFuncResult<'a> {
331    /// The function returns a singular, unnamed type.
332    Unnamed(ComponentValType),
333    /// The function returns zero or more named types.
334    Named(Box<[(&'a str, ComponentValType)]>),
335}
336
337impl<'a> FromReader<'a> for ComponentFuncResult<'a> {
338    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
339        Ok(match reader.read_u8()? {
340            0x00 => ComponentFuncResult::Unnamed(reader.read()?),
341            0x01 => ComponentFuncResult::Named(
342                reader
343                    .read_iter(MAX_WASM_FUNCTION_RETURNS, "component function results")?
344                    .collect::<Result<_>>()?,
345            ),
346            x => return reader.invalid_leading_byte(x, "component function results"),
347        })
348    }
349}
350
351impl ComponentFuncResult<'_> {
352    /// Gets the count of types returned by the function.
353    pub fn type_count(&self) -> usize {
354        match self {
355            Self::Unnamed(_) => 1,
356            Self::Named(vec) => vec.len(),
357        }
358    }
359
360    /// Iterates over the types returned by the function.
361    pub fn iter(&self) -> impl Iterator<Item = (Option<&str>, &ComponentValType)> {
362        enum Either<L, R> {
363            Left(L),
364            Right(R),
365        }
366
367        impl<L, R> Iterator for Either<L, R>
368        where
369            L: Iterator,
370            R: Iterator<Item = L::Item>,
371        {
372            type Item = L::Item;
373
374            fn next(&mut self) -> Option<Self::Item> {
375                match self {
376                    Either::Left(l) => l.next(),
377                    Either::Right(r) => r.next(),
378                }
379            }
380        }
381
382        match self {
383            Self::Unnamed(ty) => Either::Left(::core::iter::once(ty).map(|ty| (None, ty))),
384            Self::Named(vec) => Either::Right(vec.iter().map(|(n, ty)| (Some(*n), ty))),
385        }
386    }
387}
388
389/// Represents a type of a function in a WebAssembly component.
390#[derive(Debug, Clone)]
391pub struct ComponentFuncType<'a> {
392    /// The function parameters.
393    pub params: Box<[(&'a str, ComponentValType)]>,
394    /// The function result.
395    pub results: ComponentFuncResult<'a>,
396}
397
398/// Represents a case in a variant type.
399#[derive(Debug, Clone, PartialEq, Eq)]
400pub struct VariantCase<'a> {
401    /// The name of the variant case.
402    pub name: &'a str,
403    /// The value type of the variant case.
404    pub ty: Option<ComponentValType>,
405    /// The index of the variant case that is refined by this one.
406    pub refines: Option<u32>,
407}
408
409impl<'a> FromReader<'a> for VariantCase<'a> {
410    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
411        Ok(VariantCase {
412            name: reader.read()?,
413            ty: reader.read()?,
414            refines: match reader.read_u8()? {
415                0x0 => None,
416                0x1 => Some(reader.read_var_u32()?),
417                x => return reader.invalid_leading_byte(x, "variant case refines"),
418            },
419        })
420    }
421}
422
423/// Represents a defined type in a WebAssembly component.
424#[derive(Debug, Clone, PartialEq, Eq)]
425pub enum ComponentDefinedType<'a> {
426    /// The type is one of the primitive value types.
427    Primitive(PrimitiveValType),
428    /// The type is a record with the given fields.
429    Record(Box<[(&'a str, ComponentValType)]>),
430    /// The type is a variant with the given cases.
431    Variant(Box<[VariantCase<'a>]>),
432    /// The type is a list of the given value type.
433    List(ComponentValType),
434    /// The type is a tuple of the given value types.
435    Tuple(Box<[ComponentValType]>),
436    /// The type is flags with the given names.
437    Flags(Box<[&'a str]>),
438    /// The type is an enum with the given tags.
439    Enum(Box<[&'a str]>),
440    /// The type is a union of the given value types.
441    Union(Box<[ComponentValType]>),
442    /// The type is an option of the given value type.
443    Option(ComponentValType),
444    /// The type is a result type.
445    Result {
446        /// The type returned for success.
447        ok: Option<ComponentValType>,
448        /// The type returned for failure.
449        err: Option<ComponentValType>,
450    },
451}
452
453impl<'a> ComponentDefinedType<'a> {
454    fn read(reader: &mut BinaryReader<'a>, byte: u8) -> Result<ComponentDefinedType<'a>> {
455        Ok(match byte {
456            0x72 => ComponentDefinedType::Record(
457                reader
458                    .read_iter(MAX_WASM_RECORD_FIELDS, "record field")?
459                    .collect::<Result<_>>()?,
460            ),
461            0x71 => ComponentDefinedType::Variant(
462                reader
463                    .read_iter(MAX_WASM_VARIANT_CASES, "variant cases")?
464                    .collect::<Result<_>>()?,
465            ),
466            0x70 => ComponentDefinedType::List(reader.read()?),
467            0x6f => ComponentDefinedType::Tuple(
468                reader
469                    .read_iter(MAX_WASM_TUPLE_TYPES, "tuple types")?
470                    .collect::<Result<_>>()?,
471            ),
472            0x6e => ComponentDefinedType::Flags(
473                reader
474                    .read_iter(MAX_WASM_FLAG_NAMES, "flag names")?
475                    .collect::<Result<_>>()?,
476            ),
477            0x6d => ComponentDefinedType::Enum(
478                reader
479                    .read_iter(MAX_WASM_ENUM_CASES, "enum cases")?
480                    .collect::<Result<_>>()?,
481            ),
482            0x6c => ComponentDefinedType::Union(
483                reader
484                    .read_iter(MAX_WASM_UNION_TYPES, "union types")?
485                    .collect::<Result<_>>()?,
486            ),
487            0x6b => ComponentDefinedType::Option(reader.read()?),
488            0x6a => ComponentDefinedType::Result {
489                ok: reader.read()?,
490                err: reader.read()?,
491            },
492            x => return reader.invalid_leading_byte(x, "component defined type"),
493        })
494    }
495}
496
497/// A reader for the type section of a WebAssembly component.
498///
499/// # Examples
500///
501/// ```
502/// use wasmparser_nostd::ComponentTypeSectionReader;
503/// let data: &[u8] = &[0x01, 0x40, 0x01, 0x03, b'f', b'o', b'o', 0x73, 0x00, 0x73];
504/// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap();
505/// for ty in reader {
506///     println!("Type {:?}", ty.expect("type"));
507/// }
508/// ```
509pub type ComponentTypeSectionReader<'a> = SectionLimited<'a, ComponentType<'a>>;