wasm_encoder/component/
imports.rs

1use crate::{
2    encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType,
3    Encode,
4};
5use alloc::vec::Vec;
6
7/// Represents the possible type bounds for type references.
8#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
9pub enum TypeBounds {
10    /// The type is bounded by equality to the type index specified.
11    Eq(u32),
12    /// This type is a fresh resource type,
13    SubResource,
14}
15
16impl Encode for TypeBounds {
17    fn encode(&self, sink: &mut Vec<u8>) {
18        match self {
19            Self::Eq(i) => {
20                sink.push(0x00);
21                i.encode(sink);
22            }
23            Self::SubResource => sink.push(0x01),
24        }
25    }
26}
27
28/// Represents a reference to a type.
29#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
30pub enum ComponentTypeRef {
31    /// The reference is to a core module type.
32    ///
33    /// The index is expected to be core type index to a core module type.
34    Module(u32),
35    /// The reference is to a function type.
36    ///
37    /// The index is expected to be a type index to a function type.
38    Func(u32),
39    /// The reference is to a value type.
40    Value(ComponentValType),
41    /// The reference is to a bounded type.
42    Type(TypeBounds),
43    /// The reference is to an instance type.
44    ///
45    /// The index is expected to be a type index to an instance type.
46    Instance(u32),
47    /// The reference is to a component type.
48    ///
49    /// The index is expected to be a type index to a component type.
50    Component(u32),
51}
52
53impl ComponentTypeRef {
54    /// Gets the export kind of the reference.
55    pub fn kind(&self) -> ComponentExportKind {
56        match self {
57            Self::Module(_) => ComponentExportKind::Module,
58            Self::Func(_) => ComponentExportKind::Func,
59            Self::Value(_) => ComponentExportKind::Value,
60            Self::Type(..) => ComponentExportKind::Type,
61            Self::Instance(_) => ComponentExportKind::Instance,
62            Self::Component(_) => ComponentExportKind::Component,
63        }
64    }
65}
66
67impl Encode for ComponentTypeRef {
68    fn encode(&self, sink: &mut Vec<u8>) {
69        self.kind().encode(sink);
70
71        match self {
72            Self::Module(idx) | Self::Func(idx) | Self::Instance(idx) | Self::Component(idx) => {
73                idx.encode(sink);
74            }
75            Self::Value(ty) => ty.encode(sink),
76            Self::Type(bounds) => bounds.encode(sink),
77        }
78    }
79}
80
81/// An encoder for the import section of WebAssembly components.
82///
83/// # Example
84///
85/// ```rust
86/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef};
87///
88/// let mut types = ComponentTypeSection::new();
89///
90/// // Define a function type of `[string, string] -> string`.
91/// types
92///   .function()
93///   .params(
94///     [
95///       ("a", PrimitiveValType::String),
96///       ("b", PrimitiveValType::String)
97///     ]
98///   )
99///   .result(Some(PrimitiveValType::String.into()));
100///
101/// // This imports a function named `f` with the type defined above
102/// let mut imports = ComponentImportSection::new();
103/// imports.import("f", ComponentTypeRef::Func(0));
104///
105/// let mut component = Component::new();
106/// component.section(&types);
107/// component.section(&imports);
108///
109/// let bytes = component.finish();
110/// ```
111#[derive(Clone, Debug, Default)]
112pub struct ComponentImportSection {
113    bytes: Vec<u8>,
114    num_added: u32,
115}
116
117impl ComponentImportSection {
118    /// Create a new component import section encoder.
119    pub fn new() -> Self {
120        Self::default()
121    }
122
123    /// The number of imports in the section.
124    pub fn len(&self) -> u32 {
125        self.num_added
126    }
127
128    /// Determines if the section is empty.
129    pub fn is_empty(&self) -> bool {
130        self.num_added == 0
131    }
132
133    /// Define an import in the component import section.
134    pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self {
135        encode_component_import_name(&mut self.bytes, name);
136        ty.encode(&mut self.bytes);
137        self.num_added += 1;
138        self
139    }
140}
141
142impl Encode for ComponentImportSection {
143    fn encode(&self, sink: &mut Vec<u8>) {
144        encode_section(sink, self.num_added, &self.bytes);
145    }
146}
147
148impl ComponentSection for ComponentImportSection {
149    fn id(&self) -> u8 {
150        ComponentSectionId::Import.into()
151    }
152}
153
154/// Prior to WebAssembly/component-model#263 import and export names were
155/// discriminated with a leading byte indicating what kind of import they are.
156/// After that PR though names are always prefixed with a 0x00 byte.
157///
158/// On 2023-10-28 in bytecodealliance/wasm-tools#1262 was landed to start
159/// transitioning to "always lead with 0x00". That updated the validator/parser
160/// to accept either 0x00 or 0x01 but the encoder wasn't updated at the time.
161///
162/// On 2024-09-03 in bytecodealliance/wasm-tools#TODO this encoder was updated
163/// to always emit 0x00 as a leading byte.
164///
165/// This function corresponds with the `importname'` production in the
166/// specification.
167pub(crate) fn encode_component_import_name(bytes: &mut Vec<u8>, name: &str) {
168    bytes.push(0x00);
169    name.encode(bytes);
170}