1use crate::limits::MAX_WASM_CANONICAL_OPTIONS;
2use crate::prelude::*;
3use crate::{BinaryReader, FromReader, Result, SectionLimited};
4
5/// Represents options for component functions.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum CanonicalOption {
8 /// The string types in the function signature are UTF-8 encoded.
9 UTF8,
10 /// The string types in the function signature are UTF-16 encoded.
11 UTF16,
12 /// The string types in the function signature are compact UTF-16 encoded.
13 CompactUTF16,
14 /// The memory to use if the lifting or lowering of a function requires memory access.
15 ///
16 /// The value is an index to a core memory.
17 Memory(u32),
18 /// The realloc function to use if the lifting or lowering of a function requires memory
19 /// allocation.
20 ///
21 /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`.
22 Realloc(u32),
23 /// The post-return function to use if the lifting of a function requires
24 /// cleanup after the function returns.
25 PostReturn(u32),
26 /// Indicates that specified function should be lifted or lowered using the `async` ABI.
27 Async,
28 /// The function to use if the async lifting of a function should receive task/stream/future progress events
29 /// using a callback.
30 Callback(u32),
31}
32
33/// Represents a canonical function in a WebAssembly component.
34#[derive(Debug, Clone, Eq, PartialEq)]
35pub enum CanonicalFunction {
36 /// The function lifts a core WebAssembly function to the canonical ABI.
37 Lift {
38 /// The index of the core WebAssembly function to lift.
39 core_func_index: u32,
40 /// The index of the lifted function's type.
41 type_index: u32,
42 /// The canonical options for the function.
43 options: Box<[CanonicalOption]>,
44 },
45 /// The function lowers a canonical ABI function to a core WebAssembly function.
46 Lower {
47 /// The index of the function to lower.
48 func_index: u32,
49 /// The canonical options for the function.
50 options: Box<[CanonicalOption]>,
51 },
52 /// A function which creates a new owned handle to a resource.
53 ResourceNew {
54 /// The type index of the resource that's being created.
55 resource: u32,
56 },
57 /// A function which is used to drop resource handles of the specified type.
58 ResourceDrop {
59 /// The type index of the resource that's being dropped.
60 resource: u32,
61 },
62 /// A function which returns the underlying i32-based representation of the
63 /// specified resource.
64 ResourceRep {
65 /// The type index of the resource that's being accessed.
66 resource: u32,
67 },
68 /// A function which spawns a new thread by invoking the shared function.
69 ThreadSpawn {
70 /// The index of the function to spawn.
71 func_ty_index: u32,
72 },
73 /// A function which returns the number of threads that can be expected to
74 /// execute concurrently
75 ThreadHwConcurrency,
76 /// A function which tells the host to enable or disable backpressure for
77 /// the caller's instance.
78 TaskBackpressure,
79 /// A function which returns a result to the caller of a lifted export
80 /// function. This allows the callee to continue executing after returning
81 /// a result.
82 TaskReturn {
83 /// Core function type whose parameters represent the flattened
84 /// representation of the component-level results to be returned by the
85 /// currently executing task.
86 type_index: u32,
87 },
88 /// A function which waits for at least one outstanding async
89 /// task/stream/future to make progress, returning the first such event.
90 TaskWait {
91 /// If `true`, indicates the caller instance maybe reentered.
92 async_: bool,
93 /// Memory to use when storing the event.
94 memory: u32,
95 },
96 /// A function which checks whether any outstanding async task/stream/future
97 /// has made progress. Unlike `task.wait`, this does not block and may
98 /// return nothing if no such event has occurred.
99 TaskPoll {
100 /// If `true`, indicates the caller instance maybe reentered.
101 async_: bool,
102 /// Memory to use when storing the event, if any.
103 memory: u32,
104 },
105 /// A function which yields control to the host so that other tasks are able
106 /// to make progress, if any.
107 TaskYield {
108 /// If `true`, indicates the caller instance maybe reentered.
109 async_: bool,
110 },
111 /// A function to drop a specified task which has completed.
112 SubtaskDrop,
113 /// A function to create a new `stream` handle of the specified type.
114 StreamNew {
115 /// The `stream` type to instantiate.
116 ty: u32,
117 },
118 /// A function to read from a `stream` of the specified type.
119 StreamRead {
120 /// The `stream` type to expect.
121 ty: u32,
122 /// Any options (e.g. string encoding) to use when storing values to
123 /// memory.
124 options: Box<[CanonicalOption]>,
125 },
126 /// A function to write to a `stream` of the specified type.
127 StreamWrite {
128 /// The `stream` type to expect.
129 ty: u32,
130 /// Any options (e.g. string encoding) to use when loading values from
131 /// memory.
132 options: Box<[CanonicalOption]>,
133 },
134 /// A function to cancel an in-progress read from a `stream` of the
135 /// specified type.
136 StreamCancelRead {
137 /// The `stream` type to expect.
138 ty: u32,
139 /// If `false`, block until cancellation completes rather than return
140 /// `BLOCKED`.
141 async_: bool,
142 },
143 /// A function to cancel an in-progress write to a `stream` of the specified
144 /// type.
145 StreamCancelWrite {
146 /// The `stream` type to expect.
147 ty: u32,
148 /// If `false`, block until cancellation completes rather than return
149 /// `BLOCKED`.
150 async_: bool,
151 },
152 /// A function to close the readable end of a `stream` of the specified
153 /// type.
154 StreamCloseReadable {
155 /// The `stream` type to expect.
156 ty: u32,
157 },
158 /// A function to close the writable end of a `stream` of the specified
159 /// type.
160 StreamCloseWritable {
161 /// The `stream` type to expect.
162 ty: u32,
163 },
164 /// A function to create a new `future` handle of the specified type.
165 FutureNew {
166 /// The `future` type to instantiate.
167 ty: u32,
168 },
169 /// A function to read from a `future` of the specified type.
170 FutureRead {
171 /// The `future` type to expect.
172 ty: u32,
173 /// Any options (e.g. string encoding) to use when storing values to
174 /// memory.
175 options: Box<[CanonicalOption]>,
176 },
177 /// A function to write to a `future` of the specified type.
178 FutureWrite {
179 /// The `future` type to expect.
180 ty: u32,
181 /// Any options (e.g. string encoding) to use when loading values from
182 /// memory.
183 options: Box<[CanonicalOption]>,
184 },
185 /// A function to cancel an in-progress read from a `future` of the
186 /// specified type.
187 FutureCancelRead {
188 /// The `future` type to expect.
189 ty: u32,
190 /// If `false`, block until cancellation completes rather than return
191 /// `BLOCKED`.
192 async_: bool,
193 },
194 /// A function to cancel an in-progress write to a `future` of the specified
195 /// type.
196 FutureCancelWrite {
197 /// The `future` type to expect.
198 ty: u32,
199 /// If `false`, block until cancellation completes rather than return
200 /// `BLOCKED`.
201 async_: bool,
202 },
203 /// A function to close the readable end of a `future` of the specified
204 /// type.
205 FutureCloseReadable {
206 /// The `future` type to expect.
207 ty: u32,
208 },
209 /// A function to close the writable end of a `future` of the specified
210 /// type.
211 FutureCloseWritable {
212 /// The `future` type to expect.
213 ty: u32,
214 },
215 /// A function to create a new `error-context` with a specified debug
216 /// message.
217 ErrorContextNew {
218 /// String encoding, memory, etc. to use when loading debug message.
219 options: Box<[CanonicalOption]>,
220 },
221 /// A function to get the debug message for a specified `error-context`.
222 ///
223 /// Note that the debug message might not necessarily match what was passed
224 /// to `error.new`.
225 ErrorContextDebugMessage {
226 /// String encoding, memory, etc. to use when storing debug message.
227 options: Box<[CanonicalOption]>,
228 },
229 /// A function to drop a specified `error-context`.
230 ErrorContextDrop,
231}
232
233/// A reader for the canonical section of a WebAssembly component.
234pub type ComponentCanonicalSectionReader<'a> = SectionLimited<'a, CanonicalFunction>;
235
236impl<'a> FromReader<'a> for CanonicalFunction {
237 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<CanonicalFunction> {
238 Ok(match reader.read_u8()? {
239 0x00 => match reader.read_u8()? {
240 0x00 => {
241 let core_func_index = reader.read_var_u32()?;
242 let options = reader
243 .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
244 .collect::<Result<_>>()?;
245 let type_index = reader.read_var_u32()?;
246 CanonicalFunction::Lift {
247 core_func_index,
248 options,
249 type_index,
250 }
251 }
252 x => return reader.invalid_leading_byte(x, "canonical function lift"),
253 },
254 0x01 => match reader.read_u8()? {
255 0x00 => CanonicalFunction::Lower {
256 func_index: reader.read_var_u32()?,
257 options: reader
258 .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
259 .collect::<Result<_>>()?,
260 },
261 x => return reader.invalid_leading_byte(x, "canonical function lower"),
262 },
263 0x02 => CanonicalFunction::ResourceNew {
264 resource: reader.read()?,
265 },
266 0x03 => CanonicalFunction::ResourceDrop {
267 resource: reader.read()?,
268 },
269 0x04 => CanonicalFunction::ResourceRep {
270 resource: reader.read()?,
271 },
272 0x05 => CanonicalFunction::ThreadSpawn {
273 func_ty_index: reader.read()?,
274 },
275 0x06 => CanonicalFunction::ThreadHwConcurrency,
276 0x08 => CanonicalFunction::TaskBackpressure,
277 0x09 => CanonicalFunction::TaskReturn {
278 type_index: reader.read()?,
279 },
280 0x0a => CanonicalFunction::TaskWait {
281 async_: reader.read()?,
282 memory: reader.read()?,
283 },
284 0x0b => CanonicalFunction::TaskPoll {
285 async_: reader.read()?,
286 memory: reader.read()?,
287 },
288 0x0c => CanonicalFunction::TaskYield {
289 async_: reader.read()?,
290 },
291 0x0d => CanonicalFunction::SubtaskDrop,
292 0x0e => CanonicalFunction::StreamNew { ty: reader.read()? },
293 0x0f => CanonicalFunction::StreamRead {
294 ty: reader.read()?,
295 options: reader
296 .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
297 .collect::<Result<_>>()?,
298 },
299 0x10 => CanonicalFunction::StreamWrite {
300 ty: reader.read()?,
301 options: reader
302 .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
303 .collect::<Result<_>>()?,
304 },
305 0x11 => CanonicalFunction::StreamCancelRead {
306 ty: reader.read()?,
307 async_: reader.read()?,
308 },
309 0x12 => CanonicalFunction::StreamCancelWrite {
310 ty: reader.read()?,
311 async_: reader.read()?,
312 },
313 0x13 => CanonicalFunction::StreamCloseReadable { ty: reader.read()? },
314 0x14 => CanonicalFunction::StreamCloseWritable { ty: reader.read()? },
315 0x15 => CanonicalFunction::FutureNew { ty: reader.read()? },
316 0x16 => CanonicalFunction::FutureRead {
317 ty: reader.read()?,
318 options: reader
319 .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
320 .collect::<Result<_>>()?,
321 },
322 0x17 => CanonicalFunction::FutureWrite {
323 ty: reader.read()?,
324 options: reader
325 .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
326 .collect::<Result<_>>()?,
327 },
328 0x18 => CanonicalFunction::FutureCancelRead {
329 ty: reader.read()?,
330 async_: reader.read()?,
331 },
332 0x19 => CanonicalFunction::FutureCancelWrite {
333 ty: reader.read()?,
334 async_: reader.read()?,
335 },
336 0x1a => CanonicalFunction::FutureCloseReadable { ty: reader.read()? },
337 0x1b => CanonicalFunction::FutureCloseWritable { ty: reader.read()? },
338 0x1c => CanonicalFunction::ErrorContextNew {
339 options: reader
340 .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
341 .collect::<Result<_>>()?,
342 },
343 0x1d => CanonicalFunction::ErrorContextDebugMessage {
344 options: reader
345 .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
346 .collect::<Result<_>>()?,
347 },
348 0x1e => CanonicalFunction::ErrorContextDrop,
349 x => return reader.invalid_leading_byte(x, "canonical function"),
350 })
351 }
352}
353
354impl<'a> FromReader<'a> for CanonicalOption {
355 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
356 Ok(match reader.read_u8()? {
357 0x00 => CanonicalOption::UTF8,
358 0x01 => CanonicalOption::UTF16,
359 0x02 => CanonicalOption::CompactUTF16,
360 0x03 => CanonicalOption::Memory(reader.read_var_u32()?),
361 0x04 => CanonicalOption::Realloc(reader.read_var_u32()?),
362 0x05 => CanonicalOption::PostReturn(reader.read_var_u32()?),
363 0x06 => CanonicalOption::Async,
364 0x07 => CanonicalOption::Callback(reader.read_var_u32()?),
365 x: u8 => return reader.invalid_leading_byte(byte:x, desc:"canonical option"),
366 })
367 }
368}
369