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}