1 | use crate::{encoding_size, CustomSection, Encode, Section, SectionId}; |
---|---|
2 | use alloc::borrow::Cow; |
3 | use alloc::vec; |
4 | use alloc::vec::Vec; |
5 | |
6 | /// An encoder for the custom `name` section. |
7 | /// |
8 | /// # Example |
9 | /// |
10 | /// ``` |
11 | /// use wasm_encoder::{Module, NameSection, NameMap}; |
12 | /// |
13 | /// let mut names = NameSection::new(); |
14 | /// names.module("the module name"); |
15 | /// |
16 | /// let mut function_names = NameMap::new(); |
17 | /// function_names.append(0, "name of function 0"); |
18 | /// function_names.append(1, "a better function"); |
19 | /// function_names.append(3, "the best function"); |
20 | /// names.functions(&function_names); |
21 | /// |
22 | /// let mut module = Module::new(); |
23 | /// module.section(&names); |
24 | /// |
25 | /// let wasm_bytes = module.finish(); |
26 | /// ``` |
27 | #[derive(Clone, Debug, Default)] |
28 | pub struct NameSection { |
29 | bytes: Vec<u8>, |
30 | } |
31 | |
32 | enum Subsection { |
33 | // Currently specified in the wasm spec's appendix |
34 | Module = 0, |
35 | Function = 1, |
36 | Local = 2, |
37 | |
38 | // specified as part of the extended name section proposal |
39 | // |
40 | // https://github.com/WebAssembly/extended-name-section/blob/main/proposals/extended-name-section/Overview.md |
41 | Label = 3, |
42 | Type = 4, |
43 | Table = 5, |
44 | Memory = 6, |
45 | Global = 7, |
46 | Element = 8, |
47 | Data = 9, |
48 | |
49 | // https://github.com/WebAssembly/gc/issues/193 |
50 | Field = 10, |
51 | |
52 | // https://github.com/WebAssembly/exception-handling/pull/213 |
53 | Tag = 11, |
54 | } |
55 | |
56 | impl NameSection { |
57 | /// Creates a new blank `name` custom section. |
58 | pub fn new() -> Self { |
59 | Self::default() |
60 | } |
61 | |
62 | /// Appends a module name subsection to this section. |
63 | /// |
64 | /// This will indicate that the name of the entire module should be the |
65 | /// `name` specified. Note that this should be encoded first before other |
66 | /// subsections. |
67 | pub fn module(&mut self, name: &str) { |
68 | let len = encoding_size(u32::try_from(name.len()).unwrap()); |
69 | self.subsection_header(Subsection::Module, len + name.len()); |
70 | name.encode(&mut self.bytes); |
71 | } |
72 | |
73 | /// Appends a subsection for the names of all functions in this wasm module. |
74 | /// |
75 | /// Function names are declared in the `names` map provided where the index |
76 | /// in the map corresponds to the wasm index of the function. This section |
77 | /// should come after the module name subsection (if present) and before the |
78 | /// locals subsection (if present). |
79 | pub fn functions(&mut self, names: &NameMap) { |
80 | self.subsection_header(Subsection::Function, names.size()); |
81 | names.encode(&mut self.bytes); |
82 | } |
83 | |
84 | /// Appends a subsection for the names of locals within functions in this |
85 | /// wasm module. |
86 | /// |
87 | /// This section should come after the function name subsection (if present) |
88 | /// and before the labels subsection (if present). |
89 | pub fn locals(&mut self, names: &IndirectNameMap) { |
90 | self.subsection_header(Subsection::Local, names.size()); |
91 | names.encode(&mut self.bytes); |
92 | } |
93 | |
94 | /// Appends a subsection for the names of labels within functions in this |
95 | /// wasm module. |
96 | /// |
97 | /// This section should come after the local name subsection (if present) |
98 | /// and before the type subsection (if present). |
99 | pub fn labels(&mut self, names: &IndirectNameMap) { |
100 | self.subsection_header(Subsection::Label, names.size()); |
101 | names.encode(&mut self.bytes); |
102 | } |
103 | |
104 | /// Appends a subsection for the names of all types in this wasm module. |
105 | /// |
106 | /// This section should come after the label name subsection (if present) |
107 | /// and before the table subsection (if present). |
108 | pub fn types(&mut self, names: &NameMap) { |
109 | self.subsection_header(Subsection::Type, names.size()); |
110 | names.encode(&mut self.bytes); |
111 | } |
112 | |
113 | /// Appends a subsection for the names of all tables in this wasm module. |
114 | /// |
115 | /// This section should come after the type name subsection (if present) |
116 | /// and before the memory subsection (if present). |
117 | pub fn tables(&mut self, names: &NameMap) { |
118 | self.subsection_header(Subsection::Table, names.size()); |
119 | names.encode(&mut self.bytes); |
120 | } |
121 | |
122 | /// Appends a subsection for the names of all memories in this wasm module. |
123 | /// |
124 | /// This section should come after the table name subsection (if present) |
125 | /// and before the global subsection (if present). |
126 | pub fn memories(&mut self, names: &NameMap) { |
127 | self.subsection_header(Subsection::Memory, names.size()); |
128 | names.encode(&mut self.bytes); |
129 | } |
130 | |
131 | /// Appends a subsection for the names of all globals in this wasm module. |
132 | /// |
133 | /// This section should come after the memory name subsection (if present) |
134 | /// and before the element subsection (if present). |
135 | pub fn globals(&mut self, names: &NameMap) { |
136 | self.subsection_header(Subsection::Global, names.size()); |
137 | names.encode(&mut self.bytes); |
138 | } |
139 | |
140 | /// Appends a subsection for the names of all elements in this wasm module. |
141 | /// |
142 | /// This section should come after the global name subsection (if present) |
143 | /// and before the data subsection (if present). |
144 | pub fn elements(&mut self, names: &NameMap) { |
145 | self.subsection_header(Subsection::Element, names.size()); |
146 | names.encode(&mut self.bytes); |
147 | } |
148 | |
149 | /// Appends a subsection for the names of all data in this wasm module. |
150 | /// |
151 | /// This section should come after the element name subsection (if present) |
152 | /// and before the field subsection (if present). |
153 | pub fn data(&mut self, names: &NameMap) { |
154 | self.subsection_header(Subsection::Data, names.size()); |
155 | names.encode(&mut self.bytes); |
156 | } |
157 | |
158 | /// Appends a subsection for the names of all tags in this wasm module. |
159 | /// |
160 | /// This section should come after the data name subsection (if present). |
161 | pub fn tag(&mut self, names: &NameMap) { |
162 | self.subsection_header(Subsection::Tag, names.size()); |
163 | names.encode(&mut self.bytes); |
164 | } |
165 | |
166 | /// Appends a subsection for the names of fields within types in this |
167 | /// wasm module. |
168 | /// |
169 | /// This section should come after the data name subsection (if present) |
170 | /// and before the tag subsection (if present). |
171 | pub fn fields(&mut self, names: &IndirectNameMap) { |
172 | self.subsection_header(Subsection::Field, names.size()); |
173 | names.encode(&mut self.bytes); |
174 | } |
175 | |
176 | /// Appends a subsection for the names of all tags in this wasm module. |
177 | /// |
178 | /// This section should come after the field name subsection (if present). |
179 | pub fn tags(&mut self, names: &NameMap) { |
180 | self.subsection_header(Subsection::Tag, names.size()); |
181 | names.encode(&mut self.bytes); |
182 | } |
183 | |
184 | /// Appends a raw subsection with the given id and data. |
185 | pub fn raw(&mut self, id: u8, data: &[u8]) { |
186 | self.bytes.push(id); |
187 | data.encode(&mut self.bytes); |
188 | } |
189 | |
190 | fn subsection_header(&mut self, id: Subsection, len: usize) { |
191 | self.bytes.push(id as u8); |
192 | len.encode(&mut self.bytes); |
193 | } |
194 | |
195 | /// View the encoded section as a CustomSection. |
196 | pub fn as_custom<'a>(&'a self) -> CustomSection<'a> { |
197 | CustomSection { |
198 | name: "name".into(), |
199 | data: Cow::Borrowed(&self.bytes), |
200 | } |
201 | } |
202 | } |
203 | |
204 | impl Encode for NameSection { |
205 | fn encode(&self, sink: &mut Vec<u8>) { |
206 | self.as_custom().encode(sink); |
207 | } |
208 | } |
209 | |
210 | impl Section for NameSection { |
211 | fn id(&self) -> u8 { |
212 | SectionId::Custom.into() |
213 | } |
214 | } |
215 | |
216 | /// A map used to name items in a wasm module, organized by naming each |
217 | /// individual index. |
218 | /// |
219 | /// This is used in conjunction with [`NameSection::functions`] and simlar |
220 | /// methods. |
221 | #[derive(Clone, Debug, Default)] |
222 | pub struct NameMap { |
223 | bytes: Vec<u8>, |
224 | count: u32, |
225 | } |
226 | |
227 | impl NameMap { |
228 | /// Creates a new empty `NameMap`. |
229 | pub fn new() -> NameMap { |
230 | NameMap { |
231 | bytes: vec![], |
232 | count: 0, |
233 | } |
234 | } |
235 | |
236 | /// Adds a an entry where the item at `idx` has the `name` specified. |
237 | /// |
238 | /// Note that indices should be appended in ascending order of the index |
239 | /// value. Each index may only be named once, but not all indices must be |
240 | /// named (e.g. `0 foo; 1 bar; 7 qux` is valid but `0 foo; 0 bar` is not). |
241 | /// Names do not have to be unique (e.g. `0 foo; 1 foo; 2 foo` is valid). |
242 | pub fn append(&mut self, idx: u32, name: &str) { |
243 | idx.encode(&mut self.bytes); |
244 | name.encode(&mut self.bytes); |
245 | self.count += 1; |
246 | } |
247 | |
248 | pub(crate) fn size(&self) -> usize { |
249 | encoding_size(self.count) + self.bytes.len() |
250 | } |
251 | |
252 | /// Returns whether no names have been added to this map. |
253 | pub fn is_empty(&self) -> bool { |
254 | self.count == 0 |
255 | } |
256 | } |
257 | |
258 | impl Encode for NameMap { |
259 | fn encode(&self, sink: &mut Vec<u8>) { |
260 | self.count.encode(sink); |
261 | sink.extend(&self.bytes); |
262 | } |
263 | } |
264 | |
265 | /// A map used to describe names with two levels of indirection, as opposed to a |
266 | /// [`NameMap`] which has one level of indirection. |
267 | /// |
268 | /// This naming map is used with [`NameSection::locals`], for example. |
269 | #[derive(Clone, Debug, Default)] |
270 | pub struct IndirectNameMap { |
271 | bytes: Vec<u8>, |
272 | count: u32, |
273 | } |
274 | |
275 | impl IndirectNameMap { |
276 | /// Creates a new empty name map. |
277 | pub fn new() -> IndirectNameMap { |
278 | IndirectNameMap { |
279 | bytes: vec![], |
280 | count: 0, |
281 | } |
282 | } |
283 | |
284 | /// Adds a new entry where the item at `idx` has sub-items named within |
285 | /// `names` as specified. |
286 | /// |
287 | /// For example if this is describing local names then `idx` is a function |
288 | /// index where the indexes within `names` are local indices. |
289 | pub fn append(&mut self, idx: u32, names: &NameMap) { |
290 | idx.encode(&mut self.bytes); |
291 | names.encode(&mut self.bytes); |
292 | self.count += 1; |
293 | } |
294 | |
295 | fn size(&self) -> usize { |
296 | encoding_size(self.count) + self.bytes.len() |
297 | } |
298 | } |
299 | |
300 | impl Encode for IndirectNameMap { |
301 | fn encode(&self, sink: &mut Vec<u8>) { |
302 | self.count.encode(sink); |
303 | sink.extend(&self.bytes); |
304 | } |
305 | } |
306 |
Definitions
Learn Rust with the experts
Find out more