1use std::borrow::Cow;
2
3use 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)]
27pub struct NameSection {
28 bytes: Vec<u8>,
29}
30
31enum 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
55impl 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
203impl Encode for NameSection {
204 fn encode(&self, sink: &mut Vec<u8>) {
205 self.as_custom().encode(sink);
206 }
207}
208
209impl 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)]
221pub struct NameMap {
222 bytes: Vec<u8>,
223 count: u32,
224}
225
226impl 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
257impl 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)]
269pub struct IndirectNameMap {
270 bytes: Vec<u8>,
271 count: u32,
272}
273
274impl 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
299impl Encode for IndirectNameMap {
300 fn encode(&self, sink: &mut Vec<u8>) {
301 self.count.encode(sink);
302 sink.extend(&self.bytes);
303 }
304}
305

Provided by KDAB

Privacy Policy
Learn Rust with the experts
Find out more