/src/wasm-tools/crates/wasm-encoder/src/component/imports.rs
Line | Count | Source |
1 | | use crate::{ |
2 | | ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType, Encode, |
3 | | encode_section, |
4 | | }; |
5 | | use alloc::borrow::Cow; |
6 | | use alloc::string::String; |
7 | | use alloc::vec::Vec; |
8 | | |
9 | | /// Represents the possible type bounds for type references. |
10 | | #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] |
11 | | pub enum TypeBounds { |
12 | | /// The type is bounded by equality to the type index specified. |
13 | | Eq(u32), |
14 | | /// This type is a fresh resource type, |
15 | | SubResource, |
16 | | } |
17 | | |
18 | | impl Encode for TypeBounds { |
19 | 101k | fn encode(&self, sink: &mut Vec<u8>) { |
20 | 101k | match self { |
21 | 97.9k | Self::Eq(i) => { |
22 | 97.9k | sink.push(0x00); |
23 | 97.9k | i.encode(sink); |
24 | 97.9k | } |
25 | 3.94k | Self::SubResource => sink.push(0x01), |
26 | | } |
27 | 101k | } |
28 | | } |
29 | | |
30 | | /// Represents a reference to a type. |
31 | | #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] |
32 | | pub enum ComponentTypeRef { |
33 | | /// The reference is to a core module type. |
34 | | /// |
35 | | /// The index is expected to be core type index to a core module type. |
36 | | Module(u32), |
37 | | /// The reference is to a function type. |
38 | | /// |
39 | | /// The index is expected to be a type index to a function type. |
40 | | Func(u32), |
41 | | /// The reference is to a value type. |
42 | | Value(ComponentValType), |
43 | | /// The reference is to a bounded type. |
44 | | Type(TypeBounds), |
45 | | /// The reference is to an instance type. |
46 | | /// |
47 | | /// The index is expected to be a type index to an instance type. |
48 | | Instance(u32), |
49 | | /// The reference is to a component type. |
50 | | /// |
51 | | /// The index is expected to be a type index to a component type. |
52 | | Component(u32), |
53 | | } |
54 | | |
55 | | impl ComponentTypeRef { |
56 | | /// Gets the export kind of the reference. |
57 | 221k | pub fn kind(&self) -> ComponentExportKind { |
58 | 221k | match self { |
59 | 0 | Self::Module(_) => ComponentExportKind::Module, |
60 | 43.9k | Self::Func(_) => ComponentExportKind::Func, |
61 | 0 | Self::Value(_) => ComponentExportKind::Value, |
62 | 101k | Self::Type(..) => ComponentExportKind::Type, |
63 | 59.5k | Self::Instance(_) => ComponentExportKind::Instance, |
64 | 15.7k | Self::Component(_) => ComponentExportKind::Component, |
65 | | } |
66 | 221k | } |
67 | | } |
68 | | |
69 | | impl Encode for ComponentTypeRef { |
70 | 221k | fn encode(&self, sink: &mut Vec<u8>) { |
71 | 221k | self.kind().encode(sink); |
72 | | |
73 | 221k | match self { |
74 | 119k | Self::Module(idx) | Self::Func(idx) | Self::Instance(idx) | Self::Component(idx) => { |
75 | 119k | idx.encode(sink); |
76 | 119k | } |
77 | 0 | Self::Value(ty) => ty.encode(sink), |
78 | 101k | Self::Type(bounds) => bounds.encode(sink), |
79 | | } |
80 | 221k | } |
81 | | } |
82 | | |
83 | | /// An encoder for the import section of WebAssembly components. |
84 | | /// |
85 | | /// # Example |
86 | | /// |
87 | | /// ```rust |
88 | | /// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef}; |
89 | | /// |
90 | | /// let mut types = ComponentTypeSection::new(); |
91 | | /// |
92 | | /// // Define a function type of `[string, string] -> string`. |
93 | | /// types |
94 | | /// .function() |
95 | | /// .params( |
96 | | /// [ |
97 | | /// ("a", PrimitiveValType::String), |
98 | | /// ("b", PrimitiveValType::String) |
99 | | /// ] |
100 | | /// ) |
101 | | /// .result(Some(PrimitiveValType::String.into())); |
102 | | /// |
103 | | /// // This imports a function named `f` with the type defined above |
104 | | /// let mut imports = ComponentImportSection::new(); |
105 | | /// imports.import("f", ComponentTypeRef::Func(0)); |
106 | | /// |
107 | | /// let mut component = Component::new(); |
108 | | /// component.section(&types); |
109 | | /// component.section(&imports); |
110 | | /// |
111 | | /// let bytes = component.finish(); |
112 | | /// ``` |
113 | | #[derive(Clone, Debug, Default)] |
114 | | pub struct ComponentImportSection { |
115 | | bytes: Vec<u8>, |
116 | | num_added: u32, |
117 | | } |
118 | | |
119 | | impl ComponentImportSection { |
120 | | /// Create a new component import section encoder. |
121 | 4.11k | pub fn new() -> Self { |
122 | 4.11k | Self::default() |
123 | 4.11k | } |
124 | | |
125 | | /// The number of imports in the section. |
126 | 0 | pub fn len(&self) -> u32 { |
127 | 0 | self.num_added |
128 | 0 | } |
129 | | |
130 | | /// Determines if the section is empty. |
131 | 0 | pub fn is_empty(&self) -> bool { |
132 | 0 | self.num_added == 0 |
133 | 0 | } |
134 | | |
135 | | /// Define an import in the component import section. |
136 | 5.37k | pub fn import<'a>( |
137 | 5.37k | &mut self, |
138 | 5.37k | name: impl Into<ComponentExternName<'a>>, |
139 | 5.37k | ty: ComponentTypeRef, |
140 | 5.37k | ) -> &mut Self { |
141 | 5.37k | name.into().encode(&mut self.bytes); |
142 | 5.37k | ty.encode(&mut self.bytes); |
143 | 5.37k | self.num_added += 1; |
144 | 5.37k | self |
145 | 5.37k | } <wasm_encoder::component::imports::ComponentImportSection>::import::<wasm_encoder::component::imports::ComponentExternName> Line | Count | Source | 136 | 5.37k | pub fn import<'a>( | 137 | 5.37k | &mut self, | 138 | 5.37k | name: impl Into<ComponentExternName<'a>>, | 139 | 5.37k | ty: ComponentTypeRef, | 140 | 5.37k | ) -> &mut Self { | 141 | 5.37k | name.into().encode(&mut self.bytes); | 142 | 5.37k | ty.encode(&mut self.bytes); | 143 | 5.37k | self.num_added += 1; | 144 | 5.37k | self | 145 | 5.37k | } |
Unexecuted instantiation: <wasm_encoder::component::imports::ComponentImportSection>::import::<&alloc::string::String> Unexecuted instantiation: <wasm_encoder::component::imports::ComponentImportSection>::import::<_> |
146 | | } |
147 | | |
148 | | impl Encode for ComponentImportSection { |
149 | 4.11k | fn encode(&self, sink: &mut Vec<u8>) { |
150 | 4.11k | encode_section(sink, self.num_added, &self.bytes); |
151 | 4.11k | } |
152 | | } |
153 | | |
154 | | impl ComponentSection for ComponentImportSection { |
155 | 4.11k | fn id(&self) -> u8 { |
156 | 4.11k | ComponentSectionId::Import.into() |
157 | 4.11k | } |
158 | | } |
159 | | |
160 | | /// Full options for encoding a component name. |
161 | | #[derive(Debug, Clone)] |
162 | | pub struct ComponentExternName<'a> { |
163 | | /// The name to encode. |
164 | | pub name: Cow<'a, str>, |
165 | | /// An optional `(implements ...)` directive (See 🏷️ in the component model |
166 | | /// explainer). |
167 | | pub implements: Option<Cow<'a, str>>, |
168 | | /// An optional `(versionsuffix ...)` directive (See 🔗 in the component |
169 | | /// model explainer). |
170 | | pub version_suffix: Option<Cow<'a, str>>, |
171 | | /// An optional `(external-id ...)` directive (See 🏷️ in the component model |
172 | | /// explainer). |
173 | | pub external_id: Option<Cow<'a, str>>, |
174 | | } |
175 | | |
176 | | impl Encode for ComponentExternName<'_> { |
177 | 288k | fn encode(&self, bytes: &mut Vec<u8>) { |
178 | 288k | let mut options = Vec::new(); |
179 | | |
180 | | let ComponentExternName { |
181 | | name: _, |
182 | 288k | implements, |
183 | 288k | version_suffix, |
184 | 288k | external_id, |
185 | 288k | } = self; |
186 | | |
187 | 288k | if let Some(s) = implements { |
188 | 9.47k | options.push((0x00, s.as_bytes())); |
189 | 279k | } |
190 | 288k | if let Some(s) = version_suffix { |
191 | 0 | options.push((0x01, s.as_bytes())); |
192 | 288k | } |
193 | 288k | if let Some(s) = external_id { |
194 | 139k | options.push((0x02, s.as_bytes())); |
195 | 149k | } |
196 | | |
197 | 288k | if options.is_empty() { |
198 | 148k | // Prior to WebAssembly/component-model#263 import and export names |
199 | 148k | // were discriminated with a leading byte indicating what kind of |
200 | 148k | // import they are. After that PR though names are always prefixed |
201 | 148k | // with a 0x00 byte. |
202 | 148k | // |
203 | 148k | // On 2023-10-28 in bytecodealliance/wasm-tools#1262 was landed to |
204 | 148k | // start transitioning to "always lead with 0x00". That updated the |
205 | 148k | // validator/parser to accept either 0x00 or 0x01 but the encoder |
206 | 148k | // wasn't updated at the time. |
207 | 148k | // |
208 | 148k | // On 2024-09-03 in bytecodealliance/wasm-tools#TODO this encoder |
209 | 148k | // was updated to always emit 0x00 as a leading byte. |
210 | 148k | // |
211 | 148k | // This corresponds with the `importname'` production in the |
212 | 148k | // specification. |
213 | 148k | bytes.push(0x00); |
214 | 148k | } else { |
215 | 139k | bytes.push(0x02); |
216 | 139k | } |
217 | | |
218 | 288k | self.name.encode(bytes); |
219 | | |
220 | 288k | if !options.is_empty() { |
221 | 139k | options.len().encode(bytes); |
222 | 148k | for (kind, val) in options { |
223 | 148k | bytes.push(kind); |
224 | 148k | val.encode(bytes); |
225 | 148k | } |
226 | 148k | } |
227 | 288k | } |
228 | | } |
229 | | |
230 | | impl<'a> From<&'a str> for ComponentExternName<'a> { |
231 | 61.3k | fn from(name: &'a str) -> Self { |
232 | 61.3k | ComponentExternName { |
233 | 61.3k | name: Cow::Borrowed(name), |
234 | 61.3k | implements: None, |
235 | 61.3k | external_id: None, |
236 | 61.3k | version_suffix: None, |
237 | 61.3k | } |
238 | 61.3k | } |
239 | | } |
240 | | |
241 | | impl<'a> From<&'a String> for ComponentExternName<'a> { |
242 | 61.3k | fn from(name: &'a String) -> Self { |
243 | 61.3k | ComponentExternName::from(name.as_str()) |
244 | 61.3k | } |
245 | | } |
246 | | |
247 | | impl<'a> From<String> for ComponentExternName<'a> { |
248 | 63.7k | fn from(name: String) -> Self { |
249 | 63.7k | ComponentExternName { |
250 | 63.7k | name: Cow::Owned(name), |
251 | 63.7k | implements: None, |
252 | 63.7k | external_id: None, |
253 | 63.7k | version_suffix: None, |
254 | 63.7k | } |
255 | 63.7k | } |
256 | | } |
257 | | |
258 | | #[cfg(feature = "wasmparser")] |
259 | | impl<'a> From<wasmparser::ComponentExternName<'a>> for ComponentExternName<'a> { |
260 | 0 | fn from(name: wasmparser::ComponentExternName<'a>) -> Self { |
261 | | let wasmparser::ComponentExternName { |
262 | 0 | name, |
263 | 0 | implements, |
264 | 0 | external_id, |
265 | 0 | version_suffix, |
266 | 0 | } = name; |
267 | | ComponentExternName { |
268 | 0 | name: name.into(), |
269 | 0 | implements: implements.map(|s| s.into()), |
270 | 0 | external_id: external_id.map(|s| s.into()), |
271 | 0 | version_suffix: version_suffix.map(|s| s.into()), |
272 | | } |
273 | 0 | } |
274 | | } |