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