Skip to main content

wasmparser/readers/component/
imports.rs

1use crate::{
2    BinaryReader, ComponentExternalKind, ComponentValType, FromReader, Result, SectionLimited,
3};
4
5/// Represents the type bounds for imports and exports.
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub enum TypeBounds {
8    /// The type is bounded by equality.
9    Eq(u32),
10    /// A fresh resource type,
11    SubResource,
12}
13
14impl<'a> FromReader<'a> for TypeBounds {
15    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
16        Ok(match reader.read_u8()? {
17            0x00 => TypeBounds::Eq(reader.read()?),
18            0x01 => TypeBounds::SubResource,
19            x => return reader.invalid_leading_byte(x, "type bound"),
20        })
21    }
22}
23
24/// Represents a reference to a component type.
25#[derive(Clone, Copy, Debug, Eq, PartialEq)]
26pub enum ComponentTypeRef {
27    /// The reference is to a core module type.
28    ///
29    /// The index is expected to be core type index to a core module type.
30    Module(u32),
31    /// The reference is to a function type.
32    ///
33    /// The index is expected to be a type index to a function type.
34    Func(u32),
35    /// The reference is to a value type.
36    Value(ComponentValType),
37    /// The reference is to a bounded type.
38    ///
39    /// The index is expected to be a type index.
40    Type(TypeBounds),
41    /// The reference is to an instance type.
42    ///
43    /// The index is a type index to an instance type.
44    Instance(u32),
45    /// The reference is to a component type.
46    ///
47    /// The index is a type index to a component type.
48    Component(u32),
49}
50
51impl ComponentTypeRef {
52    /// Returns the corresponding [`ComponentExternalKind`] for this reference.
53    pub fn kind(&self) -> ComponentExternalKind {
54        match self {
55            ComponentTypeRef::Module(_) => ComponentExternalKind::Module,
56            ComponentTypeRef::Func(_) => ComponentExternalKind::Func,
57            ComponentTypeRef::Value(_) => ComponentExternalKind::Value,
58            ComponentTypeRef::Type(..) => ComponentExternalKind::Type,
59            ComponentTypeRef::Instance(_) => ComponentExternalKind::Instance,
60            ComponentTypeRef::Component(_) => ComponentExternalKind::Component,
61        }
62    }
63}
64
65impl<'a> FromReader<'a> for ComponentTypeRef {
66    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
67        Ok(match reader.read()? {
68            ComponentExternalKind::Module => ComponentTypeRef::Module(reader.read()?),
69            ComponentExternalKind::Func => ComponentTypeRef::Func(reader.read_var_u32()?),
70            ComponentExternalKind::Value => ComponentTypeRef::Value(reader.read()?),
71            ComponentExternalKind::Type => ComponentTypeRef::Type(reader.read()?),
72            ComponentExternalKind::Instance => ComponentTypeRef::Instance(reader.read()?),
73            ComponentExternalKind::Component => ComponentTypeRef::Component(reader.read()?),
74        })
75    }
76}
77
78/// Represents an import in a WebAssembly component
79#[derive(Debug, Copy, Clone, Eq, PartialEq)]
80pub struct ComponentImport<'a> {
81    /// The name of the imported item.
82    pub name: ComponentExternName<'a>,
83    /// The type reference for the import.
84    pub ty: ComponentTypeRef,
85}
86
87impl<'a> FromReader<'a> for ComponentImport<'a> {
88    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
89        Ok(ComponentImport {
90            name: reader.read()?,
91            ty: reader.read()?,
92        })
93    }
94}
95
96/// A reader for the import section of a WebAssembly component.
97///
98/// # Examples
99///
100/// ```
101/// use wasmparser::{ComponentImportSectionReader, BinaryReader};
102/// let data: &[u8] = &[0x01, 0x00, 0x01, 0x41, 0x01, 0x66];
103/// let reader = BinaryReader::new(data, 0);
104/// let reader = ComponentImportSectionReader::new(reader).unwrap();
105/// for import in reader {
106///     let import = import.expect("import");
107///     println!("Import: {:?}", import);
108/// }
109/// ```
110pub type ComponentImportSectionReader<'a> = SectionLimited<'a, ComponentImport<'a>>;
111
112/// Represents the name of a component import.
113#[derive(Debug, Copy, Clone, Eq, PartialEq)]
114#[allow(missing_docs)]
115pub struct ComponentExternName<'a> {
116    pub name: &'a str,
117    pub implements: Option<&'a str>,
118}
119
120impl<'a> FromReader<'a> for ComponentExternName<'a> {
121    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
122        let has_options = match reader.read_u8()? {
123            // This is the spec-required byte as of this time.
124            0x00 => false,
125
126            // Prior to WebAssembly/component-model#263 export names used a
127            // discriminator byte of 0x01 to indicate an "interface" of the
128            // form `a:b/c` but nowadays that's inferred from string syntax.
129            // Ignore 0-vs-1 to continue to parse older binaries. Eventually
130            // this will go away.
131            //
132            // This logic to ignore 0x01 was landed on 2023-10-28 in
133            // bytecodealliance/wasm-tools#1262 and the encoder at the time
134            // still emitted 0x01 to have better compatibility with prior
135            // validators.
136            //
137            // On 2024-09-03 in bytecodealliance/wasm-tools#TODO the encoder
138            // was updated to always emit 0x00 as a leading byte. After enough
139            // time has passed this case may be able to be removed. When
140            // removing this it's probably best to do it with a `WasmFeatures`
141            // flag first to ensure there's an opt-in way of fixing things.
142            0x01 => false,
143
144            0x02 => {
145                if reader.cm_implements() {
146                    true
147                } else {
148                    bail!(
149                        reader.original_position() - 1,
150                        "the `cm-implements` feature is not active"
151                    )
152                }
153            }
154
155            x => return reader.invalid_leading_byte(x, "component name"),
156        };
157        let mut ret = ComponentExternName {
158            name: reader.read_string()?,
159            implements: None,
160        };
161        if has_options {
162            for _ in 0..reader.read_var_u32()? {
163                let pos = reader.original_position();
164                match reader.read()? {
165                    ComponentNameOpt::Implements(name) => {
166                        if ret.implements.is_some() {
167                            bail!(pos, "duplicate 'implements' option in name");
168                        }
169                        ret.implements = Some(name);
170                    }
171                }
172            }
173        }
174        Ok(ret)
175    }
176}
177
178enum ComponentNameOpt<'a> {
179    Implements(&'a str),
180}
181
182impl<'a> FromReader<'a> for ComponentNameOpt<'a> {
183    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
184        match reader.read_u8()? {
185            0x00 => Ok(ComponentNameOpt::Implements(reader.read()?)),
186            x => return reader.invalid_leading_byte(x, "name option"),
187        }
188    }
189}