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 forward all remaining elements from the readable
302    /// end of one `stream` to the writable end of another `stream` of the
303    /// specified type, transferring both ends out of the calling instance.
304    pub fn stream_forward(&mut self, ty: u32) -> &mut Self {
305        self.bytes.push(0x2e);
306        ty.encode(&mut self.bytes);
307        self.num_added += 1;
308        self
309    }
310
311    /// Defines a function to cancel an in-progress read from a `stream` of the
312    /// specified type.
313    pub fn stream_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
314        self.bytes.push(0x11);
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 cancel an in-progress write to a `stream` of the
322    /// specified type.
323    pub fn stream_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
324        self.bytes.push(0x12);
325        ty.encode(&mut self.bytes);
326        self.bytes.push(if async_ { 1 } else { 0 });
327        self.num_added += 1;
328        self
329    }
330
331    /// Defines a function to drop the readable end of a `stream` of the
332    /// specified type.
333    pub fn stream_drop_readable(&mut self, ty: u32) -> &mut Self {
334        self.bytes.push(0x13);
335        ty.encode(&mut self.bytes);
336        self.num_added += 1;
337        self
338    }
339
340    /// Defines a function to drop the writable end of a `stream` of the
341    /// specified type.
342    pub fn stream_drop_writable(&mut self, ty: u32) -> &mut Self {
343        self.bytes.push(0x14);
344        ty.encode(&mut self.bytes);
345        self.num_added += 1;
346        self
347    }
348
349    /// Defines a function to create a new `future` handle of the specified
350    /// type.
351    pub fn future_new(&mut self, ty: u32) -> &mut Self {
352        self.bytes.push(0x15);
353        ty.encode(&mut self.bytes);
354        self.num_added += 1;
355        self
356    }
357
358    /// Defines a function to read from a `future` of the specified type.
359    pub fn future_read<O>(&mut self, ty: u32, options: O) -> &mut Self
360    where
361        O: IntoIterator<Item = CanonicalOption>,
362        O::IntoIter: ExactSizeIterator,
363    {
364        self.bytes.push(0x16);
365        ty.encode(&mut self.bytes);
366        self.encode_options(options);
367        self.num_added += 1;
368        self
369    }
370
371    /// Defines a function to write to a `future` of the specified type.
372    pub fn future_write<O>(&mut self, ty: u32, options: O) -> &mut Self
373    where
374        O: IntoIterator<Item = CanonicalOption>,
375        O::IntoIter: ExactSizeIterator,
376    {
377        self.bytes.push(0x17);
378        ty.encode(&mut self.bytes);
379        self.encode_options(options);
380        self.num_added += 1;
381        self
382    }
383
384    /// Defines a function to forward the value of the readable end of one
385    /// `future` to the writable end of another `future` of the specified
386    /// type, transferring both ends out of the calling instance.
387    pub fn future_forward(&mut self, ty: u32) -> &mut Self {
388        self.bytes.push(0x2f);
389        ty.encode(&mut self.bytes);
390        self.num_added += 1;
391        self
392    }
393
394    /// Defines a function to cancel an in-progress read from a `future` of the
395    /// specified type.
396    pub fn future_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
397        self.bytes.push(0x18);
398        ty.encode(&mut self.bytes);
399        self.bytes.push(if async_ { 1 } else { 0 });
400        self.num_added += 1;
401        self
402    }
403
404    /// Defines a function to cancel an in-progress write to a `future` of the
405    /// specified type.
406    pub fn future_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
407        self.bytes.push(0x19);
408        ty.encode(&mut self.bytes);
409        self.bytes.push(if async_ { 1 } else { 0 });
410        self.num_added += 1;
411        self
412    }
413
414    /// Defines a function to drop the readable end of a `future` of the
415    /// specified type.
416    pub fn future_drop_readable(&mut self, ty: u32) -> &mut Self {
417        self.bytes.push(0x1a);
418        ty.encode(&mut self.bytes);
419        self.num_added += 1;
420        self
421    }
422
423    /// Defines a function to drop the writable end of a `future` of the
424    /// specified type.
425    pub fn future_drop_writable(&mut self, ty: u32) -> &mut Self {
426        self.bytes.push(0x1b);
427        ty.encode(&mut self.bytes);
428        self.num_added += 1;
429        self
430    }
431
432    /// Defines a function to create a new `error-context` with a specified
433    /// debug message.
434    pub fn error_context_new<O>(&mut self, options: O) -> &mut Self
435    where
436        O: IntoIterator<Item = CanonicalOption>,
437        O::IntoIter: ExactSizeIterator,
438    {
439        self.bytes.push(0x1c);
440        self.encode_options(options);
441        self.num_added += 1;
442        self
443    }
444
445    /// Defines a function to get the debug message for a specified
446    /// `error-context`.
447    ///
448    /// Note that the debug message might not necessarily match what was passed
449    /// to `error-context.new`.
450    pub fn error_context_debug_message<O>(&mut self, options: O) -> &mut Self
451    where
452        O: IntoIterator<Item = CanonicalOption>,
453        O::IntoIter: ExactSizeIterator,
454    {
455        self.bytes.push(0x1d);
456        self.encode_options(options);
457        self.num_added += 1;
458        self
459    }
460
461    /// Defines a function to drop a specified `error-context`.
462    pub fn error_context_drop(&mut self) -> &mut Self {
463        self.bytes.push(0x1e);
464        self.num_added += 1;
465        self
466    }
467
468    /// Declare a new `waitable-set.new` intrinsic, used to create a
469    /// `waitable-set` pseudo-resource.
470    pub fn waitable_set_new(&mut self) -> &mut Self {
471        self.bytes.push(0x1f);
472        self.num_added += 1;
473        self
474    }
475
476    /// Declare a new `waitable-set.wait` intrinsic, used to block on a
477    /// `waitable-set`.
478    pub fn waitable_set_wait(&mut self, memory: u32) -> &mut Self {
479        self.bytes.push(0x20);
480        self.bytes.push(0);
481        memory.encode(&mut self.bytes);
482        self.num_added += 1;
483        self
484    }
485
486    /// Declare a new `waitable-set.wait` intrinsic, used to check, without
487    /// blocking, if anything in a `waitable-set` is ready.
488    pub fn waitable_set_poll(&mut self, memory: u32) -> &mut Self {
489        self.bytes.push(0x21);
490        self.bytes.push(0);
491        memory.encode(&mut self.bytes);
492        self.num_added += 1;
493        self
494    }
495
496    /// Declare a new `waitable-set.drop` intrinsic, used to dispose a
497    /// `waitable-set` pseudo-resource.
498    pub fn waitable_set_drop(&mut self) -> &mut Self {
499        self.bytes.push(0x22);
500        self.num_added += 1;
501        self
502    }
503
504    /// Declare a new `waitable.join` intrinsic, used to add an item to a
505    /// `waitable-set`.
506    pub fn waitable_join(&mut self) -> &mut Self {
507        self.bytes.push(0x23);
508        self.num_added += 1;
509        self
510    }
511
512    /// Declare a new `thread.index` intrinsic, used to get the index of the
513    /// current thread.
514    pub fn thread_index(&mut self) -> &mut Self {
515        self.bytes.push(0x26);
516        self.num_added += 1;
517        self
518    }
519
520    /// Declare a new `thread.new-indirect` intrinsic, used to create a new
521    /// thread by invoking a function indirectly through a `funcref` table.
522    pub fn thread_new_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self {
523        self.bytes.push(0x27);
524        ty_index.encode(&mut self.bytes);
525        table_index.encode(&mut self.bytes);
526        self.num_added += 1;
527        self
528    }
529
530    /// Declare a new `thread.resume-later` intrinsic.
531    pub fn thread_resume_later(&mut self) -> &mut Self {
532        self.bytes.push(0x28);
533        self.num_added += 1;
534        self
535    }
536
537    /// Declare a new `thread.suspend` intrinsic.
538    pub fn thread_suspend(&mut self) -> &mut Self {
539        self.bytes.push(0x29);
540        self.bytes.push(0);
541        self.num_added += 1;
542        self
543    }
544
545    /// Declare a new `thread.yield` intrinsic.
546    pub fn thread_yield(&mut self) -> &mut Self {
547        self.bytes.push(0x0c);
548        self.bytes.push(0);
549        self.num_added += 1;
550        self
551    }
552
553    /// Declare a new `thread.suspend-then-resume` intrinsic.
554    pub fn thread_suspend_then_resume(&mut self) -> &mut Self {
555        self.bytes.push(0x2a);
556        self.bytes.push(0);
557        self.num_added += 1;
558        self
559    }
560
561    /// Declare a new `thread.yield-then-resume` intrinsic.
562    pub fn thread_yield_then_resume(&mut self) -> &mut Self {
563        self.bytes.push(0x2b);
564        self.bytes.push(0);
565        self.num_added += 1;
566        self
567    }
568
569    /// Declare a new `thread.suspend-then-promote` intrinsic.
570    pub fn thread_suspend_then_promote(&mut self) -> &mut Self {
571        self.bytes.push(0x2c);
572        self.bytes.push(0);
573        self.num_added += 1;
574        self
575    }
576
577    /// Declare a new `thread.yield-then-promote` intrinsic.
578    pub fn thread_yield_then_promote(&mut self) -> &mut Self {
579        self.bytes.push(0x2d);
580        self.bytes.push(0);
581        self.num_added += 1;
582        self
583    }
584
585    fn encode_options<O>(&mut self, options: O) -> &mut Self
586    where
587        O: IntoIterator<Item = CanonicalOption>,
588        O::IntoIter: ExactSizeIterator,
589    {
590        let options = options.into_iter();
591        options.len().encode(&mut self.bytes);
592        for option in options {
593            option.encode(&mut self.bytes);
594        }
595        self
596    }
597}
598
599impl Encode for CanonicalFunctionSection {
600    fn encode(&self, sink: &mut Vec<u8>) {
601        encode_section(sink, self.num_added, &self.bytes);
602    }
603}
604
605impl ComponentSection for CanonicalFunctionSection {
606    fn id(&self) -> u8 {
607        ComponentSectionId::CanonicalFunction.into()
608    }
609}