Skip to main content

wasm_encoder/component/
canonicals.rs

1use crate::{
2    ComponentSection, ComponentSectionId, ComponentValType, Encode, ValType, encode_section,
3};
4use alloc::vec::Vec;
5
6/// Represents options for canonical function definitions.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum CanonicalOption {
9    /// The string types in the function signature are UTF-8 encoded.
10    UTF8,
11    /// The string types in the function signature are UTF-16 encoded.
12    UTF16,
13    /// The string types in the function signature are compact UTF-16 encoded.
14    CompactUTF16,
15    /// The memory to use if the lifting or lowering of a function requires memory access.
16    ///
17    /// The value is an index to a core memory.
18    Memory(u32),
19    /// The realloc function to use if the lifting or lowering of a function requires memory
20    /// allocation.
21    ///
22    /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`.
23    Realloc(u32),
24    /// The post-return function to use if the lifting of a function requires
25    /// cleanup after the function returns.
26    PostReturn(u32),
27    /// Indicates that specified function should be lifted or lowered using the `async` ABI.
28    Async,
29    /// The function to use if the async lifting of a function should receive task/stream/future progress events
30    /// using a callback.
31    Callback(u32),
32    /// The core function type to lower a component function into.
33    CoreType(u32),
34    /// Use the GC variant of the canonical ABI.
35    Gc,
36}
37
38impl Encode for CanonicalOption {
39    fn encode(&self, sink: &mut Vec<u8>) {
40        match self {
41            Self::UTF8 => sink.push(0x00),
42            Self::UTF16 => sink.push(0x01),
43            Self::CompactUTF16 => sink.push(0x02),
44            Self::Memory(idx) => {
45                sink.push(0x03);
46                idx.encode(sink);
47            }
48            Self::Realloc(idx) => {
49                sink.push(0x04);
50                idx.encode(sink);
51            }
52            Self::PostReturn(idx) => {
53                sink.push(0x05);
54                idx.encode(sink);
55            }
56            Self::Async => {
57                sink.push(0x06);
58            }
59            Self::Callback(idx) => {
60                sink.push(0x07);
61                idx.encode(sink);
62            }
63            Self::CoreType(idx) => {
64                sink.push(0x08);
65                idx.encode(sink);
66            }
67            Self::Gc => {
68                sink.push(0x09);
69            }
70        }
71    }
72}
73
74/// An encoder for the canonical function section of WebAssembly components.
75///
76/// # Example
77///
78/// ```
79/// use wasm_encoder::{Component, CanonicalFunctionSection, CanonicalOption};
80///
81/// let mut functions = CanonicalFunctionSection::new();
82/// functions.lift(0, 0, [CanonicalOption::UTF8]);
83///
84/// let mut component = Component::new();
85/// component.section(&functions);
86///
87/// let bytes = component.finish();
88/// ```
89#[derive(Clone, Debug, Default)]
90pub struct CanonicalFunctionSection {
91    bytes: Vec<u8>,
92    num_added: u32,
93}
94
95impl CanonicalFunctionSection {
96    /// Construct a new component function section encoder.
97    pub fn new() -> Self {
98        Self::default()
99    }
100
101    /// The number of functions in the section.
102    pub fn len(&self) -> u32 {
103        self.num_added
104    }
105
106    /// Determines if the section is empty.
107    pub fn is_empty(&self) -> bool {
108        self.num_added == 0
109    }
110
111    /// Define a function that will lift a core WebAssembly function to the canonical ABI.
112    pub fn lift<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> &mut Self
113    where
114        O: IntoIterator<Item = CanonicalOption>,
115        O::IntoIter: ExactSizeIterator,
116    {
117        self.bytes.push(0x00);
118        self.bytes.push(0x00);
119        core_func_index.encode(&mut self.bytes);
120        self.encode_options(options);
121        type_index.encode(&mut self.bytes);
122        self.num_added += 1;
123        self
124    }
125
126    /// Define a function that will lower a canonical ABI function to a core WebAssembly function.
127    pub fn lower<O>(&mut self, func_index: u32, options: O) -> &mut Self
128    where
129        O: IntoIterator<Item = CanonicalOption>,
130        O::IntoIter: ExactSizeIterator,
131    {
132        self.bytes.push(0x01);
133        self.bytes.push(0x00);
134        func_index.encode(&mut self.bytes);
135        self.encode_options(options);
136        self.num_added += 1;
137        self
138    }
139
140    /// Defines a function which will create an owned handle to the resource
141    /// specified by `ty_index`.
142    pub fn resource_new(&mut self, ty_index: u32) -> &mut Self {
143        self.bytes.push(0x02);
144        ty_index.encode(&mut self.bytes);
145        self.num_added += 1;
146        self
147    }
148
149    /// Defines a function which will drop the specified type of handle.
150    pub fn resource_drop(&mut self, ty_index: u32) -> &mut Self {
151        self.bytes.push(0x03);
152        ty_index.encode(&mut self.bytes);
153        self.num_added += 1;
154        self
155    }
156
157    /// Defines a function which will drop the specified type of handle.
158    pub fn resource_drop_async(&mut self, ty_index: u32) -> &mut Self {
159        self.bytes.push(0x07);
160        ty_index.encode(&mut self.bytes);
161        self.num_added += 1;
162        self
163    }
164
165    /// Defines a function which will return the representation of the specified
166    /// resource type.
167    pub fn resource_rep(&mut self, ty_index: u32) -> &mut Self {
168        self.bytes.push(0x04);
169        ty_index.encode(&mut self.bytes);
170        self.num_added += 1;
171        self
172    }
173
174    /// Defines a function which will spawn a new thread by invoking a shared
175    /// function of type `ty_index`.
176    pub fn thread_spawn_ref(&mut self, ty_index: u32) -> &mut Self {
177        self.bytes.push(0x40);
178        ty_index.encode(&mut self.bytes);
179        self.num_added += 1;
180        self
181    }
182
183    /// Defines a function which will spawn a new thread by invoking a shared
184    /// function indirectly through a `funcref` table.
185    pub fn thread_spawn_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self {
186        self.bytes.push(0x41);
187        ty_index.encode(&mut self.bytes);
188        table_index.encode(&mut self.bytes);
189        self.num_added += 1;
190        self
191    }
192
193    /// Defines a function which will return the number of threads that can be
194    /// expected to execute concurrently.
195    pub fn thread_available_parallelism(&mut self) -> &mut Self {
196        self.bytes.push(0x42);
197        self.num_added += 1;
198        self
199    }
200
201    /// Defines a function which tells the host to increment the backpressure
202    /// counter.
203    pub fn backpressure_inc(&mut self) -> &mut Self {
204        self.bytes.push(0x24);
205        self.num_added += 1;
206        self
207    }
208
209    /// Defines a function which tells the host to decrement the backpressure
210    /// counter.
211    pub fn backpressure_dec(&mut self) -> &mut Self {
212        self.bytes.push(0x25);
213        self.num_added += 1;
214        self
215    }
216
217    /// Defines a function which returns a result to the caller of a lifted
218    /// export function.  This allows the callee to continue executing after
219    /// returning a result.
220    pub fn task_return<O>(&mut self, ty: Option<ComponentValType>, options: O) -> &mut Self
221    where
222        O: IntoIterator<Item = CanonicalOption>,
223        O::IntoIter: ExactSizeIterator,
224    {
225        self.bytes.push(0x09);
226        crate::encode_resultlist(&mut self.bytes, ty);
227        self.encode_options(options);
228        self.num_added += 1;
229        self
230    }
231
232    /// Defines a function to acknowledge cancellation of the current task.
233    pub fn task_cancel(&mut self) -> &mut Self {
234        self.bytes.push(0x05);
235        self.num_added += 1;
236        self
237    }
238
239    /// Defines a new `context.get` intrinsic of the ith slot with the given
240    /// value type.
241    pub fn context_get(&mut self, ty: ValType, i: u32) -> &mut Self {
242        self.bytes.push(0x0a);
243        ty.encode(&mut self.bytes);
244        i.encode(&mut self.bytes);
245        self.num_added += 1;
246        self
247    }
248
249    /// Defines a new `context.set` intrinsic of the ith slot with the given
250    /// value type.
251    pub fn context_set(&mut self, ty: ValType, i: u32) -> &mut Self {
252        self.bytes.push(0x0b);
253        ty.encode(&mut self.bytes);
254        i.encode(&mut self.bytes);
255        self.num_added += 1;
256        self
257    }
258
259    /// Defines a function which yields control to the host so that other tasks
260    /// are able to make progress, if any.
261    ///
262    /// If `cancellable` is true, the caller instance may be reentered.
263    pub fn thread_yield(&mut self, cancellable: bool) -> &mut Self {
264        self.bytes.push(0x0c);
265        self.bytes.push(if cancellable { 1 } else { 0 });
266        self.num_added += 1;
267        self
268    }
269
270    /// Defines a function to drop a specified task which has completed.
271    pub fn subtask_drop(&mut self) -> &mut Self {
272        self.bytes.push(0x0d);
273        self.num_added += 1;
274        self
275    }
276
277    /// Defines a function to cancel an in-progress task.
278    pub fn subtask_cancel(&mut self, async_: bool) -> &mut Self {
279        self.bytes.push(0x06);
280        self.bytes.push(if async_ { 1 } else { 0 });
281        self.num_added += 1;
282        self
283    }
284
285    /// Defines a function to create a new `stream` handle of the specified
286    /// type.
287    pub fn stream_new(&mut self, ty: u32) -> &mut Self {
288        self.bytes.push(0x0e);
289        ty.encode(&mut self.bytes);
290        self.num_added += 1;
291        self
292    }
293
294    /// Defines a function to read from a `stream` of the specified type.
295    pub fn stream_read<O>(&mut self, ty: u32, options: O) -> &mut Self
296    where
297        O: IntoIterator<Item = CanonicalOption>,
298        O::IntoIter: ExactSizeIterator,
299    {
300        self.bytes.push(0x0f);
301        ty.encode(&mut self.bytes);
302        self.encode_options(options);
303        self.num_added += 1;
304        self
305    }
306
307    /// Defines a function to write to a `stream` of the specified type.
308    pub fn stream_write<O>(&mut self, ty: u32, options: O) -> &mut Self
309    where
310        O: IntoIterator<Item = CanonicalOption>,
311        O::IntoIter: ExactSizeIterator,
312    {
313        self.bytes.push(0x10);
314        ty.encode(&mut self.bytes);
315        self.encode_options(options);
316        self.num_added += 1;
317        self
318    }
319
320    /// Defines a function to cancel an in-progress read from a `stream` of the
321    /// specified type.
322    pub fn stream_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
323        self.bytes.push(0x11);
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 cancel an in-progress write to a `stream` of the
331    /// specified type.
332    pub fn stream_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
333        self.bytes.push(0x12);
334        ty.encode(&mut self.bytes);
335        self.bytes.push(if async_ { 1 } else { 0 });
336        self.num_added += 1;
337        self
338    }
339
340    /// Defines a function to drop the readable end of a `stream` of the
341    /// specified type.
342    pub fn stream_drop_readable(&mut self, ty: u32) -> &mut Self {
343        self.bytes.push(0x13);
344        ty.encode(&mut self.bytes);
345        self.num_added += 1;
346        self
347    }
348
349    /// Defines a function to drop the writable end of a `stream` of the
350    /// specified type.
351    pub fn stream_drop_writable(&mut self, ty: u32) -> &mut Self {
352        self.bytes.push(0x14);
353        ty.encode(&mut self.bytes);
354        self.num_added += 1;
355        self
356    }
357
358    /// Defines a function to create a new `future` handle of the specified
359    /// type.
360    pub fn future_new(&mut self, ty: u32) -> &mut Self {
361        self.bytes.push(0x15);
362        ty.encode(&mut self.bytes);
363        self.num_added += 1;
364        self
365    }
366
367    /// Defines a function to read from a `future` of the specified type.
368    pub fn future_read<O>(&mut self, ty: u32, options: O) -> &mut Self
369    where
370        O: IntoIterator<Item = CanonicalOption>,
371        O::IntoIter: ExactSizeIterator,
372    {
373        self.bytes.push(0x16);
374        ty.encode(&mut self.bytes);
375        self.encode_options(options);
376        self.num_added += 1;
377        self
378    }
379
380    /// Defines a function to write to a `future` of the specified type.
381    pub fn future_write<O>(&mut self, ty: u32, options: O) -> &mut Self
382    where
383        O: IntoIterator<Item = CanonicalOption>,
384        O::IntoIter: ExactSizeIterator,
385    {
386        self.bytes.push(0x17);
387        ty.encode(&mut self.bytes);
388        self.encode_options(options);
389        self.num_added += 1;
390        self
391    }
392
393    /// Defines a function to cancel an in-progress read from a `future` of the
394    /// specified type.
395    pub fn future_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
396        self.bytes.push(0x18);
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 cancel an in-progress write to a `future` of the
404    /// specified type.
405    pub fn future_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
406        self.bytes.push(0x19);
407        ty.encode(&mut self.bytes);
408        self.bytes.push(if async_ { 1 } else { 0 });
409        self.num_added += 1;
410        self
411    }
412
413    /// Defines a function to drop the readable end of a `future` of the
414    /// specified type.
415    pub fn future_drop_readable(&mut self, ty: u32) -> &mut Self {
416        self.bytes.push(0x1a);
417        ty.encode(&mut self.bytes);
418        self.num_added += 1;
419        self
420    }
421
422    /// Defines a function to drop the writable end of a `future` of the
423    /// specified type.
424    pub fn future_drop_writable(&mut self, ty: u32) -> &mut Self {
425        self.bytes.push(0x1b);
426        ty.encode(&mut self.bytes);
427        self.num_added += 1;
428        self
429    }
430
431    /// Defines a function to create a new `error-context` with a specified
432    /// debug message.
433    pub fn error_context_new<O>(&mut self, options: O) -> &mut Self
434    where
435        O: IntoIterator<Item = CanonicalOption>,
436        O::IntoIter: ExactSizeIterator,
437    {
438        self.bytes.push(0x1c);
439        self.encode_options(options);
440        self.num_added += 1;
441        self
442    }
443
444    /// Defines a function to get the debug message for a specified
445    /// `error-context`.
446    ///
447    /// Note that the debug message might not necessarily match what was passed
448    /// to `error-context.new`.
449    pub fn error_context_debug_message<O>(&mut self, options: O) -> &mut Self
450    where
451        O: IntoIterator<Item = CanonicalOption>,
452        O::IntoIter: ExactSizeIterator,
453    {
454        self.bytes.push(0x1d);
455        self.encode_options(options);
456        self.num_added += 1;
457        self
458    }
459
460    /// Defines a function to drop a specified `error-context`.
461    pub fn error_context_drop(&mut self) -> &mut Self {
462        self.bytes.push(0x1e);
463        self.num_added += 1;
464        self
465    }
466
467    /// Declare a new `waitable-set.new` intrinsic, used to create a
468    /// `waitable-set` pseudo-resource.
469    pub fn waitable_set_new(&mut self) -> &mut Self {
470        self.bytes.push(0x1f);
471        self.num_added += 1;
472        self
473    }
474
475    /// Declare a new `waitable-set.wait` intrinsic, used to block on a
476    /// `waitable-set`.
477    pub fn waitable_set_wait(&mut self, async_: bool, memory: u32) -> &mut Self {
478        self.bytes.push(0x20);
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.wait` intrinsic, used to check, without
486    /// blocking, if anything in a `waitable-set` is ready.
487    pub fn waitable_set_poll(&mut self, async_: bool, memory: u32) -> &mut Self {
488        self.bytes.push(0x21);
489        self.bytes.push(if async_ { 1 } else { 0 });
490        memory.encode(&mut self.bytes);
491        self.num_added += 1;
492        self
493    }
494
495    /// Declare a new `waitable-set.drop` intrinsic, used to dispose a
496    /// `waitable-set` pseudo-resource.
497    pub fn waitable_set_drop(&mut self) -> &mut Self {
498        self.bytes.push(0x22);
499        self.num_added += 1;
500        self
501    }
502
503    /// Declare a new `waitable.join` intrinsic, used to add an item to a
504    /// `waitable-set`.
505    pub fn waitable_join(&mut self) -> &mut Self {
506        self.bytes.push(0x23);
507        self.num_added += 1;
508        self
509    }
510
511    /// Declare a new `thread.index` intrinsic, used to get the index of the
512    /// current thread.
513    pub fn thread_index(&mut self) -> &mut Self {
514        self.bytes.push(0x26);
515        self.num_added += 1;
516        self
517    }
518
519    /// Declare a new `thread.new-indirect` intrinsic, used to create a new
520    /// thread by invoking a function indirectly through a `funcref` table.
521    pub fn thread_new_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self {
522        self.bytes.push(0x27);
523        ty_index.encode(&mut self.bytes);
524        table_index.encode(&mut self.bytes);
525        self.num_added += 1;
526        self
527    }
528
529    /// Declare a new `thread.suspend-to-suspended` intrinsic, used to switch execution to
530    /// another suspended thread.
531    pub fn thread_suspend_to_suspended(&mut self, cancellable: bool) -> &mut Self {
532        self.bytes.push(0x28);
533        self.bytes.push(if cancellable { 1 } else { 0 });
534        self.num_added += 1;
535        self
536    }
537
538    /// Declare a new `thread.suspend` intrinsic, used to suspend execution of
539    /// the current thread.
540    pub fn thread_suspend(&mut self, cancellable: bool) -> &mut Self {
541        self.bytes.push(0x29);
542        self.bytes.push(if cancellable { 1 } else { 0 });
543        self.num_added += 1;
544        self
545    }
546
547    /// Declare a new `thread.suspend-to` intrinsic, used to suspend the current
548    /// thread and switch to another thread that might not be suspended.
549    pub fn thread_suspend_to(&mut self, cancellable: bool) -> &mut Self {
550        self.bytes.push(0x2c);
551        self.bytes.push(if cancellable { 1 } else { 0 });
552        self.num_added += 1;
553        self
554    }
555
556    /// Declare a new `thread.unsuspend` intrinsic, used to resume execution
557    /// of the given thread.
558    pub fn thread_unsuspend(&mut self) -> &mut Self {
559        self.bytes.push(0x2a);
560        self.num_added += 1;
561        self
562    }
563
564    /// Declare a new `thread.yield-to-suspended` intrinsic, used to yield execution to
565    /// a given suspended thread.
566    pub fn thread_yield_to_suspended(&mut self, cancellable: bool) -> &mut Self {
567        self.bytes.push(0x2b);
568        self.bytes.push(if cancellable { 1 } else { 0 });
569        self.num_added += 1;
570        self
571    }
572
573    fn encode_options<O>(&mut self, options: O) -> &mut Self
574    where
575        O: IntoIterator<Item = CanonicalOption>,
576        O::IntoIter: ExactSizeIterator,
577    {
578        let options = options.into_iter();
579        options.len().encode(&mut self.bytes);
580        for option in options {
581            option.encode(&mut self.bytes);
582        }
583        self
584    }
585}
586
587impl Encode for CanonicalFunctionSection {
588    fn encode(&self, sink: &mut Vec<u8>) {
589        encode_section(sink, self.num_added, &self.bytes);
590    }
591}
592
593impl ComponentSection for CanonicalFunctionSection {
594    fn id(&self) -> u8 {
595        ComponentSectionId::CanonicalFunction.into()
596    }
597}