wasmparser/readers/component/
types.rs

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