wasm_encoder/core/names.rs
1use crate::{encoding_size, CustomSection, Encode, Section, SectionId};
2use alloc::borrow::Cow;
3use alloc::vec;
4use 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)]
28pub struct NameSection {
29 bytes: Vec<u8>,
30}
31
32enum 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
56impl 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
204impl Encode for NameSection {
205 fn encode(&self, sink: &mut Vec<u8>) {
206 self.as_custom().encode(sink);
207 }
208}
209
210impl 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)]
222pub struct NameMap {
223 bytes: Vec<u8>,
224 count: u32,
225}
226
227impl 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
258impl 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)]
270pub struct IndirectNameMap {
271 bytes: Vec<u8>,
272 count: u32,
273}
274
275impl 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
300impl Encode for IndirectNameMap {
301 fn encode(&self, sink: &mut Vec<u8>) {
302 self.count.encode(sink);
303 sink.extend(&self.bytes);
304 }
305}