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