wasm_encoder/component/
canonicals.rs

1use crate::{ComponentSection, ComponentSectionId, ComponentValType, Encode, encode_section};
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 increment the backpressure
200    /// counter.
201    pub fn backpressure_inc(&mut self) -> &mut Self {
202        self.bytes.push(0x24);
203        self.num_added += 1;
204        self
205    }
206
207    /// Defines a function which tells the host to decrement the backpressure
208    /// counter.
209    pub fn backpressure_dec(&mut self) -> &mut Self {
210        self.bytes.push(0x25);
211        self.num_added += 1;
212        self
213    }
214
215    /// Defines a function which returns a result to the caller of a lifted
216    /// export function.  This allows the callee to continue executing after
217    /// returning a result.
218    pub fn task_return<O>(&mut self, ty: Option<ComponentValType>, options: O) -> &mut Self
219    where
220        O: IntoIterator<Item = CanonicalOption>,
221        O::IntoIter: ExactSizeIterator,
222    {
223        self.bytes.push(0x09);
224        crate::encode_resultlist(&mut self.bytes, ty);
225        self.encode_options(options);
226        self.num_added += 1;
227        self
228    }
229
230    /// Defines a function to acknowledge cancellation of the current task.
231    pub fn task_cancel(&mut self) -> &mut Self {
232        self.bytes.push(0x05);
233        self.num_added += 1;
234        self
235    }
236
237    /// Defines a new `context.get` intrinsic of the ith slot.
238    pub fn context_get(&mut self, i: u32) -> &mut Self {
239        self.bytes.push(0x0a);
240        self.bytes.push(0x7f);
241        i.encode(&mut self.bytes);
242        self.num_added += 1;
243        self
244    }
245
246    /// Defines a new `context.set` intrinsic of the ith slot.
247    pub fn context_set(&mut self, i: u32) -> &mut Self {
248        self.bytes.push(0x0b);
249        self.bytes.push(0x7f);
250        i.encode(&mut self.bytes);
251        self.num_added += 1;
252        self
253    }
254
255    /// Defines a function which yields control to the host so that other tasks
256    /// are able to make progress, if any.
257    ///
258    /// If `cancellable` is true, the caller instance may be reentered.
259    pub fn thread_yield(&mut self, cancellable: bool) -> &mut Self {
260        self.bytes.push(0x0c);
261        self.bytes.push(if cancellable { 1 } else { 0 });
262        self.num_added += 1;
263        self
264    }
265
266    /// Defines a function to drop a specified task which has completed.
267    pub fn subtask_drop(&mut self) -> &mut Self {
268        self.bytes.push(0x0d);
269        self.num_added += 1;
270        self
271    }
272
273    /// Defines a function to cancel an in-progress task.
274    pub fn subtask_cancel(&mut self, async_: bool) -> &mut Self {
275        self.bytes.push(0x06);
276        self.bytes.push(if async_ { 1 } else { 0 });
277        self.num_added += 1;
278        self
279    }
280
281    /// Defines a function to create a new `stream` handle of the specified
282    /// type.
283    pub fn stream_new(&mut self, ty: u32) -> &mut Self {
284        self.bytes.push(0x0e);
285        ty.encode(&mut self.bytes);
286        self.num_added += 1;
287        self
288    }
289
290    /// Defines a function to read from a `stream` of the specified type.
291    pub fn stream_read<O>(&mut self, ty: u32, options: O) -> &mut Self
292    where
293        O: IntoIterator<Item = CanonicalOption>,
294        O::IntoIter: ExactSizeIterator,
295    {
296        self.bytes.push(0x0f);
297        ty.encode(&mut self.bytes);
298        self.encode_options(options);
299        self.num_added += 1;
300        self
301    }
302
303    /// Defines a function to write to a `stream` of the specified type.
304    pub fn stream_write<O>(&mut self, ty: u32, options: O) -> &mut Self
305    where
306        O: IntoIterator<Item = CanonicalOption>,
307        O::IntoIter: ExactSizeIterator,
308    {
309        self.bytes.push(0x10);
310        ty.encode(&mut self.bytes);
311        self.encode_options(options);
312        self.num_added += 1;
313        self
314    }
315
316    /// Defines a function to cancel an in-progress read from a `stream` of the
317    /// specified type.
318    pub fn stream_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
319        self.bytes.push(0x11);
320        ty.encode(&mut self.bytes);
321        self.bytes.push(if async_ { 1 } else { 0 });
322        self.num_added += 1;
323        self
324    }
325
326    /// Defines a function to cancel an in-progress write to a `stream` of the
327    /// specified type.
328    pub fn stream_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
329        self.bytes.push(0x12);
330        ty.encode(&mut self.bytes);
331        self.bytes.push(if async_ { 1 } else { 0 });
332        self.num_added += 1;
333        self
334    }
335
336    /// Defines a function to drop the readable end of a `stream` of the
337    /// specified type.
338    pub fn stream_drop_readable(&mut self, ty: u32) -> &mut Self {
339        self.bytes.push(0x13);
340        ty.encode(&mut self.bytes);
341        self.num_added += 1;
342        self
343    }
344
345    /// Defines a function to drop the writable end of a `stream` of the
346    /// specified type.
347    pub fn stream_drop_writable(&mut self, ty: u32) -> &mut Self {
348        self.bytes.push(0x14);
349        ty.encode(&mut self.bytes);
350        self.num_added += 1;
351        self
352    }
353
354    /// Defines a function to create a new `future` handle of the specified
355    /// type.
356    pub fn future_new(&mut self, ty: u32) -> &mut Self {
357        self.bytes.push(0x15);
358        ty.encode(&mut self.bytes);
359        self.num_added += 1;
360        self
361    }
362
363    /// Defines a function to read from a `future` of the specified type.
364    pub fn future_read<O>(&mut self, ty: u32, options: O) -> &mut Self
365    where
366        O: IntoIterator<Item = CanonicalOption>,
367        O::IntoIter: ExactSizeIterator,
368    {
369        self.bytes.push(0x16);
370        ty.encode(&mut self.bytes);
371        self.encode_options(options);
372        self.num_added += 1;
373        self
374    }
375
376    /// Defines a function to write to a `future` of the specified type.
377    pub fn future_write<O>(&mut self, ty: u32, options: O) -> &mut Self
378    where
379        O: IntoIterator<Item = CanonicalOption>,
380        O::IntoIter: ExactSizeIterator,
381    {
382        self.bytes.push(0x17);
383        ty.encode(&mut self.bytes);
384        self.encode_options(options);
385        self.num_added += 1;
386        self
387    }
388
389    /// Defines a function to cancel an in-progress read from a `future` of the
390    /// specified type.
391    pub fn future_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
392        self.bytes.push(0x18);
393        ty.encode(&mut self.bytes);
394        self.bytes.push(if async_ { 1 } else { 0 });
395        self.num_added += 1;
396        self
397    }
398
399    /// Defines a function to cancel an in-progress write to a `future` of the
400    /// specified type.
401    pub fn future_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
402        self.bytes.push(0x19);
403        ty.encode(&mut self.bytes);
404        self.bytes.push(if async_ { 1 } else { 0 });
405        self.num_added += 1;
406        self
407    }
408
409    /// Defines a function to drop the readable end of a `future` of the
410    /// specified type.
411    pub fn future_drop_readable(&mut self, ty: u32) -> &mut Self {
412        self.bytes.push(0x1a);
413        ty.encode(&mut self.bytes);
414        self.num_added += 1;
415        self
416    }
417
418    /// Defines a function to drop the writable end of a `future` of the
419    /// specified type.
420    pub fn future_drop_writable(&mut self, ty: u32) -> &mut Self {
421        self.bytes.push(0x1b);
422        ty.encode(&mut self.bytes);
423        self.num_added += 1;
424        self
425    }
426
427    /// Defines a function to create a new `error-context` with a specified
428    /// debug message.
429    pub fn error_context_new<O>(&mut self, options: O) -> &mut Self
430    where
431        O: IntoIterator<Item = CanonicalOption>,
432        O::IntoIter: ExactSizeIterator,
433    {
434        self.bytes.push(0x1c);
435        self.encode_options(options);
436        self.num_added += 1;
437        self
438    }
439
440    /// Defines a function to get the debug message for a specified
441    /// `error-context`.
442    ///
443    /// Note that the debug message might not necessarily match what was passed
444    /// to `error-context.new`.
445    pub fn error_context_debug_message<O>(&mut self, options: O) -> &mut Self
446    where
447        O: IntoIterator<Item = CanonicalOption>,
448        O::IntoIter: ExactSizeIterator,
449    {
450        self.bytes.push(0x1d);
451        self.encode_options(options);
452        self.num_added += 1;
453        self
454    }
455
456    /// Defines a function to drop a specified `error-context`.
457    pub fn error_context_drop(&mut self) -> &mut Self {
458        self.bytes.push(0x1e);
459        self.num_added += 1;
460        self
461    }
462
463    /// Declare a new `waitable-set.new` intrinsic, used to create a
464    /// `waitable-set` pseudo-resource.
465    pub fn waitable_set_new(&mut self) -> &mut Self {
466        self.bytes.push(0x1f);
467        self.num_added += 1;
468        self
469    }
470
471    /// Declare a new `waitable-set.wait` intrinsic, used to block on a
472    /// `waitable-set`.
473    pub fn waitable_set_wait(&mut self, async_: bool, memory: u32) -> &mut Self {
474        self.bytes.push(0x20);
475        self.bytes.push(if async_ { 1 } else { 0 });
476        memory.encode(&mut self.bytes);
477        self.num_added += 1;
478        self
479    }
480
481    /// Declare a new `waitable-set.wait` intrinsic, used to check, without
482    /// blocking, if anything in a `waitable-set` is ready.
483    pub fn waitable_set_poll(&mut self, async_: bool, memory: u32) -> &mut Self {
484        self.bytes.push(0x21);
485        self.bytes.push(if async_ { 1 } else { 0 });
486        memory.encode(&mut self.bytes);
487        self.num_added += 1;
488        self
489    }
490
491    /// Declare a new `waitable-set.drop` intrinsic, used to dispose a
492    /// `waitable-set` pseudo-resource.
493    pub fn waitable_set_drop(&mut self) -> &mut Self {
494        self.bytes.push(0x22);
495        self.num_added += 1;
496        self
497    }
498
499    /// Declare a new `waitable.join` intrinsic, used to add an item to a
500    /// `waitable-set`.
501    pub fn waitable_join(&mut self) -> &mut Self {
502        self.bytes.push(0x23);
503        self.num_added += 1;
504        self
505    }
506
507    /// Declare a new `thread.index` intrinsic, used to get the index of the
508    /// current thread.
509    pub fn thread_index(&mut self) -> &mut Self {
510        self.bytes.push(0x26);
511        self.num_added += 1;
512        self
513    }
514
515    /// Declare a new `thread.new-indirect` intrinsic, used to create a new
516    /// thread by invoking a function indirectly through a `funcref` table.
517    pub fn thread_new_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self {
518        self.bytes.push(0x27);
519        ty_index.encode(&mut self.bytes);
520        table_index.encode(&mut self.bytes);
521        self.num_added += 1;
522        self
523    }
524
525    /// Declare a new `thread.switch-to` intrinsic, used to switch execution to
526    /// another thread.
527    pub fn thread_switch_to(&mut self, cancellable: bool) -> &mut Self {
528        self.bytes.push(0x28);
529        self.bytes.push(if cancellable { 1 } else { 0 });
530        self.num_added += 1;
531        self
532    }
533
534    /// Declare a new `thread.suspend` intrinsic, used to suspend execution of
535    /// the current thread.
536    pub fn thread_suspend(&mut self, cancellable: bool) -> &mut Self {
537        self.bytes.push(0x29);
538        self.bytes.push(if cancellable { 1 } else { 0 });
539        self.num_added += 1;
540        self
541    }
542
543    /// Declare a new `thread.resume-later` intrinsic, used to resume execution
544    /// of the given thread.
545    pub fn thread_resume_later(&mut self) -> &mut Self {
546        self.bytes.push(0x2a);
547        self.num_added += 1;
548        self
549    }
550
551    /// Declare a new `thread.yield-to` intrinsic, used to yield execution to
552    /// a given thread.
553    pub fn thread_yield_to(&mut self, cancellable: bool) -> &mut Self {
554        self.bytes.push(0x2b);
555        self.bytes.push(if cancellable { 1 } else { 0 });
556        self.num_added += 1;
557        self
558    }
559
560    fn encode_options<O>(&mut self, options: O) -> &mut Self
561    where
562        O: IntoIterator<Item = CanonicalOption>,
563        O::IntoIter: ExactSizeIterator,
564    {
565        let options = options.into_iter();
566        options.len().encode(&mut self.bytes);
567        for option in options {
568            option.encode(&mut self.bytes);
569        }
570        self
571    }
572}
573
574impl Encode for CanonicalFunctionSection {
575    fn encode(&self, sink: &mut Vec<u8>) {
576        encode_section(sink, self.num_added, &self.bytes);
577    }
578}
579
580impl ComponentSection for CanonicalFunctionSection {
581    fn id(&self) -> u8 {
582        ComponentSectionId::CanonicalFunction.into()
583    }
584}