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