1use crate::{encode_section, ComponentSection, ComponentSectionId, 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_hw_concurrency(&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: u32) -> &mut Self {
192 self.bytes.push(0x09);
193 ty.encode(&mut self.bytes);
194 self.num_added += 1;
195 self
196 }
197
198 /// Defines a function which waits for at least one outstanding async
199 /// task/stream/future to make progress, returning the first such event.
200 ///
201 /// If `async_` is true, the caller instance may be reentered.
202 pub fn task_wait(&mut self, async_: bool, memory: u32) -> &mut Self {
203 self.bytes.push(0x0a);
204 self.bytes.push(if async_ { 1 } else { 0 });
205 memory.encode(&mut self.bytes);
206 self.num_added += 1;
207 self
208 }
209
210 /// Defines a function which checks whether any outstanding async
211 /// task/stream/future has made progress. Unlike `task.wait`, this does not
212 /// block and may return nothing if no such event has occurred.
213 ///
214 /// If `async_` is true, the caller instance may be reentered.
215 pub fn task_poll(&mut self, async_: bool, memory: u32) -> &mut Self {
216 self.bytes.push(0x0b);
217 self.bytes.push(if async_ { 1 } else { 0 });
218 memory.encode(&mut self.bytes);
219 self.num_added += 1;
220 self
221 }
222
223 /// Defines a function which yields control to the host so that other tasks
224 /// are able to make progress, if any.
225 ///
226 /// If `async_` is true, the caller instance may be reentered.
227 pub fn task_yield(&mut self, async_: bool) -> &mut Self {
228 self.bytes.push(0x0c);
229 self.bytes.push(if async_ { 1 } else { 0 });
230 self.num_added += 1;
231 self
232 }
233
234 /// Defines a function to drop a specified task which has completed.
235 pub fn subtask_drop(&mut self) -> &mut Self {
236 self.bytes.push(0x0d);
237 self.num_added += 1;
238 self
239 }
240
241 /// Defines a function to create a new `stream` handle of the specified
242 /// type.
243 pub fn stream_new(&mut self, ty: u32) -> &mut Self {
244 self.bytes.push(0x0e);
245 ty.encode(&mut self.bytes);
246 self.num_added += 1;
247 self
248 }
249
250 /// Defines a function to read from a `stream` of the specified type.
251 pub fn stream_read<O>(&mut self, ty: u32, options: O) -> &mut Self
252 where
253 O: IntoIterator<Item = CanonicalOption>,
254 O::IntoIter: ExactSizeIterator,
255 {
256 self.bytes.push(0x0f);
257 ty.encode(&mut self.bytes);
258 let options = options.into_iter();
259 options.len().encode(&mut self.bytes);
260 for option in options {
261 option.encode(&mut self.bytes);
262 }
263 self.num_added += 1;
264 self
265 }
266
267 /// Defines a function to write to a `stream` of the specified type.
268 pub fn stream_write<O>(&mut self, ty: u32, options: O) -> &mut Self
269 where
270 O: IntoIterator<Item = CanonicalOption>,
271 O::IntoIter: ExactSizeIterator,
272 {
273 self.bytes.push(0x10);
274 ty.encode(&mut self.bytes);
275 let options = options.into_iter();
276 options.len().encode(&mut self.bytes);
277 for option in options {
278 option.encode(&mut self.bytes);
279 }
280 self.num_added += 1;
281 self
282 }
283
284 /// Defines a function to cancel an in-progress read from a `stream` of the
285 /// specified type.
286 pub fn stream_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
287 self.bytes.push(0x11);
288 ty.encode(&mut self.bytes);
289 self.bytes.push(if async_ { 1 } else { 0 });
290 self.num_added += 1;
291 self
292 }
293
294 /// Defines a function to cancel an in-progress write to a `stream` of the
295 /// specified type.
296 pub fn stream_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
297 self.bytes.push(0x12);
298 ty.encode(&mut self.bytes);
299 self.bytes.push(if async_ { 1 } else { 0 });
300 self.num_added += 1;
301 self
302 }
303
304 /// Defines a function to close the readable end of a `stream` of the
305 /// specified type.
306 pub fn stream_close_readable(&mut self, ty: u32) -> &mut Self {
307 self.bytes.push(0x13);
308 ty.encode(&mut self.bytes);
309 self.num_added += 1;
310 self
311 }
312
313 /// Defines a function to close the writable end of a `stream` of the
314 /// specified type.
315 pub fn stream_close_writable(&mut self, ty: u32) -> &mut Self {
316 self.bytes.push(0x14);
317 ty.encode(&mut self.bytes);
318 self.num_added += 1;
319 self
320 }
321
322 /// Defines a function to create a new `future` handle of the specified
323 /// type.
324 pub fn future_new(&mut self, ty: u32) -> &mut Self {
325 self.bytes.push(0x15);
326 ty.encode(&mut self.bytes);
327 self.num_added += 1;
328 self
329 }
330
331 /// Defines a function to read from a `future` of the specified type.
332 pub fn future_read<O>(&mut self, ty: u32, options: O) -> &mut Self
333 where
334 O: IntoIterator<Item = CanonicalOption>,
335 O::IntoIter: ExactSizeIterator,
336 {
337 self.bytes.push(0x16);
338 ty.encode(&mut self.bytes);
339 let options = options.into_iter();
340 options.len().encode(&mut self.bytes);
341 for option in options {
342 option.encode(&mut self.bytes);
343 }
344 self.num_added += 1;
345 self
346 }
347
348 /// Defines a function to write to a `future` of the specified type.
349 pub fn future_write<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(0x17);
355 ty.encode(&mut self.bytes);
356 let options = options.into_iter();
357 options.len().encode(&mut self.bytes);
358 for option in options {
359 option.encode(&mut self.bytes);
360 }
361 self.num_added += 1;
362 self
363 }
364
365 /// Defines a function to cancel an in-progress read from a `future` of the
366 /// specified type.
367 pub fn future_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
368 self.bytes.push(0x18);
369 ty.encode(&mut self.bytes);
370 self.bytes.push(if async_ { 1 } else { 0 });
371 self.num_added += 1;
372 self
373 }
374
375 /// Defines a function to cancel an in-progress write to a `future` of the
376 /// specified type.
377 pub fn future_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
378 self.bytes.push(0x19);
379 ty.encode(&mut self.bytes);
380 self.bytes.push(if async_ { 1 } else { 0 });
381 self.num_added += 1;
382 self
383 }
384
385 /// Defines a function to close the readable end of a `future` of the
386 /// specified type.
387 pub fn future_close_readable(&mut self, ty: u32) -> &mut Self {
388 self.bytes.push(0x1a);
389 ty.encode(&mut self.bytes);
390 self.num_added += 1;
391 self
392 }
393
394 /// Defines a function to close the writable end of a `future` of the
395 /// specified type.
396 pub fn future_close_writable(&mut self, ty: u32) -> &mut Self {
397 self.bytes.push(0x1b);
398 ty.encode(&mut self.bytes);
399 self.num_added += 1;
400 self
401 }
402
403 /// Defines a function to create a new `error-context` with a specified
404 /// debug message.
405 pub fn error_context_new<O>(&mut self, options: O) -> &mut Self
406 where
407 O: IntoIterator<Item = CanonicalOption>,
408 O::IntoIter: ExactSizeIterator,
409 {
410 self.bytes.push(0x1c);
411 let options = options.into_iter();
412 options.len().encode(&mut self.bytes);
413 for option in options {
414 option.encode(&mut self.bytes);
415 }
416 self.num_added += 1;
417 self
418 }
419
420 /// Defines a function to get the debug message for a specified
421 /// `error-context`.
422 ///
423 /// Note that the debug message might not necessarily match what was passed
424 /// to `error-context.new`.
425 pub fn error_context_debug_message<O>(&mut self, options: O) -> &mut Self
426 where
427 O: IntoIterator<Item = CanonicalOption>,
428 O::IntoIter: ExactSizeIterator,
429 {
430 self.bytes.push(0x1d);
431 let options = options.into_iter();
432 options.len().encode(&mut self.bytes);
433 for option in options {
434 option.encode(&mut self.bytes);
435 }
436 self.num_added += 1;
437 self
438 }
439
440 /// Defines a function to drop a specified `error-context`.
441 pub fn error_context_drop(&mut self) -> &mut Self {
442 self.bytes.push(0x1e);
443 self.num_added += 1;
444 self
445 }
446}
447
448impl Encode for CanonicalFunctionSection {
449 fn encode(&self, sink: &mut Vec<u8>) {
450 encode_section(sink, self.num_added, &self.bytes);
451 }
452}
453
454impl ComponentSection for CanonicalFunctionSection {
455 fn id(&self) -> u8 {
456 ComponentSectionId::CanonicalFunction.into()
457 }
458}
459