wasm_encoder/component/
canonicals.rs

1use crate::{encode_section, ComponentSection, ComponentSectionId, ComponentValType, Encode};
2use alloc::vec::Vec;
3
4/// Represents options for canonical function definitions.
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub 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
32impl 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)]
77pub struct CanonicalFunctionSection {
78    bytes: Vec<u8>,
79    num_added: u32,
80}
81
82impl 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        self.bytes.push(0x00);
105        self.bytes.push(0x00);
106        core_func_index.encode(&mut self.bytes);
107        self.encode_options(options);
108        type_index.encode(&mut self.bytes);
109        self.num_added += 1;
110        self
111    }
112
113    /// Define a function that will lower a canonical ABI function to a core WebAssembly function.
114    pub fn lower<O>(&mut self, func_index: u32, options: O) -> &mut Self
115    where
116        O: IntoIterator<Item = CanonicalOption>,
117        O::IntoIter: ExactSizeIterator,
118    {
119        self.bytes.push(0x01);
120        self.bytes.push(0x00);
121        func_index.encode(&mut self.bytes);
122        self.encode_options(options);
123        self.num_added += 1;
124        self
125    }
126
127    /// Defines a function which will create an owned handle to the resource
128    /// specified by `ty_index`.
129    pub fn resource_new(&mut self, ty_index: u32) -> &mut Self {
130        self.bytes.push(0x02);
131        ty_index.encode(&mut self.bytes);
132        self.num_added += 1;
133        self
134    }
135
136    /// Defines a function which will drop the specified type of handle.
137    pub fn resource_drop(&mut self, ty_index: u32) -> &mut Self {
138        self.bytes.push(0x03);
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_async(&mut self, ty_index: u32) -> &mut Self {
146        self.bytes.push(0x07);
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 spawn a new thread by invoking a shared
162    /// function of type `ty_index`.
163    pub fn thread_spawn_ref(&mut self, ty_index: u32) -> &mut Self {
164        self.bytes.push(0x40);
165        ty_index.encode(&mut self.bytes);
166        self.num_added += 1;
167        self
168    }
169
170    /// Defines a function which will spawn a new thread by invoking a shared
171    /// function indirectly through a `funcref` table.
172    pub fn thread_spawn_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self {
173        self.bytes.push(0x41);
174        ty_index.encode(&mut self.bytes);
175        table_index.encode(&mut self.bytes);
176        self.num_added += 1;
177        self
178    }
179
180    /// Defines a function which will return the number of threads that can be
181    /// expected to execute concurrently.
182    pub fn thread_available_parallelism(&mut self) -> &mut Self {
183        self.bytes.push(0x42);
184        self.num_added += 1;
185        self
186    }
187
188    /// Defines a function which tells the host to enable or disable
189    /// backpressure for the caller's instance.  When backpressure is enabled,
190    /// the host must not start any new calls to that instance until
191    /// backpressure is disabled.
192    pub fn backpressure_set(&mut self) -> &mut Self {
193        self.bytes.push(0x08);
194        self.num_added += 1;
195        self
196    }
197
198    /// Defines a function which returns a result to the caller of a lifted
199    /// export function.  This allows the callee to continue executing after
200    /// returning a result.
201    pub fn task_return<O>(&mut self, ty: Option<ComponentValType>, options: O) -> &mut Self
202    where
203        O: IntoIterator<Item = CanonicalOption>,
204        O::IntoIter: ExactSizeIterator,
205    {
206        self.bytes.push(0x09);
207        crate::encode_resultlist(&mut self.bytes, ty);
208        self.encode_options(options);
209        self.num_added += 1;
210        self
211    }
212
213    /// Defines a function to acknowledge cancellation of the current task.
214    pub fn task_cancel(&mut self) -> &mut Self {
215        self.bytes.push(0x25);
216        self.num_added += 1;
217        self
218    }
219
220    /// Defines a new `context.get` intrinsic of the ith slot.
221    pub fn context_get(&mut self, i: u32) -> &mut Self {
222        self.bytes.push(0x0a);
223        self.bytes.push(0x7f);
224        i.encode(&mut self.bytes);
225        self.num_added += 1;
226        self
227    }
228
229    /// Defines a new `context.set` intrinsic of the ith slot.
230    pub fn context_set(&mut self, i: u32) -> &mut Self {
231        self.bytes.push(0x0b);
232        self.bytes.push(0x7f);
233        i.encode(&mut self.bytes);
234        self.num_added += 1;
235        self
236    }
237
238    /// Defines a function which yields control to the host so that other tasks
239    /// are able to make progress, if any.
240    ///
241    /// If `async_` is true, the caller instance may be reentered.
242    pub fn yield_(&mut self, async_: bool) -> &mut Self {
243        self.bytes.push(0x0c);
244        self.bytes.push(if async_ { 1 } else { 0 });
245        self.num_added += 1;
246        self
247    }
248
249    /// Defines a function to drop a specified task which has completed.
250    pub fn subtask_drop(&mut self) -> &mut Self {
251        self.bytes.push(0x0d);
252        self.num_added += 1;
253        self
254    }
255
256    /// Defines a function to cancel an in-progress task.
257    pub fn subtask_cancel(&mut self, async_: bool) -> &mut Self {
258        self.bytes.push(0x24);
259        self.bytes.push(if async_ { 1 } else { 0 });
260        self.num_added += 1;
261        self
262    }
263
264    /// Defines a function to create a new `stream` handle of the specified
265    /// type.
266    pub fn stream_new(&mut self, ty: u32) -> &mut Self {
267        self.bytes.push(0x0e);
268        ty.encode(&mut self.bytes);
269        self.num_added += 1;
270        self
271    }
272
273    /// Defines a function to read from a `stream` of the specified type.
274    pub fn stream_read<O>(&mut self, ty: u32, options: O) -> &mut Self
275    where
276        O: IntoIterator<Item = CanonicalOption>,
277        O::IntoIter: ExactSizeIterator,
278    {
279        self.bytes.push(0x0f);
280        ty.encode(&mut self.bytes);
281        self.encode_options(options);
282        self.num_added += 1;
283        self
284    }
285
286    /// Defines a function to write to a `stream` of the specified type.
287    pub fn stream_write<O>(&mut self, ty: u32, options: O) -> &mut Self
288    where
289        O: IntoIterator<Item = CanonicalOption>,
290        O::IntoIter: ExactSizeIterator,
291    {
292        self.bytes.push(0x10);
293        ty.encode(&mut self.bytes);
294        self.encode_options(options);
295        self.num_added += 1;
296        self
297    }
298
299    /// Defines a function to cancel an in-progress read from a `stream` of the
300    /// specified type.
301    pub fn stream_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
302        self.bytes.push(0x11);
303        ty.encode(&mut self.bytes);
304        self.bytes.push(if async_ { 1 } else { 0 });
305        self.num_added += 1;
306        self
307    }
308
309    /// Defines a function to cancel an in-progress write to a `stream` of the
310    /// specified type.
311    pub fn stream_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
312        self.bytes.push(0x12);
313        ty.encode(&mut self.bytes);
314        self.bytes.push(if async_ { 1 } else { 0 });
315        self.num_added += 1;
316        self
317    }
318
319    /// Defines a function to close the readable end of a `stream` of the
320    /// specified type.
321    pub fn stream_close_readable(&mut self, ty: u32) -> &mut Self {
322        self.bytes.push(0x13);
323        ty.encode(&mut self.bytes);
324        self.num_added += 1;
325        self
326    }
327
328    /// Defines a function to close the writable end of a `stream` of the
329    /// specified type.
330    pub fn stream_close_writable(&mut self, ty: u32) -> &mut Self {
331        self.bytes.push(0x14);
332        ty.encode(&mut self.bytes);
333        self.num_added += 1;
334        self
335    }
336
337    /// Defines a function to create a new `future` handle of the specified
338    /// type.
339    pub fn future_new(&mut self, ty: u32) -> &mut Self {
340        self.bytes.push(0x15);
341        ty.encode(&mut self.bytes);
342        self.num_added += 1;
343        self
344    }
345
346    /// Defines a function to read from a `future` of the specified type.
347    pub fn future_read<O>(&mut self, ty: u32, options: O) -> &mut Self
348    where
349        O: IntoIterator<Item = CanonicalOption>,
350        O::IntoIter: ExactSizeIterator,
351    {
352        self.bytes.push(0x16);
353        ty.encode(&mut self.bytes);
354        self.encode_options(options);
355        self.num_added += 1;
356        self
357    }
358
359    /// Defines a function to write to a `future` of the specified type.
360    pub fn future_write<O>(&mut self, ty: u32, options: O) -> &mut Self
361    where
362        O: IntoIterator<Item = CanonicalOption>,
363        O::IntoIter: ExactSizeIterator,
364    {
365        self.bytes.push(0x17);
366        ty.encode(&mut self.bytes);
367        self.encode_options(options);
368        self.num_added += 1;
369        self
370    }
371
372    /// Defines a function to cancel an in-progress read from a `future` of the
373    /// specified type.
374    pub fn future_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
375        self.bytes.push(0x18);
376        ty.encode(&mut self.bytes);
377        self.bytes.push(if async_ { 1 } else { 0 });
378        self.num_added += 1;
379        self
380    }
381
382    /// Defines a function to cancel an in-progress write to a `future` of the
383    /// specified type.
384    pub fn future_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
385        self.bytes.push(0x19);
386        ty.encode(&mut self.bytes);
387        self.bytes.push(if async_ { 1 } else { 0 });
388        self.num_added += 1;
389        self
390    }
391
392    /// Defines a function to close the readable end of a `future` of the
393    /// specified type.
394    pub fn future_close_readable(&mut self, ty: u32) -> &mut Self {
395        self.bytes.push(0x1a);
396        ty.encode(&mut self.bytes);
397        self.num_added += 1;
398        self
399    }
400
401    /// Defines a function to close the writable end of a `future` of the
402    /// specified type.
403    pub fn future_close_writable(&mut self, ty: u32) -> &mut Self {
404        self.bytes.push(0x1b);
405        ty.encode(&mut self.bytes);
406        self.num_added += 1;
407        self
408    }
409
410    /// Defines a function to create a new `error-context` with a specified
411    /// debug message.
412    pub fn error_context_new<O>(&mut self, options: O) -> &mut Self
413    where
414        O: IntoIterator<Item = CanonicalOption>,
415        O::IntoIter: ExactSizeIterator,
416    {
417        self.bytes.push(0x1c);
418        self.encode_options(options);
419        self.num_added += 1;
420        self
421    }
422
423    /// Defines a function to get the debug message for a specified
424    /// `error-context`.
425    ///
426    /// Note that the debug message might not necessarily match what was passed
427    /// to `error-context.new`.
428    pub fn error_context_debug_message<O>(&mut self, options: O) -> &mut Self
429    where
430        O: IntoIterator<Item = CanonicalOption>,
431        O::IntoIter: ExactSizeIterator,
432    {
433        self.bytes.push(0x1d);
434        self.encode_options(options);
435        self.num_added += 1;
436        self
437    }
438
439    /// Defines a function to drop a specified `error-context`.
440    pub fn error_context_drop(&mut self) -> &mut Self {
441        self.bytes.push(0x1e);
442        self.num_added += 1;
443        self
444    }
445
446    /// Declare a new `waitable-set.new` intrinsic, used to create a
447    /// `waitable-set` pseudo-resource.
448    pub fn waitable_set_new(&mut self) -> &mut Self {
449        self.bytes.push(0x1f);
450        self.num_added += 1;
451        self
452    }
453
454    /// Declare a new `waitable-set.wait` intrinsic, used to block on a
455    /// `waitable-set`.
456    pub fn waitable_set_wait(&mut self, async_: bool, memory: u32) -> &mut Self {
457        self.bytes.push(0x20);
458        self.bytes.push(if async_ { 1 } else { 0 });
459        memory.encode(&mut self.bytes);
460        self.num_added += 1;
461        self
462    }
463
464    /// Declare a new `waitable-set.wait` intrinsic, used to check, without
465    /// blocking, if anything in a `waitable-set` is ready.
466    pub fn waitable_set_poll(&mut self, async_: bool, memory: u32) -> &mut Self {
467        self.bytes.push(0x21);
468        self.bytes.push(if async_ { 1 } else { 0 });
469        memory.encode(&mut self.bytes);
470        self.num_added += 1;
471        self
472    }
473
474    /// Declare a new `waitable-set.drop` intrinsic, used to dispose a
475    /// `waitable-set` pseudo-resource.
476    pub fn waitable_set_drop(&mut self) -> &mut Self {
477        self.bytes.push(0x22);
478        self.num_added += 1;
479        self
480    }
481
482    /// Declare a new `waitable.join` intrinsic, used to add an item to a
483    /// `waitable-set`.
484    pub fn waitable_join(&mut self) -> &mut Self {
485        self.bytes.push(0x23);
486        self.num_added += 1;
487        self
488    }
489
490    fn encode_options<O>(&mut self, options: O) -> &mut Self
491    where
492        O: IntoIterator<Item = CanonicalOption>,
493        O::IntoIter: ExactSizeIterator,
494    {
495        let options = options.into_iter();
496        options.len().encode(&mut self.bytes);
497        for option in options {
498            option.encode(&mut self.bytes);
499        }
500        self
501    }
502}
503
504impl Encode for CanonicalFunctionSection {
505    fn encode(&self, sink: &mut Vec<u8>) {
506        encode_section(sink, self.num_added, &self.bytes);
507    }
508}
509
510impl ComponentSection for CanonicalFunctionSection {
511    fn id(&self) -> u8 {
512        ComponentSectionId::CanonicalFunction.into()
513    }
514}