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}