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