wasmparser/readers/component/
types.rs

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