Skip to main content

wasm_encoder/core/
names.rs

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