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