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 return the representation of the specified
158    /// resource type.
159    pub fn resource_rep(&mut self, ty_index: u32) -> &mut Self {
160        self.bytes.push(0x04);
161        ty_index.encode(&mut self.bytes);
162        self.num_added += 1;
163        self
164    }
165
166    /// Defines a function which will spawn a new thread by invoking a shared
167    /// function of type `ty_index`.
168    pub fn thread_spawn_ref(&mut self, ty_index: u32) -> &mut Self {
169        self.bytes.push(0x40);
170        ty_index.encode(&mut self.bytes);
171        self.num_added += 1;
172        self
173    }
174
175    /// Defines a function which will spawn a new thread by invoking a shared
176    /// function indirectly through a `funcref` table.
177    pub fn thread_spawn_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self {
178        self.bytes.push(0x41);
179        ty_index.encode(&mut self.bytes);
180        table_index.encode(&mut self.bytes);
181        self.num_added += 1;
182        self
183    }
184
185    /// Defines a function which will return the number of threads that can be
186    /// expected to execute concurrently.
187    pub fn thread_available_parallelism(&mut self) -> &mut Self {
188        self.bytes.push(0x42);
189        self.num_added += 1;
190        self
191    }
192
193    /// Defines a function which tells the host to increment the backpressure
194    /// counter.
195    pub fn backpressure_inc(&mut self) -> &mut Self {
196        self.bytes.push(0x24);
197        self.num_added += 1;
198        self
199    }
200
201    /// Defines a function which tells the host to decrement the backpressure
202    /// counter.
203    pub fn backpressure_dec(&mut self) -> &mut Self {
204        self.bytes.push(0x25);
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 with the given
232    /// value type.
233    pub fn context_get(&mut self, ty: ValType, i: u32) -> &mut Self {
234        self.bytes.push(0x0a);
235        ty.encode(&mut self.bytes);
236        i.encode(&mut self.bytes);
237        self.num_added += 1;
238        self
239    }
240
241    /// Defines a new `context.set` intrinsic of the ith slot with the given
242    /// value type.
243    pub fn context_set(&mut self, ty: ValType, i: u32) -> &mut Self {
244        self.bytes.push(0x0b);
245        ty.encode(&mut self.bytes);
246        i.encode(&mut self.bytes);
247        self.num_added += 1;
248        self
249    }
250
251    /// Defines a function to drop a specified task which has completed.
252    pub fn subtask_drop(&mut self) -> &mut Self {
253        self.bytes.push(0x0d);
254        self.num_added += 1;
255        self
256    }
257
258    /// Defines a function to cancel an in-progress task.
259    pub fn subtask_cancel(&mut self, async_: bool) -> &mut Self {
260        self.bytes.push(0x06);
261        self.bytes.push(if async_ { 1 } else { 0 });
262        self.num_added += 1;
263        self
264    }
265
266    /// Defines a function to create a new `stream` handle of the specified
267    /// type.
268    pub fn stream_new(&mut self, ty: u32) -> &mut Self {
269        self.bytes.push(0x0e);
270        ty.encode(&mut self.bytes);
271        self.num_added += 1;
272        self
273    }
274
275    /// Defines a function to read from a `stream` of the specified type.
276    pub fn stream_read<O>(&mut self, ty: u32, options: O) -> &mut Self
277    where
278        O: IntoIterator<Item = CanonicalOption>,
279        O::IntoIter: ExactSizeIterator,
280    {
281        self.bytes.push(0x0f);
282        ty.encode(&mut self.bytes);
283        self.encode_options(options);
284        self.num_added += 1;
285        self
286    }
287
288    /// Defines a function to write to a `stream` of the specified type.
289    pub fn stream_write<O>(&mut self, ty: u32, options: O) -> &mut Self
290    where
291        O: IntoIterator<Item = CanonicalOption>,
292        O::IntoIter: ExactSizeIterator,
293    {
294        self.bytes.push(0x10);
295        ty.encode(&mut self.bytes);
296        self.encode_options(options);
297        self.num_added += 1;
298        self
299    }
300
301    /// Defines a function to cancel an in-progress read from a `stream` of the
302    /// specified type.
303    pub fn stream_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
304        self.bytes.push(0x11);
305        ty.encode(&mut self.bytes);
306        self.bytes.push(if async_ { 1 } else { 0 });
307        self.num_added += 1;
308        self
309    }
310
311    /// Defines a function to cancel an in-progress write to a `stream` of the
312    /// specified type.
313    pub fn stream_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
314        self.bytes.push(0x12);
315        ty.encode(&mut self.bytes);
316        self.bytes.push(if async_ { 1 } else { 0 });
317        self.num_added += 1;
318        self
319    }
320
321    /// Defines a function to drop the readable end of a `stream` of the
322    /// specified type.
323    pub fn stream_drop_readable(&mut self, ty: u32) -> &mut Self {
324        self.bytes.push(0x13);
325        ty.encode(&mut self.bytes);
326        self.num_added += 1;
327        self
328    }
329
330    /// Defines a function to drop the writable end of a `stream` of the
331    /// specified type.
332    pub fn stream_drop_writable(&mut self, ty: u32) -> &mut Self {
333        self.bytes.push(0x14);
334        ty.encode(&mut self.bytes);
335        self.num_added += 1;
336        self
337    }
338
339    /// Defines a function to create a new `future` handle of the specified
340    /// type.
341    pub fn future_new(&mut self, ty: u32) -> &mut Self {
342        self.bytes.push(0x15);
343        ty.encode(&mut self.bytes);
344        self.num_added += 1;
345        self
346    }
347
348    /// Defines a function to read from a `future` of the specified type.
349    pub fn future_read<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(0x16);
355        ty.encode(&mut self.bytes);
356        self.encode_options(options);
357        self.num_added += 1;
358        self
359    }
360
361    /// Defines a function to write to a `future` of the specified type.
362    pub fn future_write<O>(&mut self, ty: u32, options: O) -> &mut Self
363    where
364        O: IntoIterator<Item = CanonicalOption>,
365        O::IntoIter: ExactSizeIterator,
366    {
367        self.bytes.push(0x17);
368        ty.encode(&mut self.bytes);
369        self.encode_options(options);
370        self.num_added += 1;
371        self
372    }
373
374    /// Defines a function to cancel an in-progress read from a `future` of the
375    /// specified type.
376    pub fn future_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
377        self.bytes.push(0x18);
378        ty.encode(&mut self.bytes);
379        self.bytes.push(if async_ { 1 } else { 0 });
380        self.num_added += 1;
381        self
382    }
383
384    /// Defines a function to cancel an in-progress write to a `future` of the
385    /// specified type.
386    pub fn future_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
387        self.bytes.push(0x19);
388        ty.encode(&mut self.bytes);
389        self.bytes.push(if async_ { 1 } else { 0 });
390        self.num_added += 1;
391        self
392    }
393
394    /// Defines a function to drop the readable end of a `future` of the
395    /// specified type.
396    pub fn future_drop_readable(&mut self, ty: u32) -> &mut Self {
397        self.bytes.push(0x1a);
398        ty.encode(&mut self.bytes);
399        self.num_added += 1;
400        self
401    }
402
403    /// Defines a function to drop the writable end of a `future` of the
404    /// specified type.
405    pub fn future_drop_writable(&mut self, ty: u32) -> &mut Self {
406        self.bytes.push(0x1b);
407        ty.encode(&mut self.bytes);
408        self.num_added += 1;
409        self
410    }
411
412    /// Defines a function to create a new `error-context` with a specified
413    /// debug message.
414    pub fn error_context_new<O>(&mut self, options: O) -> &mut Self
415    where
416        O: IntoIterator<Item = CanonicalOption>,
417        O::IntoIter: ExactSizeIterator,
418    {
419        self.bytes.push(0x1c);
420        self.encode_options(options);
421        self.num_added += 1;
422        self
423    }
424
425    /// Defines a function to get the debug message for a specified
426    /// `error-context`.
427    ///
428    /// Note that the debug message might not necessarily match what was passed
429    /// to `error-context.new`.
430    pub fn error_context_debug_message<O>(&mut self, options: O) -> &mut Self
431    where
432        O: IntoIterator<Item = CanonicalOption>,
433        O::IntoIter: ExactSizeIterator,
434    {
435        self.bytes.push(0x1d);
436        self.encode_options(options);
437        self.num_added += 1;
438        self
439    }
440
441    /// Defines a function to drop a specified `error-context`.
442    pub fn error_context_drop(&mut self) -> &mut Self {
443        self.bytes.push(0x1e);
444        self.num_added += 1;
445        self
446    }
447
448    /// Declare a new `waitable-set.new` intrinsic, used to create a
449    /// `waitable-set` pseudo-resource.
450    pub fn waitable_set_new(&mut self) -> &mut Self {
451        self.bytes.push(0x1f);
452        self.num_added += 1;
453        self
454    }
455
456    /// Declare a new `waitable-set.wait` intrinsic, used to block on a
457    /// `waitable-set`.
458    pub fn waitable_set_wait(&mut self, async_: bool, memory: u32) -> &mut Self {
459        self.bytes.push(0x20);
460        self.bytes.push(if async_ { 1 } else { 0 });
461        memory.encode(&mut self.bytes);
462        self.num_added += 1;
463        self
464    }
465
466    /// Declare a new `waitable-set.wait` intrinsic, used to check, without
467    /// blocking, if anything in a `waitable-set` is ready.
468    pub fn waitable_set_poll(&mut self, async_: bool, memory: u32) -> &mut Self {
469        self.bytes.push(0x21);
470        self.bytes.push(if async_ { 1 } else { 0 });
471        memory.encode(&mut self.bytes);
472        self.num_added += 1;
473        self
474    }
475
476    /// Declare a new `waitable-set.drop` intrinsic, used to dispose a
477    /// `waitable-set` pseudo-resource.
478    pub fn waitable_set_drop(&mut self) -> &mut Self {
479        self.bytes.push(0x22);
480        self.num_added += 1;
481        self
482    }
483
484    /// Declare a new `waitable.join` intrinsic, used to add an item to a
485    /// `waitable-set`.
486    pub fn waitable_join(&mut self) -> &mut Self {
487        self.bytes.push(0x23);
488        self.num_added += 1;
489        self
490    }
491
492    /// Declare a new `thread.index` intrinsic, used to get the index of the
493    /// current thread.
494    pub fn thread_index(&mut self) -> &mut Self {
495        self.bytes.push(0x26);
496        self.num_added += 1;
497        self
498    }
499
500    /// Declare a new `thread.new-indirect` intrinsic, used to create a new
501    /// thread by invoking a function indirectly through a `funcref` table.
502    pub fn thread_new_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self {
503        self.bytes.push(0x27);
504        ty_index.encode(&mut self.bytes);
505        table_index.encode(&mut self.bytes);
506        self.num_added += 1;
507        self
508    }
509
510    /// Declare a new `thread.resume-later` intrinsic.
511    pub fn thread_resume_later(&mut self) -> &mut Self {
512        self.bytes.push(0x28);
513        self.num_added += 1;
514        self
515    }
516
517    /// Declare a new `thread.suspend` intrinsic.
518    pub fn thread_suspend(&mut self, cancellable: bool) -> &mut Self {
519        self.bytes.push(0x29);
520        self.bytes.push(if cancellable { 1 } else { 0 });
521        self.num_added += 1;
522        self
523    }
524
525    /// Declare a new `thread.yield` intrinsic.
526    pub fn thread_yield(&mut self, cancellable: bool) -> &mut Self {
527        self.bytes.push(0x0c);
528        self.bytes.push(if cancellable { 1 } else { 0 });
529        self.num_added += 1;
530        self
531    }
532
533    /// Declare a new `thread.suspend-then-resume` intrinsic.
534    pub fn thread_suspend_then_resume(&mut self, cancellable: bool) -> &mut Self {
535        self.bytes.push(0x2a);
536        self.bytes.push(if cancellable { 1 } else { 0 });
537        self.num_added += 1;
538        self
539    }
540
541    /// Declare a new `thread.yield-then-resume` intrinsic.
542    pub fn thread_yield_then_resume(&mut self, cancellable: bool) -> &mut Self {
543        self.bytes.push(0x2b);
544        self.bytes.push(if cancellable { 1 } else { 0 });
545        self.num_added += 1;
546        self
547    }
548
549    /// Declare a new `thread.suspend-then-promote` intrinsic.
550    pub fn thread_suspend_then_promote(&mut self, cancellable: bool) -> &mut Self {
551        self.bytes.push(0x2c);
552        self.bytes.push(if cancellable { 1 } else { 0 });
553        self.num_added += 1;
554        self
555    }
556
557    /// Declare a new `thread.yield-then-promote` intrinsic.
558    pub fn thread_yield_then_promote(&mut self, cancellable: bool) -> &mut Self {
559        self.bytes.push(0x2d);
560        self.bytes.push(if cancellable { 1 } else { 0 });
561        self.num_added += 1;
562        self
563    }
564
565    fn encode_options<O>(&mut self, options: O) -> &mut Self
566    where
567        O: IntoIterator<Item = CanonicalOption>,
568        O::IntoIter: ExactSizeIterator,
569    {
570        let options = options.into_iter();
571        options.len().encode(&mut self.bytes);
572        for option in options {
573            option.encode(&mut self.bytes);
574        }
575        self
576    }
577}
578
579impl Encode for CanonicalFunctionSection {
580    fn encode(&self, sink: &mut Vec<u8>) {
581        encode_section(sink, self.num_added, &self.bytes);
582    }
583}
584
585impl ComponentSection for CanonicalFunctionSection {
586    fn id(&self) -> u8 {
587        ComponentSectionId::CanonicalFunction.into()
588    }
589}