1use crate::{encode_section, ComponentSection, ComponentSectionId, Encode};
2
3/// Represents options for canonical function definitions.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum CanonicalOption {
6 /// The string types in the function signature are UTF-8 encoded.
7 UTF8,
8 /// The string types in the function signature are UTF-16 encoded.
9 UTF16,
10 /// The string types in the function signature are compact UTF-16 encoded.
11 CompactUTF16,
12 /// The memory to use if the lifting or lowering of a function requires memory access.
13 ///
14 /// The value is an index to a core memory.
15 Memory(u32),
16 /// The realloc function to use if the lifting or lowering of a function requires memory
17 /// allocation.
18 ///
19 /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`.
20 Realloc(u32),
21 /// The post-return function to use if the lifting of a function requires
22 /// cleanup after the function returns.
23 PostReturn(u32),
24}
25
26impl Encode for CanonicalOption {
27 fn encode(&self, sink: &mut Vec<u8>) {
28 match self {
29 Self::UTF8 => sink.push(0x00),
30 Self::UTF16 => sink.push(0x01),
31 Self::CompactUTF16 => sink.push(0x02),
32 Self::Memory(idx: &u32) => {
33 sink.push(0x03);
34 idx.encode(sink);
35 }
36 Self::Realloc(idx: &u32) => {
37 sink.push(0x04);
38 idx.encode(sink);
39 }
40 Self::PostReturn(idx: &u32) => {
41 sink.push(0x05);
42 idx.encode(sink);
43 }
44 }
45 }
46}
47
48/// An encoder for the canonical function section of WebAssembly components.
49///
50/// # Example
51///
52/// ```
53/// use wasm_encoder::{Component, CanonicalFunctionSection, CanonicalOption};
54///
55/// let mut functions = CanonicalFunctionSection::new();
56/// functions.lift(0, 0, [CanonicalOption::UTF8]);
57///
58/// let mut component = Component::new();
59/// component.section(&functions);
60///
61/// let bytes = component.finish();
62/// ```
63#[derive(Clone, Debug, Default)]
64pub struct CanonicalFunctionSection {
65 bytes: Vec<u8>,
66 num_added: u32,
67}
68
69impl CanonicalFunctionSection {
70 /// Construct a new component function section encoder.
71 pub fn new() -> Self {
72 Self::default()
73 }
74
75 /// The number of functions in the section.
76 pub fn len(&self) -> u32 {
77 self.num_added
78 }
79
80 /// Determines if the section is empty.
81 pub fn is_empty(&self) -> bool {
82 self.num_added == 0
83 }
84
85 /// Define a function that will lift a core WebAssembly function to the canonical ABI.
86 pub fn lift<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> &mut Self
87 where
88 O: IntoIterator<Item = CanonicalOption>,
89 O::IntoIter: ExactSizeIterator,
90 {
91 let options = options.into_iter();
92 self.bytes.push(0x00);
93 self.bytes.push(0x00);
94 core_func_index.encode(&mut self.bytes);
95 options.len().encode(&mut self.bytes);
96 for option in options {
97 option.encode(&mut self.bytes);
98 }
99 type_index.encode(&mut self.bytes);
100 self.num_added += 1;
101 self
102 }
103
104 /// Define a function that will lower a canonical ABI function to a core WebAssembly function.
105 pub fn lower<O>(&mut self, func_index: u32, options: O) -> &mut Self
106 where
107 O: IntoIterator<Item = CanonicalOption>,
108 O::IntoIter: ExactSizeIterator,
109 {
110 let options = options.into_iter();
111 self.bytes.push(0x01);
112 self.bytes.push(0x00);
113 func_index.encode(&mut self.bytes);
114 options.len().encode(&mut self.bytes);
115 for option in options {
116 option.encode(&mut self.bytes);
117 }
118 self.num_added += 1;
119 self
120 }
121
122 /// Defines a function which will create an owned handle to the resource
123 /// specified by `ty_index`.
124 pub fn resource_new(&mut self, ty_index: u32) -> &mut Self {
125 self.bytes.push(0x02);
126 ty_index.encode(&mut self.bytes);
127 self.num_added += 1;
128 self
129 }
130
131 /// Defines a function which will drop the specified type of handle.
132 pub fn resource_drop(&mut self, ty_index: u32) -> &mut Self {
133 self.bytes.push(0x03);
134 ty_index.encode(&mut self.bytes);
135 self.num_added += 1;
136 self
137 }
138
139 /// Defines a function which will return the representation of the specified
140 /// resource type.
141 pub fn resource_rep(&mut self, ty_index: u32) -> &mut Self {
142 self.bytes.push(0x04);
143 ty_index.encode(&mut self.bytes);
144 self.num_added += 1;
145 self
146 }
147
148 /// Defines a function which will spawns a new thread by invoking a shared
149 /// function of type `ty_index`.
150 pub fn thread_spawn(&mut self, ty_index: u32) -> &mut Self {
151 self.bytes.push(0x05);
152 ty_index.encode(&mut self.bytes);
153 self.num_added += 1;
154 self
155 }
156
157 /// Defines a function which will return the number of threads that can be
158 /// expected to execute concurrently.
159 pub fn thread_hw_concurrency(&mut self) -> &mut Self {
160 self.bytes.push(0x06);
161 self.num_added += 1;
162 self
163 }
164}
165
166impl Encode for CanonicalFunctionSection {
167 fn encode(&self, sink: &mut Vec<u8>) {
168 encode_section(sink, self.num_added, &self.bytes);
169 }
170}
171
172impl ComponentSection for CanonicalFunctionSection {
173 fn id(&self) -> u8 {
174 ComponentSectionId::CanonicalFunction.into()
175 }
176}
177