1 | use crate::{encode_section, ComponentSection, ComponentSectionId, Encode}; |
2 | use alloc::vec::Vec; |
3 | |
4 | /// Represents options for canonical function definitions. |
5 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
6 | pub enum CanonicalOption { |
7 | /// The string types in the function signature are UTF-8 encoded. |
8 | UTF8, |
9 | /// The string types in the function signature are UTF-16 encoded. |
10 | UTF16, |
11 | /// The string types in the function signature are compact UTF-16 encoded. |
12 | CompactUTF16, |
13 | /// The memory to use if the lifting or lowering of a function requires memory access. |
14 | /// |
15 | /// The value is an index to a core memory. |
16 | Memory(u32), |
17 | /// The realloc function to use if the lifting or lowering of a function requires memory |
18 | /// allocation. |
19 | /// |
20 | /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`. |
21 | Realloc(u32), |
22 | /// The post-return function to use if the lifting of a function requires |
23 | /// cleanup after the function returns. |
24 | PostReturn(u32), |
25 | /// Indicates that specified function should be lifted or lowered using the `async` ABI. |
26 | Async, |
27 | /// The function to use if the async lifting of a function should receive task/stream/future progress events |
28 | /// using a callback. |
29 | Callback(u32), |
30 | } |
31 | |
32 | impl Encode for CanonicalOption { |
33 | fn encode(&self, sink: &mut Vec<u8>) { |
34 | match self { |
35 | Self::UTF8 => sink.push(0x00), |
36 | Self::UTF16 => sink.push(0x01), |
37 | Self::CompactUTF16 => sink.push(0x02), |
38 | Self::Memory(idx) => { |
39 | sink.push(0x03); |
40 | idx.encode(sink); |
41 | } |
42 | Self::Realloc(idx) => { |
43 | sink.push(0x04); |
44 | idx.encode(sink); |
45 | } |
46 | Self::PostReturn(idx) => { |
47 | sink.push(0x05); |
48 | idx.encode(sink); |
49 | } |
50 | Self::Async => { |
51 | sink.push(0x06); |
52 | } |
53 | Self::Callback(idx) => { |
54 | sink.push(0x07); |
55 | idx.encode(sink); |
56 | } |
57 | } |
58 | } |
59 | } |
60 | |
61 | /// An encoder for the canonical function section of WebAssembly components. |
62 | /// |
63 | /// # Example |
64 | /// |
65 | /// ``` |
66 | /// use wasm_encoder::{Component, CanonicalFunctionSection, CanonicalOption}; |
67 | /// |
68 | /// let mut functions = CanonicalFunctionSection::new(); |
69 | /// functions.lift(0, 0, [CanonicalOption::UTF8]); |
70 | /// |
71 | /// let mut component = Component::new(); |
72 | /// component.section(&functions); |
73 | /// |
74 | /// let bytes = component.finish(); |
75 | /// ``` |
76 | #[derive (Clone, Debug, Default)] |
77 | pub struct CanonicalFunctionSection { |
78 | bytes: Vec<u8>, |
79 | num_added: u32, |
80 | } |
81 | |
82 | impl CanonicalFunctionSection { |
83 | /// Construct a new component function section encoder. |
84 | pub fn new() -> Self { |
85 | Self::default() |
86 | } |
87 | |
88 | /// The number of functions in the section. |
89 | pub fn len(&self) -> u32 { |
90 | self.num_added |
91 | } |
92 | |
93 | /// Determines if the section is empty. |
94 | pub fn is_empty(&self) -> bool { |
95 | self.num_added == 0 |
96 | } |
97 | |
98 | /// Define a function that will lift a core WebAssembly function to the canonical ABI. |
99 | pub fn lift<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> &mut Self |
100 | where |
101 | O: IntoIterator<Item = CanonicalOption>, |
102 | O::IntoIter: ExactSizeIterator, |
103 | { |
104 | let options = options.into_iter(); |
105 | self.bytes.push(0x00); |
106 | self.bytes.push(0x00); |
107 | core_func_index.encode(&mut self.bytes); |
108 | options.len().encode(&mut self.bytes); |
109 | for option in options { |
110 | option.encode(&mut self.bytes); |
111 | } |
112 | type_index.encode(&mut self.bytes); |
113 | self.num_added += 1; |
114 | self |
115 | } |
116 | |
117 | /// Define a function that will lower a canonical ABI function to a core WebAssembly function. |
118 | pub fn lower<O>(&mut self, func_index: u32, options: O) -> &mut Self |
119 | where |
120 | O: IntoIterator<Item = CanonicalOption>, |
121 | O::IntoIter: ExactSizeIterator, |
122 | { |
123 | let options = options.into_iter(); |
124 | self.bytes.push(0x01); |
125 | self.bytes.push(0x00); |
126 | func_index.encode(&mut self.bytes); |
127 | options.len().encode(&mut self.bytes); |
128 | for option in options { |
129 | option.encode(&mut self.bytes); |
130 | } |
131 | self.num_added += 1; |
132 | self |
133 | } |
134 | |
135 | /// Defines a function which will create an owned handle to the resource |
136 | /// specified by `ty_index`. |
137 | pub fn resource_new(&mut self, ty_index: u32) -> &mut Self { |
138 | self.bytes.push(0x02); |
139 | ty_index.encode(&mut self.bytes); |
140 | self.num_added += 1; |
141 | self |
142 | } |
143 | |
144 | /// Defines a function which will drop the specified type of handle. |
145 | pub fn resource_drop(&mut self, ty_index: u32) -> &mut Self { |
146 | self.bytes.push(0x03); |
147 | ty_index.encode(&mut self.bytes); |
148 | self.num_added += 1; |
149 | self |
150 | } |
151 | |
152 | /// Defines a function which will return the representation of the specified |
153 | /// resource type. |
154 | pub fn resource_rep(&mut self, ty_index: u32) -> &mut Self { |
155 | self.bytes.push(0x04); |
156 | ty_index.encode(&mut self.bytes); |
157 | self.num_added += 1; |
158 | self |
159 | } |
160 | |
161 | /// Defines a function which will spawns a new thread by invoking a shared |
162 | /// function of type `ty_index`. |
163 | pub fn thread_spawn(&mut self, ty_index: u32) -> &mut Self { |
164 | self.bytes.push(0x05); |
165 | ty_index.encode(&mut self.bytes); |
166 | self.num_added += 1; |
167 | self |
168 | } |
169 | |
170 | /// Defines a function which will return the number of threads that can be |
171 | /// expected to execute concurrently. |
172 | pub fn thread_hw_concurrency(&mut self) -> &mut Self { |
173 | self.bytes.push(0x06); |
174 | self.num_added += 1; |
175 | self |
176 | } |
177 | |
178 | /// Defines a function which tells the host to enable or disable |
179 | /// backpressure for the caller's instance. When backpressure is enabled, |
180 | /// the host must not start any new calls to that instance until |
181 | /// backpressure is disabled. |
182 | pub fn task_backpressure(&mut self) -> &mut Self { |
183 | self.bytes.push(0x08); |
184 | self.num_added += 1; |
185 | self |
186 | } |
187 | |
188 | /// Defines a function which returns a result to the caller of a lifted |
189 | /// export function. This allows the callee to continue executing after |
190 | /// returning a result. |
191 | pub fn task_return(&mut self, ty: u32) -> &mut Self { |
192 | self.bytes.push(0x09); |
193 | ty.encode(&mut self.bytes); |
194 | self.num_added += 1; |
195 | self |
196 | } |
197 | |
198 | /// Defines a function which waits for at least one outstanding async |
199 | /// task/stream/future to make progress, returning the first such event. |
200 | /// |
201 | /// If `async_` is true, the caller instance may be reentered. |
202 | pub fn task_wait(&mut self, async_: bool, memory: u32) -> &mut Self { |
203 | self.bytes.push(0x0a); |
204 | self.bytes.push(if async_ { 1 } else { 0 }); |
205 | memory.encode(&mut self.bytes); |
206 | self.num_added += 1; |
207 | self |
208 | } |
209 | |
210 | /// Defines a function which checks whether any outstanding async |
211 | /// task/stream/future has made progress. Unlike `task.wait`, this does not |
212 | /// block and may return nothing if no such event has occurred. |
213 | /// |
214 | /// If `async_` is true, the caller instance may be reentered. |
215 | pub fn task_poll(&mut self, async_: bool, memory: u32) -> &mut Self { |
216 | self.bytes.push(0x0b); |
217 | self.bytes.push(if async_ { 1 } else { 0 }); |
218 | memory.encode(&mut self.bytes); |
219 | self.num_added += 1; |
220 | self |
221 | } |
222 | |
223 | /// Defines a function which yields control to the host so that other tasks |
224 | /// are able to make progress, if any. |
225 | /// |
226 | /// If `async_` is true, the caller instance may be reentered. |
227 | pub fn task_yield(&mut self, async_: bool) -> &mut Self { |
228 | self.bytes.push(0x0c); |
229 | self.bytes.push(if async_ { 1 } else { 0 }); |
230 | self.num_added += 1; |
231 | self |
232 | } |
233 | |
234 | /// Defines a function to drop a specified task which has completed. |
235 | pub fn subtask_drop(&mut self) -> &mut Self { |
236 | self.bytes.push(0x0d); |
237 | self.num_added += 1; |
238 | self |
239 | } |
240 | |
241 | /// Defines a function to create a new `stream` handle of the specified |
242 | /// type. |
243 | pub fn stream_new(&mut self, ty: u32) -> &mut Self { |
244 | self.bytes.push(0x0e); |
245 | ty.encode(&mut self.bytes); |
246 | self.num_added += 1; |
247 | self |
248 | } |
249 | |
250 | /// Defines a function to read from a `stream` of the specified type. |
251 | pub fn stream_read<O>(&mut self, ty: u32, options: O) -> &mut Self |
252 | where |
253 | O: IntoIterator<Item = CanonicalOption>, |
254 | O::IntoIter: ExactSizeIterator, |
255 | { |
256 | self.bytes.push(0x0f); |
257 | ty.encode(&mut self.bytes); |
258 | let options = options.into_iter(); |
259 | options.len().encode(&mut self.bytes); |
260 | for option in options { |
261 | option.encode(&mut self.bytes); |
262 | } |
263 | self.num_added += 1; |
264 | self |
265 | } |
266 | |
267 | /// Defines a function to write to a `stream` of the specified type. |
268 | pub fn stream_write<O>(&mut self, ty: u32, options: O) -> &mut Self |
269 | where |
270 | O: IntoIterator<Item = CanonicalOption>, |
271 | O::IntoIter: ExactSizeIterator, |
272 | { |
273 | self.bytes.push(0x10); |
274 | ty.encode(&mut self.bytes); |
275 | let options = options.into_iter(); |
276 | options.len().encode(&mut self.bytes); |
277 | for option in options { |
278 | option.encode(&mut self.bytes); |
279 | } |
280 | self.num_added += 1; |
281 | self |
282 | } |
283 | |
284 | /// Defines a function to cancel an in-progress read from a `stream` of the |
285 | /// specified type. |
286 | pub fn stream_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self { |
287 | self.bytes.push(0x11); |
288 | ty.encode(&mut self.bytes); |
289 | self.bytes.push(if async_ { 1 } else { 0 }); |
290 | self.num_added += 1; |
291 | self |
292 | } |
293 | |
294 | /// Defines a function to cancel an in-progress write to a `stream` of the |
295 | /// specified type. |
296 | pub fn stream_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self { |
297 | self.bytes.push(0x12); |
298 | ty.encode(&mut self.bytes); |
299 | self.bytes.push(if async_ { 1 } else { 0 }); |
300 | self.num_added += 1; |
301 | self |
302 | } |
303 | |
304 | /// Defines a function to close the readable end of a `stream` of the |
305 | /// specified type. |
306 | pub fn stream_close_readable(&mut self, ty: u32) -> &mut Self { |
307 | self.bytes.push(0x13); |
308 | ty.encode(&mut self.bytes); |
309 | self.num_added += 1; |
310 | self |
311 | } |
312 | |
313 | /// Defines a function to close the writable end of a `stream` of the |
314 | /// specified type. |
315 | pub fn stream_close_writable(&mut self, ty: u32) -> &mut Self { |
316 | self.bytes.push(0x14); |
317 | ty.encode(&mut self.bytes); |
318 | self.num_added += 1; |
319 | self |
320 | } |
321 | |
322 | /// Defines a function to create a new `future` handle of the specified |
323 | /// type. |
324 | pub fn future_new(&mut self, ty: u32) -> &mut Self { |
325 | self.bytes.push(0x15); |
326 | ty.encode(&mut self.bytes); |
327 | self.num_added += 1; |
328 | self |
329 | } |
330 | |
331 | /// Defines a function to read from a `future` of the specified type. |
332 | pub fn future_read<O>(&mut self, ty: u32, options: O) -> &mut Self |
333 | where |
334 | O: IntoIterator<Item = CanonicalOption>, |
335 | O::IntoIter: ExactSizeIterator, |
336 | { |
337 | self.bytes.push(0x16); |
338 | ty.encode(&mut self.bytes); |
339 | let options = options.into_iter(); |
340 | options.len().encode(&mut self.bytes); |
341 | for option in options { |
342 | option.encode(&mut self.bytes); |
343 | } |
344 | self.num_added += 1; |
345 | self |
346 | } |
347 | |
348 | /// Defines a function to write to a `future` of the specified type. |
349 | pub fn future_write<O>(&mut self, ty: u32, options: O) -> &mut Self |
350 | where |
351 | O: IntoIterator<Item = CanonicalOption>, |
352 | O::IntoIter: ExactSizeIterator, |
353 | { |
354 | self.bytes.push(0x17); |
355 | ty.encode(&mut self.bytes); |
356 | let options = options.into_iter(); |
357 | options.len().encode(&mut self.bytes); |
358 | for option in options { |
359 | option.encode(&mut self.bytes); |
360 | } |
361 | self.num_added += 1; |
362 | self |
363 | } |
364 | |
365 | /// Defines a function to cancel an in-progress read from a `future` of the |
366 | /// specified type. |
367 | pub fn future_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self { |
368 | self.bytes.push(0x18); |
369 | ty.encode(&mut self.bytes); |
370 | self.bytes.push(if async_ { 1 } else { 0 }); |
371 | self.num_added += 1; |
372 | self |
373 | } |
374 | |
375 | /// Defines a function to cancel an in-progress write to a `future` of the |
376 | /// specified type. |
377 | pub fn future_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self { |
378 | self.bytes.push(0x19); |
379 | ty.encode(&mut self.bytes); |
380 | self.bytes.push(if async_ { 1 } else { 0 }); |
381 | self.num_added += 1; |
382 | self |
383 | } |
384 | |
385 | /// Defines a function to close the readable end of a `future` of the |
386 | /// specified type. |
387 | pub fn future_close_readable(&mut self, ty: u32) -> &mut Self { |
388 | self.bytes.push(0x1a); |
389 | ty.encode(&mut self.bytes); |
390 | self.num_added += 1; |
391 | self |
392 | } |
393 | |
394 | /// Defines a function to close the writable end of a `future` of the |
395 | /// specified type. |
396 | pub fn future_close_writable(&mut self, ty: u32) -> &mut Self { |
397 | self.bytes.push(0x1b); |
398 | ty.encode(&mut self.bytes); |
399 | self.num_added += 1; |
400 | self |
401 | } |
402 | |
403 | /// Defines a function to create a new `error-context` with a specified |
404 | /// debug message. |
405 | pub fn error_context_new<O>(&mut self, options: O) -> &mut Self |
406 | where |
407 | O: IntoIterator<Item = CanonicalOption>, |
408 | O::IntoIter: ExactSizeIterator, |
409 | { |
410 | self.bytes.push(0x1c); |
411 | let options = options.into_iter(); |
412 | options.len().encode(&mut self.bytes); |
413 | for option in options { |
414 | option.encode(&mut self.bytes); |
415 | } |
416 | self.num_added += 1; |
417 | self |
418 | } |
419 | |
420 | /// Defines a function to get the debug message for a specified |
421 | /// `error-context`. |
422 | /// |
423 | /// Note that the debug message might not necessarily match what was passed |
424 | /// to `error-context.new`. |
425 | pub fn error_context_debug_message<O>(&mut self, options: O) -> &mut Self |
426 | where |
427 | O: IntoIterator<Item = CanonicalOption>, |
428 | O::IntoIter: ExactSizeIterator, |
429 | { |
430 | self.bytes.push(0x1d); |
431 | let options = options.into_iter(); |
432 | options.len().encode(&mut self.bytes); |
433 | for option in options { |
434 | option.encode(&mut self.bytes); |
435 | } |
436 | self.num_added += 1; |
437 | self |
438 | } |
439 | |
440 | /// Defines a function to drop a specified `error-context`. |
441 | pub fn error_context_drop(&mut self) -> &mut Self { |
442 | self.bytes.push(0x1e); |
443 | self.num_added += 1; |
444 | self |
445 | } |
446 | } |
447 | |
448 | impl Encode for CanonicalFunctionSection { |
449 | fn encode(&self, sink: &mut Vec<u8>) { |
450 | encode_section(sink, self.num_added, &self.bytes); |
451 | } |
452 | } |
453 | |
454 | impl ComponentSection for CanonicalFunctionSection { |
455 | fn id(&self) -> u8 { |
456 | ComponentSectionId::CanonicalFunction.into() |
457 | } |
458 | } |
459 | |