├── .gitignore ├── Cargo.toml ├── ChangeLog.md ├── README.md ├── examples ├── fibonacci.rs └── simple_add.rs └── src ├── builder.rs ├── lib.rs ├── main.rs ├── module.rs ├── ops.rs ├── types.rs └── util.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "web-assembler" 3 | version = "0.1.1" 4 | license = "MIT OR Apache-2.0" 5 | authors = ["Sunrin SHIMURA (keen) <3han5chou7@gmail.com>"] 6 | description = "An in memory wasm assembler for Rust." 7 | readme = "README.md" 8 | documentation = "https://docs.rs/web-assembler" 9 | repository = "https://github.com/KeenS/WebAssembler-rs" 10 | keywords = ["wasm", "webassembly", "assembler"] 11 | categories = ["web-programming", "wasm"] 12 | 13 | 14 | [dependencies] 15 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | # 0.1.1 2 | ## Fixes 3 | * fix the type of `if`. See #4 4 | # 0.1.0 5 | first release 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | An in memory wasm assembler for Rust. This is useful when you run a lang to wasm compiler written in Rust on web browser. 2 | -------------------------------------------------------------------------------- /examples/fibonacci.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate web_assembler as wasm; 3 | 4 | use wasm::builder::*; 5 | use wasm::*; 6 | use std::fs::File; 7 | use std::io::Write; 8 | use std::env; 9 | 10 | fn main() { 11 | let out_file = env::args().nth(1).expect("argument missing: output file"); 12 | 13 | let mut md = ModuleBuilder::new(); 14 | // function to create must be the 0th function of the module... 15 | let fib = FunctionIndex(0).into(); 16 | let f = FunctionBuilder::new(funtype!((i32) -> i32)) 17 | .code(|cb, params| { 18 | let n = params[0]; 19 | cb.get_local(n) 20 | .constant(1i32) 21 | .i32_sub() 22 | .call(fib) 23 | .get_local(n) 24 | .constant(2i32) 25 | .i32_sub() 26 | .call(fib) 27 | .i32_add() 28 | .return_() 29 | }) 30 | .build(); 31 | md.new_function(f); 32 | 33 | let module = md.build(); 34 | let mut code = Vec::new(); 35 | module.dump(&mut code); 36 | let mut out = File::create(out_file).unwrap(); 37 | out.write(&code).unwrap(); 38 | } 39 | -------------------------------------------------------------------------------- /examples/simple_add.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate web_assembler as wasm; 3 | 4 | use wasm::builder::*; 5 | use wasm::*; 6 | use std::fs::File; 7 | use std::io::Write; 8 | use std::env; 9 | 10 | fn main() { 11 | let out_file = env::args().nth(1).expect("argument missing: output file"); 12 | 13 | let mut md = ModuleBuilder::new(); 14 | let f = FunctionBuilder::new(funtype!((i32, i32) -> i32)) 15 | .code(|cb, params| { 16 | let a = params[0]; 17 | let b = params[1]; 18 | cb.get_local(a).get_local(b).i32_add().return_() 19 | }) 20 | .build(); 21 | md.new_function(f); 22 | 23 | let module = md.build(); 24 | let mut code = Vec::new(); 25 | module.dump(&mut code); 26 | let mut out = File::create(out_file).unwrap(); 27 | out.write(&code).unwrap(); 28 | } 29 | -------------------------------------------------------------------------------- /src/builder.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Range, RangeFrom}; 2 | 3 | use module::*; 4 | use types::*; 5 | use ops; 6 | use ops::Op; 7 | pub struct ModuleBuilder(Module); 8 | 9 | macro_rules! gen_add { 10 | ($name: tt ($param: tt, $ty: ty) -> $ret: tt, $field: tt) => { 11 | pub fn $name(&mut self, ty: $ty) -> $ret { 12 | 13 | match &mut (self.0).$field { 14 | &mut Some(ref mut v) => { 15 | v.push(ty); 16 | $ret::new((v.len() - 1) as u32) 17 | }, 18 | none => { 19 | *none = Some(vec![ty]); 20 | $ret::new(0) 21 | }, 22 | } 23 | } 24 | }; 25 | 26 | (prv, $name: tt ($param: tt, $ty: ty) -> $ret: tt, $field: tt) => { 27 | fn $name(&mut self, ty: $ty) -> $ret { 28 | 29 | match &mut (self.0).$field { 30 | &mut Some(ref mut v) => { 31 | v.push(ty); 32 | $ret::new((v.len() - 1) as u32) 33 | }, 34 | none => { 35 | *none = Some(vec![ty]); 36 | $ret::new(0) 37 | }, 38 | } 39 | } 40 | }; 41 | } 42 | 43 | impl ModuleBuilder { 44 | pub fn new() -> Self { 45 | ModuleBuilder(Module { 46 | unknown: None, 47 | types: None, 48 | imports: None, 49 | functions: None, 50 | tables: None, 51 | memories: None, 52 | globals: None, 53 | exports: None, 54 | start: None, 55 | elements: None, 56 | codes: None, 57 | data: None, 58 | }) 59 | } 60 | 61 | pub fn function_index_of(&self, i: ImportIndex) -> Result { 62 | self.0.function_index_of(i) 63 | } 64 | 65 | fn nimports(&self) -> u32 { 66 | self.0 67 | .imports 68 | .iter() 69 | .flat_map(|i| i.iter()) 70 | .filter(|i| i.kind.is_function()) 71 | .count() as u32 72 | } 73 | 74 | fn resolve_functions(&mut self) { 75 | let nimports = self.nimports(); 76 | // resolve codes 77 | for f in self.0.codes.iter_mut().flat_map(|f| f.iter_mut()) { 78 | f.resolve_functions(nimports) 79 | } 80 | // resolve tables 81 | for e in self.0.elements.iter_mut().flat_map(|e| e.iter_mut()) { 82 | for index in e.elems.iter_mut() { 83 | use InnerFunctionSpaceIndex::*; 84 | match index.0 { 85 | Function(ref mut f) => { 86 | f.0 += nimports; 87 | } 88 | _ => (), 89 | } 90 | } 91 | } 92 | } 93 | 94 | pub fn build(mut self) -> Module { 95 | self.resolve_functions(); 96 | let nimports = self.nimports(); 97 | self.0.start.as_mut().map(|i| i.0 += nimports); 98 | self.0 99 | } 100 | 101 | 102 | gen_add!(add_type(ty, FuncType) -> TypeIndex, 103 | types); 104 | gen_add!(add_import(import, ImportEntry) -> ImportIndex, 105 | imports); 106 | gen_add!(prv, add_function(func, Function) -> FunctionIndex, 107 | functions); 108 | gen_add!(add_table(table, TableType) -> TableIndex, 109 | tables); 110 | gen_add!(add_memory(memory, MemoryType) -> MemoryIndex, 111 | memories); 112 | gen_add!(add_global(global, GlobalVariable) -> GlobalIndex, 113 | globals); 114 | gen_add!(add_export(export, ExportEntry) -> ExportIndex, 115 | exports); 116 | pub fn start(&mut self, index: FunctionIndex) { 117 | self.0.start = Some(index); 118 | } 119 | gen_add!(add_element(element, ElemSegment) -> ElementIndex, 120 | elements); 121 | gen_add!(prv, add_code(code, FunctionBody) -> CodeIndex, 122 | codes); 123 | gen_add!(add_data(data, DataSegment) -> DataIndex, 124 | data); 125 | 126 | pub fn new_function(&mut self, (t, body): (FuncType, FunctionBody)) -> FunctionIndex { 127 | let tidx = self.add_type(t); 128 | let fidx = self.add_function(Function(tidx)); 129 | let cidx = self.add_code(body); 130 | assert_eq!(*cidx, *fidx); 131 | fidx 132 | } 133 | 134 | pub fn new_data(&mut self, idx: MemoryIndex, offset: Code, data: Vec) -> DataIndex { 135 | let seg = DataSegment { 136 | index: idx, 137 | offset: InitExpr(offset), 138 | data: data, 139 | }; 140 | self.add_data(seg) 141 | } 142 | 143 | pub fn new_global(&mut self, ty: GlobalType, init: Code) -> GlobalIndex { 144 | self.add_global(GlobalVariable { 145 | ty: ty, 146 | init: InitExpr(init), 147 | }) 148 | } 149 | } 150 | 151 | pub trait NewTable { 152 | fn new_table(&mut self, element: ElemType, range: T) -> TableIndex; 153 | } 154 | 155 | impl NewTable> for ModuleBuilder { 156 | fn new_table(&mut self, element: ElemType, range: Range) -> TableIndex { 157 | let table = TableType { 158 | element: element, 159 | limits: ResizableLimits::new(range.start).max(range.end), 160 | }; 161 | self.add_table(table) 162 | } 163 | } 164 | 165 | impl NewTable> for ModuleBuilder { 166 | fn new_table(&mut self, element: ElemType, range: RangeFrom) -> TableIndex { 167 | let table = TableType { 168 | element: element, 169 | limits: ResizableLimits::new(range.start), 170 | }; 171 | self.add_table(table) 172 | } 173 | } 174 | 175 | pub trait NewMemory { 176 | fn new_memory(&mut self, range: T) -> MemoryIndex; 177 | } 178 | 179 | impl NewMemory> for ModuleBuilder { 180 | fn new_memory(&mut self, range: Range) -> MemoryIndex { 181 | let memory = MemoryType { limits: ResizableLimits::new(range.start).max(range.end) }; 182 | self.add_memory(memory) 183 | } 184 | } 185 | 186 | impl NewMemory> for ModuleBuilder { 187 | fn new_memory(&mut self, range: RangeFrom) -> MemoryIndex { 188 | let memory = MemoryType { limits: ResizableLimits::new(range.start) }; 189 | self.add_memory(memory) 190 | } 191 | } 192 | 193 | pub trait Export { 194 | fn export>(&mut self, name: S, index: T) -> ExportIndex; 195 | } 196 | 197 | 198 | macro_rules! gen_export { 199 | ($name: ty, $variant: tt) => { 200 | impl Export<$name> for ModuleBuilder { 201 | fn export>(&mut self, name: S, index: $name) -> ExportIndex { 202 | let entry = ExportEntry { 203 | field: name.into(), 204 | kind: ExportKind::$variant(index), 205 | }; 206 | self.add_export(entry) 207 | } 208 | } 209 | } 210 | } 211 | 212 | gen_export!(FunctionIndex, Function); 213 | gen_export!(TableIndex, Table); 214 | gen_export!(MemoryIndex, Memory); 215 | gen_export!(GlobalIndex, Global); 216 | 217 | 218 | pub trait Import { 219 | fn import(&mut self, module: S, name: T, index: Ty) -> ImportIndex 220 | where S: Into, 221 | T: Into; 222 | } 223 | 224 | macro_rules! gen_import { 225 | ($name: ty, $variant: tt) => { 226 | impl Import<$name> for ModuleBuilder { 227 | fn import(&mut self, module: S, name: T, index: $name) -> ImportIndex 228 | where S: Into, 229 | T: Into 230 | { 231 | let entry = ImportEntry { 232 | module: module.into(), 233 | field: name.into(), 234 | kind: ImportKind::$variant(index), 235 | }; 236 | self.add_import(entry) 237 | } 238 | } 239 | } 240 | } 241 | 242 | gen_import!(TypeIndex, Function); 243 | gen_import!(TableType, Table); 244 | gen_import!(MemoryType, Memory); 245 | gen_import!(GlobalType, Global); 246 | 247 | 248 | pub trait NewFunction { 249 | fn new_function(&mut self, t: T, body: FunctionBody) -> FunctionIndex; 250 | } 251 | 252 | impl NewFunction for ModuleBuilder { 253 | fn new_function(&mut self, t: TypeIndex, body: FunctionBody) -> FunctionIndex { 254 | let fidx = self.add_function(Function(t)); 255 | let cidx = self.add_code(body); 256 | assert_eq!(*cidx, *fidx); 257 | fidx 258 | } 259 | } 260 | 261 | impl NewFunction for ModuleBuilder { 262 | fn new_function(&mut self, t: FuncType, body: FunctionBody) -> FunctionIndex { 263 | self.new_function((t, body)) 264 | } 265 | } 266 | 267 | 268 | 269 | pub struct CodeBuilder { 270 | code: Vec, 271 | } 272 | 273 | macro_rules! gen_builder { 274 | ($variant: path, $fname: ident) => { 275 | pub fn $fname(mut self) -> Self { 276 | self.code.push($variant); 277 | self 278 | } 279 | }; 280 | ($variant: tt {$($arg: ident : $argty: ty, )* }, $fname: ident) => { 281 | pub fn $fname(mut self, $($arg: $argty, )*) -> Self { 282 | self.code.push($variant { 283 | $($arg : $arg, )* 284 | }); 285 | self 286 | } 287 | }; 288 | 289 | ($variant: tt { $arg: ident : $argty: ty $(, $args: ident : $argtys: ty)* }, $fname: ident) => { 290 | gen_builder!($variant {$arg: $argty $(, $args : $argtys)*, }, $fname); 291 | }; 292 | 293 | ($variant: tt [$($arg: ident : $argty: ty, )*], $fname: ident) => { 294 | pub fn $fname(mut self, $($arg: $argty, )*) -> Self { 295 | self.code.push($variant($($arg, )*)); 296 | self 297 | } 298 | }; 299 | 300 | ($variant: tt [ $arg: ident : $argty: ty $(, $args: ident : $argtys: ty)*], $fname: ident) => { 301 | gen_builder!($variant [$arg: $argty $(, $args : $argtys)*, ], $fname); 302 | }; 303 | } 304 | 305 | macro_rules! gen_memory_builder { 306 | ($variant: tt, $fname: ident, $align: expr) => { 307 | pub fn $fname(mut self, offset: u32) -> Self { 308 | let imm = ops::MemoryImmediate{ 309 | flags: $align - 3, 310 | offset: offset 311 | }; 312 | self.code.push($variant{imm: imm}); 313 | self 314 | } 315 | }; 316 | 317 | } 318 | use Op::*; 319 | 320 | impl CodeBuilder { 321 | pub fn new() -> Self { 322 | CodeBuilder { code: Vec::new() } 323 | } 324 | 325 | pub fn build(self) -> Code { 326 | Code(self.code) 327 | } 328 | 329 | gen_builder!(Unreachable, unreachable); 330 | gen_builder!(Nop, nop); 331 | gen_builder!(Block { sig: BlockType }, block); 332 | gen_builder!(Loop { sig: BlockType }, loop_); 333 | gen_builder!(If { sig: BlockType }, if_); 334 | gen_builder!(Else, else_); 335 | gen_builder!(End, end); 336 | gen_builder!(Br { depth: u32 }, br); 337 | gen_builder!(BrIf { depth: u32 }, br_if); 338 | pub fn br_table(mut self, table: Vec, default: u32) -> Self { 339 | self.code 340 | .push(BrTable(ops::BrTarget { 341 | table: table, 342 | default_target: default, 343 | })); 344 | self 345 | } 346 | gen_builder!(Return, return_); 347 | 348 | gen_builder!(Call { index: FunctionSpaceIndex }, call); 349 | gen_builder!(CallIndirect { 350 | index: TypeIndex, 351 | reserved: bool, 352 | }, 353 | call_indirect); 354 | 355 | gen_builder!(Drop, drop); 356 | gen_builder!(Select, select); 357 | 358 | gen_builder!(GetLocal[idx: LocalIndex], get_local); 359 | gen_builder!(SetLocal[idx: LocalIndex], set_local); 360 | gen_builder!(TeeLocal[idx: LocalIndex], tee_local); 361 | gen_builder!(GetGlobal[idx: GlobalIndex], get_global); 362 | gen_builder!(SetGlobal[idx: GlobalIndex], set_global); 363 | 364 | // TODO: generate with-flag API too. 365 | gen_memory_builder!(I32Load, i32_load, 5); 366 | gen_memory_builder!(I64Load, i64_load, 6); 367 | gen_memory_builder!(F32Load, f32_load, 5); 368 | gen_memory_builder!(F64Load, f64_load, 6); 369 | gen_memory_builder!(I32Load8S, i32_load8_s, 3); 370 | gen_memory_builder!(I32Load8U, i32_load8_u, 3); 371 | gen_memory_builder!(I32Load16S, i32_load16_s, 4); 372 | gen_memory_builder!(I32Load16U, i32_load16_u, 4); 373 | gen_memory_builder!(I64Load8S, i64_load8_s, 3); 374 | gen_memory_builder!(I64Load8U, i64_load8_u, 3); 375 | gen_memory_builder!(I64Load16S, i64_load16_s, 4); 376 | gen_memory_builder!(I64Load16U, i64_load16_u, 4); 377 | gen_memory_builder!(I64load32S, i64_load32_s, 5); 378 | gen_memory_builder!(I64load32U, i64_load32_u, 5); 379 | gen_memory_builder!(I32Store, i32_store, 5); 380 | gen_memory_builder!(I64Store, i64_store, 6); 381 | gen_memory_builder!(F32Store, f32_store, 5); 382 | gen_memory_builder!(F64Store, f64_store, 6); 383 | gen_memory_builder!(I32Store8, i32_store8, 3); 384 | gen_memory_builder!(I32Store16, i32_store16, 4); 385 | gen_memory_builder!(I64Store8, i64_store8, 3); 386 | gen_memory_builder!(I64Store16, i64_store16, 4); 387 | gen_memory_builder!(I64Store32, i64_store32, 5); 388 | gen_builder!(CurrentMemory { reserved: bool }, current_memory); 389 | gen_builder!(GrowMemory { reserved: bool }, grow_memory); 390 | 391 | 392 | pub fn constant(mut self, c: C) -> Self 393 | where Op: From 394 | { 395 | self.code.push(Op::from(c)); 396 | self 397 | } 398 | 399 | gen_builder!(I32Eqz, i32_eqz); 400 | gen_builder!(I32Eq, i32_eq); 401 | gen_builder!(I32NE, i32_ne); 402 | gen_builder!(I32LtS, i32_lt_s); 403 | gen_builder!(I32LtU, i32_lt_u); 404 | gen_builder!(I32GtS, i32_gt_s); 405 | gen_builder!(I32GtU, i32_gt_u); 406 | gen_builder!(I32LeS, i32_le_s); 407 | gen_builder!(I32LeU, i32_le_u); 408 | gen_builder!(I32GeS, i32_ge_s); 409 | gen_builder!(I32GeU, i32_ge_u); 410 | gen_builder!(I64Eqz, i64_eqz); 411 | gen_builder!(I64Eq, i64_eq); 412 | gen_builder!(I64Ne, i64_ne); 413 | gen_builder!(I64LtS, i64_lt_s); 414 | gen_builder!(I64LtU, i64_lt_u); 415 | gen_builder!(I64GtS, i64_gt_s); 416 | gen_builder!(I64GtU, i64_gt_u); 417 | gen_builder!(I64LeS, i64_le_s); 418 | gen_builder!(I64LeU, i64_le_u); 419 | gen_builder!(I64GeS, i64_ge_s); 420 | gen_builder!(I64GeU, i64_ge_u); 421 | gen_builder!(F32Eq, f32_eq); 422 | gen_builder!(F32Ne, f32_ne); 423 | gen_builder!(F32Lt, f32_lt); 424 | gen_builder!(F32Gt, f32_gt); 425 | gen_builder!(F32Le, f32_le); 426 | gen_builder!(F32Ge, f32_ge); 427 | gen_builder!(F64Eq, f64_eq); 428 | gen_builder!(F64Ne, f64_ne); 429 | gen_builder!(F64Lt, f64_lt); 430 | gen_builder!(F64Gt, f64_gt); 431 | gen_builder!(F64Le, f64_le); 432 | gen_builder!(F64Ge, f64_ge); 433 | 434 | gen_builder!(I32Clz, i32_clz); 435 | gen_builder!(I32Ctz, i32_ctz); 436 | gen_builder!(I32Popcnt, i32_popcnt); 437 | gen_builder!(I32Add, i32_add); 438 | gen_builder!(I32Sub, i32_sub); 439 | gen_builder!(I32Mul, i32_mul); 440 | gen_builder!(I32DivS, i32_div_s); 441 | gen_builder!(I32DivU, i32_div_u); 442 | gen_builder!(I32RemS, i32_rem_s); 443 | gen_builder!(I32RemU, i32_rem_u); 444 | gen_builder!(I32And, i32_and); 445 | gen_builder!(I32Or, i32_or); 446 | gen_builder!(I32Xor, i32_xor); 447 | gen_builder!(I32Shl, i32_shl); 448 | gen_builder!(I32ShrS, i32_shr_s); 449 | gen_builder!(I32ShrU, i32_shr_u); 450 | gen_builder!(I32Rotl, i32_rotl); 451 | gen_builder!(I32Rotr, i32_rotr); 452 | gen_builder!(I64Clz, i64_clz); 453 | gen_builder!(I64Ctz, i64_ctz); 454 | gen_builder!(I64Popcnt, i64_popcnt); 455 | gen_builder!(I64Add, i64_add); 456 | gen_builder!(I64Sub, i64_sub); 457 | gen_builder!(I64Mul, i64_mul); 458 | gen_builder!(I64DivS, i64_div_s); 459 | gen_builder!(I64DivU, i64_div_u); 460 | gen_builder!(I64RemS, i64_rem_s); 461 | gen_builder!(I64RemU, i64_rem_u); 462 | gen_builder!(I64And, i64_and); 463 | gen_builder!(I64Or, i64_or); 464 | gen_builder!(I64Xor, i64_xor); 465 | gen_builder!(I64Shl, i64_shl); 466 | gen_builder!(I64ShrS, i64_shr_s); 467 | gen_builder!(I64ShrU, i64_shr_u); 468 | gen_builder!(I64Rotl, i64_rotl); 469 | gen_builder!(I64Rotr, i64_rotr); 470 | gen_builder!(F32Abs, f32_abs); 471 | gen_builder!(F32Neg, f32_neg); 472 | gen_builder!(F32Ceil, f32_ceil); 473 | gen_builder!(F32Floor, f32_floor); 474 | gen_builder!(F32Trunc, f32_trunc); 475 | gen_builder!(F32Nearest, f32_nearest); 476 | gen_builder!(F32Sqrt, f32_sqrt); 477 | gen_builder!(F32Add, f32_add); 478 | gen_builder!(F32Sub, f32_sub); 479 | gen_builder!(F32Mul, f32_mul); 480 | gen_builder!(F32Div, f32_div); 481 | gen_builder!(F32Min, f32_min); 482 | gen_builder!(F32Max, f32_max); 483 | gen_builder!(F32Copysign, f32_copysign); 484 | gen_builder!(F64Abs, f64_abs); 485 | gen_builder!(F64Neg, f64_neg); 486 | gen_builder!(F64Ceil, f64_ceil); 487 | gen_builder!(F64Floor, f64_floor); 488 | gen_builder!(F64Trunc, f64_trunc); 489 | gen_builder!(F64Nearest, f64_nearest); 490 | gen_builder!(F64Sqrt, f64_sqrt); 491 | gen_builder!(F64Add, f64_add); 492 | gen_builder!(F64Sub, f64_sub); 493 | gen_builder!(F64Mul, f64_mul); 494 | gen_builder!(F64Div, f64_div); 495 | gen_builder!(F64Min, f64_min); 496 | gen_builder!(F64Max, f64_max); 497 | gen_builder!(F64Copysign, f64_copysign); 498 | 499 | gen_builder!(I32wrapI64, i32_wrap_i64); 500 | gen_builder!(I32TruncSF32, i32_trunc_s_f32); 501 | gen_builder!(I32TruncUF32, i32_trunc_u_f32); 502 | gen_builder!(I32TruncSF64, i32_trunc_s_f64); 503 | gen_builder!(I32TruncUF64, i32_trunc_u_f64); 504 | gen_builder!(I64ExtendSI32, i64_extend_s_i32); 505 | gen_builder!(I64ExtendUI32, i64_extend_u_i32); 506 | gen_builder!(I64TruncSF32, i64_trunc_s_f32); 507 | gen_builder!(I64TruncUF32, i64_trunc_u_f32); 508 | gen_builder!(I64TruncSF64, i64_trunc_s_f64); 509 | gen_builder!(I64TruncUF64, i64_trunc_u_f64); 510 | gen_builder!(F32ConvertSI32, f32_convert_s_i32); 511 | gen_builder!(F32ConvertUI32, f32_convert_u_i32); 512 | gen_builder!(F32ConvertSI64, f32_convert_s_i64); 513 | gen_builder!(F32ConvertUI64, f32_convert_u_i64); 514 | gen_builder!(F32DemoteF64, f32_demote_f64); 515 | gen_builder!(F64ConvertSI32, f64_convert_s_i32); 516 | gen_builder!(F64ConvertUI32, f64_convert_u_i32); 517 | gen_builder!(F64ConvertSI64, f64_convert_s_i64); 518 | gen_builder!(F64ConvertUI64, f64_convert_u_i64); 519 | gen_builder!(F64PromoteF32, f64_promote_f32); 520 | 521 | gen_builder!(I32ReinterpretF32, i32_reinterpret_f32); 522 | gen_builder!(I64ReinterpretF64, i64_reinterpret_f64); 523 | gen_builder!(F32ReinterpretI32, f32_reinterpret_i32); 524 | gen_builder!(F64ReinterpretI64, f64_reinterpret_i64); 525 | } 526 | 527 | pub struct FunctionBuilder { 528 | ty: FuncType, 529 | args: Vec, 530 | locals: Vec, 531 | cb: CodeBuilder, 532 | } 533 | 534 | 535 | impl FunctionBuilder { 536 | pub fn new(ty: FuncType) -> Self { 537 | let args = (0..ty.params.len()) 538 | .map(|i| LocalIndex::new(i as u32)) 539 | .collect(); 540 | let fb = FunctionBuilder { 541 | ty: ty, 542 | args: args, 543 | locals: Vec::new(), 544 | cb: CodeBuilder::new(), 545 | }; 546 | fb 547 | } 548 | 549 | pub fn build(self) -> (FuncType, FunctionBody) { 550 | // TODO: compact local entry 551 | let locals = self.locals 552 | .into_iter() 553 | .map(|l| LocalEntry { count: 1, ty: l }) 554 | .collect(); 555 | let body = FunctionBody { 556 | locals: locals, 557 | code: self.cb.build(), 558 | }; 559 | (self.ty, body) 560 | } 561 | 562 | pub fn new_local(&mut self, ty: ValueType) -> LocalIndex { 563 | self.locals.push(ty); 564 | LocalIndex::new((self.ty.params.len() + self.locals.len() - 1) as u32) 565 | } 566 | 567 | pub fn new_locals(&mut self, tys: Vec) -> Vec { 568 | tys.into_iter() 569 | .map(|ty| { 570 | self.locals.push(ty); 571 | LocalIndex::new((self.ty.params.len() + self.locals.len() - 1) as u32) 572 | }) 573 | .collect() 574 | } 575 | 576 | pub fn code CodeBuilder>(mut self, f: F) -> Self { 577 | self.cb = f(self.cb, &self.args); 578 | self 579 | } 580 | } 581 | 582 | #[macro_export] 583 | macro_rules! ty { 584 | (i32) => (ValueType::I32); 585 | (i64) => (ValueType::I64); 586 | (f32) => (ValueType::F32); 587 | (f64) => (ValueType::F64); 588 | } 589 | 590 | 591 | #[macro_export] 592 | macro_rules! ty_vec { 593 | ($($t: tt, )*) => { 594 | vec!($(ty!($t), )*) 595 | }; 596 | 597 | ($t: tt $(, $ts: tt)*) => { 598 | vec!(ty!($t) $(, ty!($ts))*) 599 | }; 600 | } 601 | 602 | #[macro_export] 603 | macro_rules! funtype { 604 | (($($params: tt)*) -> $ret: tt) => { 605 | FuncType { 606 | params: ty_vec!($($params)*), 607 | ret: Some(ty!($ret)) 608 | } 609 | }; 610 | (($($params: tt)*)) => { 611 | FuncType { 612 | params: ty_vec!($($params)*), 613 | ret: None, 614 | } 615 | }; 616 | } 617 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | mod module; 3 | mod types; 4 | mod ops; 5 | pub mod builder; 6 | 7 | pub use types::*; 8 | pub use module::*; 9 | pub use ops::*; 10 | 11 | pub trait Dump { 12 | fn dump(&self, buf: &mut Vec) -> usize; 13 | } 14 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate web_assembler as wasm; 3 | 4 | use wasm::*; 5 | use wasm::builder::*; 6 | 7 | use std::io::Write; 8 | use std::fs::File; 9 | 10 | fn main() { 11 | let mut mb = ModuleBuilder::new(); 12 | let f = mb.new_function(FunctionBuilder::new(funtype!((i32, i32) -> i32)) 13 | .code(|cb, args| { 14 | cb.constant(-3256).get_local(args[0]).i32_store(4) 15 | }) 16 | .build()); 17 | mb.export("addTwo", f); 18 | let module = mb.build(); 19 | 20 | let mut buf = Vec::new(); 21 | module.dump(&mut buf); 22 | 23 | let mut out = File::create(std::env::args().nth(1).unwrap()).unwrap(); 24 | let _ = out.write(&buf).unwrap(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/module.rs: -------------------------------------------------------------------------------- 1 | use util::*; 2 | use types::*; 3 | use Dump; 4 | 5 | #[derive(Debug, Clone)] 6 | pub struct Module { 7 | // version: usize 8 | pub unknown: Option, 9 | pub types: Option>, 10 | pub imports: Option>, 11 | pub functions: Option>, 12 | pub tables: Option>, 13 | pub memories: Option>, 14 | pub globals: Option>, 15 | pub exports: Option>, 16 | pub start: Option, 17 | pub elements: Option>, 18 | pub codes: Option>, 19 | pub data: Option>, 20 | } 21 | 22 | impl Module { 23 | pub fn function_index_of(&self, i: ImportIndex) -> Result { 24 | match self.imports { 25 | None => return Err(i), 26 | Some(ref imports) => { 27 | if let Some(&ImportEntry {kind: ImportKind::Function(_) ,..}) =imports.get(*i as usize) { 28 | let index = imports.iter() 29 | .take(*i as usize) 30 | .filter(|e| e.kind.is_function()) 31 | .count(); 32 | Ok(FunctionSpaceIndex(InnerFunctionSpaceIndex::Import(ImportedFunctionIndex(index as u32)))) 33 | } else { 34 | return Err(i) 35 | } 36 | } 37 | } 38 | } 39 | } 40 | 41 | impl Dump for Module { 42 | fn dump(&self, buf: &mut Vec) -> usize { 43 | let mut size = 0; 44 | 45 | let magic = b"\0asm"; 46 | size += write_slice(buf, magic); 47 | 48 | let version = 0x01; 49 | size += write_uint32(buf, version); 50 | 51 | 52 | let mut v = Vec::new(); 53 | macro_rules! do_section { 54 | ($code: expr, $field: expr) => {{ 55 | let field = &$field; 56 | for xs in field { 57 | v.clear(); 58 | let mut section_size = 0; 59 | let sec = &mut v; 60 | section_size += write_varuint32(sec, xs.len() as u32); 61 | for x in xs { 62 | section_size += x.dump(sec); 63 | } 64 | 65 | size += write_uint8(buf, $code); 66 | size += write_varuint32(buf, section_size as u32); 67 | size += write_slice(buf, &sec); 68 | } 69 | }}; 70 | } 71 | 72 | 73 | do_section!(0x01, self.types); 74 | do_section!(0x02, self.imports); 75 | do_section!(0x03, self.functions); 76 | do_section!(0x04, self.tables); 77 | do_section!(0x05, self.memories); 78 | do_section!(0x06, self.globals); 79 | do_section!(0x07, self.exports); 80 | { 81 | for index in self.start { 82 | v.clear(); 83 | let mut section_size = 0; 84 | let sec = &mut v; 85 | section_size += write_varuint32(sec, *index); 86 | 87 | size += write_uint8(buf, 0x08); 88 | size += write_varuint32(buf, section_size as u32); 89 | size += write_slice(buf, &sec); 90 | } 91 | } 92 | do_section!(0x09, self.elements); 93 | do_section!(0x0a, self.codes); 94 | do_section!(0x0b, self.data); 95 | size 96 | } 97 | } 98 | 99 | #[derive(Debug, Clone)] 100 | pub struct ImportEntry { 101 | pub module: String, 102 | pub field: String, 103 | pub kind: ImportKind, 104 | } 105 | 106 | #[derive(Debug, Clone)] 107 | pub enum ImportKind { 108 | Function(TypeIndex), 109 | Table(TableType), 110 | Memory(MemoryType), 111 | Global(GlobalType), 112 | } 113 | 114 | impl ImportKind { 115 | pub fn is_function(&self) -> bool { 116 | if let &ImportKind::Function(_) = self { 117 | true 118 | } else { 119 | false 120 | } 121 | } 122 | 123 | pub fn is_table(&self) -> bool { 124 | if let &ImportKind::Table(_) = self { 125 | true 126 | } else { 127 | false 128 | } 129 | } 130 | 131 | pub fn is_memory(&self) -> bool { 132 | if let &ImportKind::Memory(_) = self { 133 | true 134 | } else { 135 | false 136 | } 137 | } 138 | 139 | pub fn is_global(&self) -> bool { 140 | if let &ImportKind::Global(_) = self { 141 | true 142 | } else { 143 | false 144 | } 145 | } 146 | } 147 | 148 | impl Dump for ImportEntry { 149 | fn dump(&self, buf: &mut Vec) -> usize { 150 | let mut size = 0; 151 | let module = &self.module; 152 | let field = &self.field; 153 | 154 | size += write_varuint32(buf, module.len() as u32); 155 | size += write_slice(buf, module.as_bytes()); 156 | 157 | size += write_varuint32(buf, field.len() as u32); 158 | size += write_slice(buf, field.as_bytes()); 159 | 160 | size += self.kind.dump(buf); 161 | 162 | size 163 | 164 | } 165 | } 166 | 167 | impl Dump for ImportKind { 168 | fn dump(&self, buf: &mut Vec) -> usize { 169 | use self::ImportKind::*; 170 | let mut size = 0; 171 | match self { 172 | &Function(ref id) => { 173 | size += write_uint8(buf, 0); 174 | size += write_varuint32(buf, **id); 175 | size 176 | } 177 | &Table(ref tbl) => { 178 | size += write_uint8(buf, 1); 179 | size += tbl.dump(buf); 180 | size 181 | } 182 | &Memory(ref m) => { 183 | size += write_uint8(buf, 2); 184 | size += m.dump(buf); 185 | size 186 | 187 | } 188 | &Global(ref glb) => { 189 | size += write_uint8(buf, 3); 190 | size += glb.dump(buf); 191 | size 192 | 193 | } 194 | 195 | } 196 | } 197 | } 198 | 199 | 200 | #[derive(Debug, Clone)] 201 | pub struct Function(pub TypeIndex); 202 | 203 | impl Dump for Function { 204 | fn dump(&self, buf: &mut Vec) -> usize { 205 | write_varuint32(buf, *self.0) 206 | } 207 | } 208 | 209 | #[derive(Debug, Clone)] 210 | pub struct GlobalVariable { 211 | pub ty: GlobalType, 212 | pub init: InitExpr, 213 | } 214 | 215 | 216 | impl Dump for GlobalVariable { 217 | fn dump(&self, buf: &mut Vec) -> usize { 218 | let mut size = 0; 219 | 220 | size += self.ty.dump(buf); 221 | size += self.init.dump(buf); 222 | size 223 | } 224 | } 225 | 226 | #[derive(Debug, Clone)] 227 | pub struct ExportEntry { 228 | pub field: String, 229 | pub kind: ExportKind, 230 | } 231 | 232 | #[derive(Debug, Clone)] 233 | pub enum ExportKind { 234 | Function(FunctionIndex), 235 | Table(TableIndex), 236 | Memory(MemoryIndex), 237 | Global(GlobalIndex), 238 | } 239 | 240 | impl Dump for ExportEntry { 241 | fn dump(&self, buf: &mut Vec) -> usize { 242 | let mut size = 0; 243 | let field = &self.field; 244 | 245 | size += write_varuint32(buf, field.len() as u32); 246 | size += write_slice(buf, field.as_bytes()); 247 | 248 | size += self.kind.dump(buf); 249 | 250 | size 251 | } 252 | } 253 | 254 | impl Dump for ExportKind { 255 | fn dump(&self, buf: &mut Vec) -> usize { 256 | use self::ExportKind::*; 257 | let mut size = 0; 258 | match self { 259 | &Function(ref i) => { 260 | size += write_uint8(buf, 0); 261 | size += write_varuint32(buf, **i); 262 | } 263 | &Table(ref i) => { 264 | size += write_uint8(buf, 1); 265 | size += write_varuint32(buf, **i); 266 | } 267 | &Memory(ref i) => { 268 | size += write_uint8(buf, 2); 269 | size += write_varuint32(buf, **i); 270 | } 271 | &Global(ref i) => { 272 | size += write_uint8(buf, 3); 273 | size += write_varuint32(buf, **i); 274 | } 275 | } 276 | size 277 | } 278 | } 279 | 280 | #[derive(Debug, Clone)] 281 | pub struct ElemSegment { 282 | pub index: TableIndex, 283 | pub offset: InitExpr, 284 | pub elems: Vec, 285 | } 286 | 287 | impl Dump for ElemSegment { 288 | fn dump(&self, buf: &mut Vec) -> usize { 289 | let mut size = 0; 290 | 291 | let elems = &self.elems; 292 | assert_eq!(*self.index, 0); 293 | size += write_varuint32(buf, *self.index); 294 | size += self.offset.dump(buf); 295 | 296 | size += write_varuint32(buf, elems.len() as u32); 297 | for e in elems.iter() { 298 | size += write_varuint32(buf, **e); 299 | } 300 | size 301 | } 302 | } 303 | 304 | #[derive(Debug, Clone)] 305 | pub struct FunctionBody { 306 | pub locals: Vec, 307 | pub code: Code, 308 | } 309 | 310 | impl FunctionBody { 311 | pub fn resolve_functions(&mut self, nimports: u32) { 312 | for op in self.code.0.iter_mut() { 313 | op.resolve_functions(nimports) 314 | } 315 | } 316 | } 317 | 318 | 319 | impl Dump for FunctionBody { 320 | fn dump(&self, buf: &mut Vec) -> usize { 321 | let mut size = 0; 322 | 323 | let locals = &self.locals; 324 | let code = &self.code; 325 | 326 | let body_size; 327 | let mut body = Vec::new(); 328 | { 329 | let mut size = 0; 330 | let buf = &mut body; 331 | size += write_varuint32(buf, locals.len() as u32); 332 | for l in locals.iter() { 333 | size += l.dump(buf); 334 | } 335 | 336 | size += code.dump(buf); 337 | size += write_uint8(buf, 0x0b); 338 | 339 | body_size = size; 340 | } 341 | 342 | 343 | size += write_varuint32(buf, body_size as u32); 344 | size += write_slice(buf, &body); 345 | 346 | size 347 | } 348 | } 349 | 350 | 351 | #[derive(Debug, Clone)] 352 | pub struct LocalEntry { 353 | pub count: u32, 354 | pub ty: ValueType, 355 | } 356 | 357 | 358 | impl Dump for LocalEntry { 359 | fn dump(&self, buf: &mut Vec) -> usize { 360 | let mut size = 0; 361 | 362 | size += write_varuint32(buf, self.count); 363 | size += self.ty.dump(buf); 364 | 365 | size 366 | } 367 | } 368 | 369 | #[derive(Debug, Clone)] 370 | pub struct DataSegment { 371 | pub index: MemoryIndex, 372 | pub offset: InitExpr, 373 | pub data: Vec, 374 | } 375 | 376 | impl Dump for DataSegment { 377 | fn dump(&self, buf: &mut Vec) -> usize { 378 | let mut size = 0; 379 | 380 | let data = &self.data; 381 | 382 | size += write_varuint32(buf, *self.index); 383 | size += self.offset.dump(buf); 384 | 385 | size += write_varuint32(buf, data.len() as u32); 386 | size += write_slice(buf, data); 387 | 388 | size 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /src/ops.rs: -------------------------------------------------------------------------------- 1 | use types::*; 2 | use util::*; 3 | use Dump; 4 | 5 | #[derive(Debug, Clone)] 6 | pub enum Op { 7 | Unreachable, 8 | Nop, 9 | Block { sig: BlockType }, 10 | Loop { sig: BlockType }, 11 | If { sig: BlockType }, 12 | Else, 13 | End, 14 | // TODO: use relative block index 15 | Br { depth: u32 }, 16 | BrIf { depth: u32 }, 17 | BrTable(BrTarget), 18 | Return, 19 | Call { index: FunctionSpaceIndex }, 20 | // TODO: use table index 21 | CallIndirect { index: TypeIndex, reserved: bool }, 22 | Drop, 23 | Select, 24 | GetLocal(LocalIndex), 25 | SetLocal(LocalIndex), 26 | TeeLocal(LocalIndex), 27 | GetGlobal(GlobalIndex), 28 | SetGlobal(GlobalIndex), 29 | I32Load { imm: MemoryImmediate }, 30 | I64Load { imm: MemoryImmediate }, 31 | F32Load { imm: MemoryImmediate }, 32 | F64Load { imm: MemoryImmediate }, 33 | I32Load8S { imm: MemoryImmediate }, 34 | I32Load8U { imm: MemoryImmediate }, 35 | I32Load16S { imm: MemoryImmediate }, 36 | I32Load16U { imm: MemoryImmediate }, 37 | I64Load8S { imm: MemoryImmediate }, 38 | I64Load8U { imm: MemoryImmediate }, 39 | I64Load16S { imm: MemoryImmediate }, 40 | I64Load16U { imm: MemoryImmediate }, 41 | I64load32S { imm: MemoryImmediate }, 42 | I64load32U { imm: MemoryImmediate }, 43 | I32Store { imm: MemoryImmediate }, 44 | I64Store { imm: MemoryImmediate }, 45 | F32Store { imm: MemoryImmediate }, 46 | F64Store { imm: MemoryImmediate }, 47 | I32Store8 { imm: MemoryImmediate }, 48 | I32Store16 { imm: MemoryImmediate }, 49 | I64Store8 { imm: MemoryImmediate }, 50 | I64Store16 { imm: MemoryImmediate }, 51 | I64Store32 { imm: MemoryImmediate }, 52 | CurrentMemory { reserved: bool }, 53 | GrowMemory { reserved: bool }, 54 | I32Const(i32), 55 | I64Const(i64), 56 | F32Const(f32), 57 | F64Const(f64), 58 | I32Eqz, 59 | I32Eq, 60 | I32NE, 61 | I32LtS, 62 | I32LtU, 63 | I32GtS, 64 | I32GtU, 65 | I32LeS, 66 | I32LeU, 67 | I32GeS, 68 | I32GeU, 69 | I64Eqz, 70 | I64Eq, 71 | I64Ne, 72 | I64LtS, 73 | I64LtU, 74 | I64GtS, 75 | I64GtU, 76 | I64LeS, 77 | I64LeU, 78 | I64GeS, 79 | I64GeU, 80 | F32Eq, 81 | F32Ne, 82 | F32Lt, 83 | F32Gt, 84 | F32Le, 85 | F32Ge, 86 | F64Eq, 87 | F64Ne, 88 | F64Lt, 89 | F64Gt, 90 | F64Le, 91 | F64Ge, 92 | I32Clz, 93 | I32Ctz, 94 | I32Popcnt, 95 | I32Add, 96 | I32Sub, 97 | I32Mul, 98 | I32DivS, 99 | I32DivU, 100 | I32RemS, 101 | I32RemU, 102 | I32And, 103 | I32Or, 104 | I32Xor, 105 | I32Shl, 106 | I32ShrS, 107 | I32ShrU, 108 | I32Rotl, 109 | I32Rotr, 110 | I64Clz, 111 | I64Ctz, 112 | I64Popcnt, 113 | I64Add, 114 | I64Sub, 115 | I64Mul, 116 | I64DivS, 117 | I64DivU, 118 | I64RemS, 119 | I64RemU, 120 | I64And, 121 | I64Or, 122 | I64Xor, 123 | I64Shl, 124 | I64ShrS, 125 | I64ShrU, 126 | I64Rotl, 127 | I64Rotr, 128 | F32Abs, 129 | F32Neg, 130 | F32Ceil, 131 | F32Floor, 132 | F32Trunc, 133 | F32Nearest, 134 | F32Sqrt, 135 | F32Add, 136 | F32Sub, 137 | F32Mul, 138 | F32Div, 139 | F32Min, 140 | F32Max, 141 | F32Copysign, 142 | F64Abs, 143 | F64Neg, 144 | F64Ceil, 145 | F64Floor, 146 | F64Trunc, 147 | F64Nearest, 148 | F64Sqrt, 149 | F64Add, 150 | F64Sub, 151 | F64Mul, 152 | F64Div, 153 | F64Min, 154 | F64Max, 155 | F64Copysign, 156 | I32wrapI64, 157 | I32TruncSF32, 158 | I32TruncUF32, 159 | I32TruncSF64, 160 | I32TruncUF64, 161 | I64ExtendSI32, 162 | I64ExtendUI32, 163 | I64TruncSF32, 164 | I64TruncUF32, 165 | I64TruncSF64, 166 | I64TruncUF64, 167 | F32ConvertSI32, 168 | F32ConvertUI32, 169 | F32ConvertSI64, 170 | F32ConvertUI64, 171 | F32DemoteF64, 172 | F64ConvertSI32, 173 | F64ConvertUI32, 174 | F64ConvertSI64, 175 | F64ConvertUI64, 176 | F64PromoteF32, 177 | I32ReinterpretF32, 178 | I64ReinterpretF64, 179 | F32ReinterpretI32, 180 | F64ReinterpretI64, 181 | } 182 | 183 | impl Op { 184 | pub fn resolve_functions(&mut self, nimports: u32) { 185 | match *self { 186 | Op::Call { ref mut index } => { 187 | use InnerFunctionSpaceIndex::*; 188 | match index.0 { 189 | Function(ref mut f) => { 190 | f.0 += nimports; 191 | } 192 | _ => (), 193 | } 194 | } 195 | _ => (), 196 | } 197 | } 198 | } 199 | 200 | impl Dump for Op { 201 | fn dump(&self, buf: &mut Vec) -> usize { 202 | use self::Op::*; 203 | fn do_imm(buf: &mut Vec, imm: &MemoryImmediate, code: u8) -> usize { 204 | let mut size = 0; 205 | 206 | size += write_uint8(buf, code); 207 | size += imm.dump(buf); 208 | 209 | size 210 | 211 | }; 212 | let mut size = 0; 213 | 214 | match self { 215 | &Unreachable => size += write_uint8(buf, 0x00), 216 | &Nop => size += write_uint8(buf, 0x01), 217 | &Block { ref sig } => { 218 | size += write_uint8(buf, 0x02); 219 | size += sig.dump(buf); 220 | } 221 | &Loop { ref sig } => { 222 | size += write_uint8(buf, 0x03); 223 | size += sig.dump(buf); 224 | } 225 | &If { ref sig } => { 226 | size += write_uint8(buf, 0x04); 227 | size += sig.dump(buf); 228 | } 229 | &Else => size += write_uint8(buf, 0x05), 230 | &End => size += write_uint8(buf, 0x0b), 231 | &Br { ref depth } => { 232 | size += write_uint8(buf, 0x0c); 233 | size += write_varuint32(buf, *depth); 234 | } 235 | &BrIf { ref depth } => { 236 | size += write_uint8(buf, 0x0d); 237 | size += write_varuint32(buf, *depth); 238 | } 239 | &BrTable(ref br_target) => { 240 | size += write_uint8(buf, 0x0e); 241 | size += br_target.dump(buf); 242 | } 243 | &Return => size += write_uint8(buf, 0x0f), 244 | &Call { ref index } => { 245 | size += write_uint8(buf, 0x10); 246 | size += write_varuint32(buf, **index); 247 | } 248 | 249 | &CallIndirect { 250 | ref index, 251 | ref reserved, 252 | } => { 253 | size += write_uint8(buf, 0x11); 254 | size += write_varuint32(buf, **index); 255 | size += write_varuint1(buf, *reserved as u8); 256 | } 257 | &Drop => size += write_uint8(buf, 0x1a), 258 | &Select => size += write_uint8(buf, 0x1b), 259 | &GetLocal(ref i) => { 260 | size += write_uint8(buf, 0x20); 261 | size += write_varuint32(buf, **i); 262 | } 263 | &SetLocal(ref i) => { 264 | size += write_uint8(buf, 0x21); 265 | size += write_varuint32(buf, **i); 266 | } 267 | &TeeLocal(ref i) => { 268 | size += write_uint8(buf, 0x22); 269 | size += write_varuint32(buf, **i); 270 | } 271 | &GetGlobal(ref i) => { 272 | size += write_uint8(buf, 0x023); 273 | size += write_varuint32(buf, **i); 274 | } 275 | &SetGlobal(ref i) => { 276 | size += write_uint8(buf, 0x24); 277 | size += write_varuint32(buf, **i); 278 | } 279 | &I32Load { ref imm } => size += do_imm(buf, imm, 0x28), 280 | &I64Load { ref imm } => size += do_imm(buf, imm, 0x29), 281 | &F32Load { ref imm } => size += do_imm(buf, imm, 0x2a), 282 | &F64Load { ref imm } => size += do_imm(buf, imm, 0x2b), 283 | &I32Load8S { ref imm } => size += do_imm(buf, imm, 0x2c), 284 | &I32Load8U { ref imm } => size += do_imm(buf, imm, 0x2d), 285 | &I32Load16S { ref imm } => size += do_imm(buf, imm, 0x2e), 286 | &I32Load16U { ref imm } => size += do_imm(buf, imm, 0x2f), 287 | &I64Load8S { ref imm } => size += do_imm(buf, imm, 0x30), 288 | &I64Load8U { ref imm } => size += do_imm(buf, imm, 0x31), 289 | &I64Load16S { ref imm } => size += do_imm(buf, imm, 0x32), 290 | &I64Load16U { ref imm } => size += do_imm(buf, imm, 0x33), 291 | &I64load32S { ref imm } => size += do_imm(buf, imm, 0x34), 292 | &I64load32U { ref imm } => size += do_imm(buf, imm, 0x35), 293 | &I32Store { ref imm } => size += do_imm(buf, imm, 0x36), 294 | &I64Store { ref imm } => size += do_imm(buf, imm, 0x37), 295 | &F32Store { ref imm } => size += do_imm(buf, imm, 0x38), 296 | &F64Store { ref imm } => size += do_imm(buf, imm, 0x39), 297 | &I32Store8 { ref imm } => size += do_imm(buf, imm, 0x3a), 298 | &I32Store16 { ref imm } => size += do_imm(buf, imm, 0x3b), 299 | &I64Store8 { ref imm } => size += do_imm(buf, imm, 0x3c), 300 | &I64Store16 { ref imm } => size += do_imm(buf, imm, 0x3d), 301 | &I64Store32 { ref imm } => size += do_imm(buf, imm, 0x3e), 302 | &CurrentMemory { ref reserved } => { 303 | size += write_uint8(buf, 0x3f); 304 | size += write_varuint1(buf, *reserved as u8); 305 | } 306 | &GrowMemory { ref reserved } => { 307 | size += write_uint8(buf, 0x40); 308 | size += write_varuint1(buf, *reserved as u8); 309 | } 310 | &I32Const(ref i) => { 311 | size += write_uint8(buf, 0x41); 312 | size += write_varint32(buf, *i); 313 | } 314 | &I64Const(ref i) => { 315 | size += write_uint8(buf, 0x42); 316 | size += write_varint64(buf, *i); 317 | } 318 | &F32Const(ref f) => { 319 | size += write_uint8(buf, 0x43); 320 | unsafe { 321 | size += write_uint32(buf, ::std::mem::transmute::(*f)); 322 | } 323 | } 324 | &F64Const(ref f) => { 325 | size += write_uint8(buf, 0x44); 326 | unsafe { 327 | size += write_uint64(buf, ::std::mem::transmute::(*f)); 328 | } 329 | } 330 | &I32Eqz => size += write_uint8(buf, 0x45), 331 | &I32Eq => size += write_uint8(buf, 0x46), 332 | &I32NE => size += write_uint8(buf, 0x47), 333 | &I32LtS => size += write_uint8(buf, 0x48), 334 | &I32LtU => size += write_uint8(buf, 0x49), 335 | &I32GtS => size += write_uint8(buf, 0x4a), 336 | &I32GtU => size += write_uint8(buf, 0x4b), 337 | &I32LeS => size += write_uint8(buf, 0x4c), 338 | &I32LeU => size += write_uint8(buf, 0x4d), 339 | &I32GeS => size += write_uint8(buf, 0x4e), 340 | &I32GeU => size += write_uint8(buf, 0x4f), 341 | &I64Eqz => size += write_uint8(buf, 0x50), 342 | &I64Eq => size += write_uint8(buf, 0x51), 343 | &I64Ne => size += write_uint8(buf, 0x52), 344 | &I64LtS => size += write_uint8(buf, 0x53), 345 | &I64LtU => size += write_uint8(buf, 0x54), 346 | &I64GtS => size += write_uint8(buf, 0x55), 347 | &I64GtU => size += write_uint8(buf, 0x56), 348 | &I64LeS => size += write_uint8(buf, 0x57), 349 | &I64LeU => size += write_uint8(buf, 0x58), 350 | &I64GeS => size += write_uint8(buf, 0x59), 351 | &I64GeU => size += write_uint8(buf, 0x5a), 352 | &F32Eq => size += write_uint8(buf, 0x5b), 353 | &F32Ne => size += write_uint8(buf, 0x5c), 354 | &F32Lt => size += write_uint8(buf, 0x5d), 355 | &F32Gt => size += write_uint8(buf, 0x5e), 356 | &F32Le => size += write_uint8(buf, 0x5f), 357 | &F32Ge => size += write_uint8(buf, 0x60), 358 | &F64Eq => size += write_uint8(buf, 0x61), 359 | &F64Ne => size += write_uint8(buf, 0x62), 360 | &F64Lt => size += write_uint8(buf, 0x63), 361 | &F64Gt => size += write_uint8(buf, 0x64), 362 | &F64Le => size += write_uint8(buf, 0x65), 363 | &F64Ge => size += write_uint8(buf, 0x66), 364 | &I32Clz => size += write_uint8(buf, 0x67), 365 | &I32Ctz => size += write_uint8(buf, 0x68), 366 | &I32Popcnt => size += write_uint8(buf, 0x69), 367 | &I32Add => size += write_uint8(buf, 0x6a), 368 | &I32Sub => size += write_uint8(buf, 0x6b), 369 | &I32Mul => size += write_uint8(buf, 0x6c), 370 | &I32DivS => size += write_uint8(buf, 0x6d), 371 | &I32DivU => size += write_uint8(buf, 0x6e), 372 | &I32RemS => size += write_uint8(buf, 0x6f), 373 | &I32RemU => size += write_uint8(buf, 0x70), 374 | &I32And => size += write_uint8(buf, 0x71), 375 | &I32Or => size += write_uint8(buf, 0x72), 376 | &I32Xor => size += write_uint8(buf, 0x73), 377 | &I32Shl => size += write_uint8(buf, 0x74), 378 | &I32ShrS => size += write_uint8(buf, 0x75), 379 | &I32ShrU => size += write_uint8(buf, 0x76), 380 | &I32Rotl => size += write_uint8(buf, 0x77), 381 | &I32Rotr => size += write_uint8(buf, 0x78), 382 | &I64Clz => size += write_uint8(buf, 0x79), 383 | &I64Ctz => size += write_uint8(buf, 0x7a), 384 | &I64Popcnt => size += write_uint8(buf, 0x7b), 385 | &I64Add => size += write_uint8(buf, 0x7c), 386 | &I64Sub => size += write_uint8(buf, 0x7d), 387 | &I64Mul => size += write_uint8(buf, 0x7e), 388 | &I64DivS => size += write_uint8(buf, 0x7f), 389 | &I64DivU => size += write_uint8(buf, 0x80), 390 | &I64RemS => size += write_uint8(buf, 0x81), 391 | &I64RemU => size += write_uint8(buf, 0x82), 392 | &I64And => size += write_uint8(buf, 0x83), 393 | &I64Or => size += write_uint8(buf, 0x84), 394 | &I64Xor => size += write_uint8(buf, 0x85), 395 | &I64Shl => size += write_uint8(buf, 0x86), 396 | &I64ShrS => size += write_uint8(buf, 0x87), 397 | &I64ShrU => size += write_uint8(buf, 0x88), 398 | &I64Rotl => size += write_uint8(buf, 0x89), 399 | &I64Rotr => size += write_uint8(buf, 0x8a), 400 | &F32Abs => size += write_uint8(buf, 0x8b), 401 | &F32Neg => size += write_uint8(buf, 0x8c), 402 | &F32Ceil => size += write_uint8(buf, 0x8d), 403 | &F32Floor => size += write_uint8(buf, 0x8e), 404 | &F32Trunc => size += write_uint8(buf, 0x8f), 405 | &F32Nearest => size += write_uint8(buf, 0x90), 406 | &F32Sqrt => size += write_uint8(buf, 0x91), 407 | &F32Add => size += write_uint8(buf, 0x92), 408 | &F32Sub => size += write_uint8(buf, 0x93), 409 | &F32Mul => size += write_uint8(buf, 0x94), 410 | &F32Div => size += write_uint8(buf, 0x95), 411 | &F32Min => size += write_uint8(buf, 0x96), 412 | &F32Max => size += write_uint8(buf, 0x97), 413 | &F32Copysign => size += write_uint8(buf, 0x98), 414 | &F64Abs => size += write_uint8(buf, 0x99), 415 | &F64Neg => size += write_uint8(buf, 0x9a), 416 | &F64Ceil => size += write_uint8(buf, 0x9b), 417 | &F64Floor => size += write_uint8(buf, 0x9c), 418 | &F64Trunc => size += write_uint8(buf, 0x9d), 419 | &F64Nearest => size += write_uint8(buf, 0x9e), 420 | &F64Sqrt => size += write_uint8(buf, 0x9f), 421 | &F64Add => size += write_uint8(buf, 0xa0), 422 | &F64Sub => size += write_uint8(buf, 0xa1), 423 | &F64Mul => size += write_uint8(buf, 0xa2), 424 | &F64Div => size += write_uint8(buf, 0xa3), 425 | &F64Min => size += write_uint8(buf, 0xa4), 426 | &F64Max => size += write_uint8(buf, 0xa5), 427 | &F64Copysign => size += write_uint8(buf, 0xa6), 428 | &I32wrapI64 => size += write_uint8(buf, 0xa7), 429 | &I32TruncSF32 => size += write_uint8(buf, 0xa8), 430 | &I32TruncUF32 => size += write_uint8(buf, 0xa9), 431 | &I32TruncSF64 => size += write_uint8(buf, 0xaa), 432 | &I32TruncUF64 => size += write_uint8(buf, 0xab), 433 | &I64ExtendSI32 => size += write_uint8(buf, 0xac), 434 | &I64ExtendUI32 => size += write_uint8(buf, 0xad), 435 | &I64TruncSF32 => size += write_uint8(buf, 0xae), 436 | &I64TruncUF32 => size += write_uint8(buf, 0xaf), 437 | &I64TruncSF64 => size += write_uint8(buf, 0xb0), 438 | &I64TruncUF64 => size += write_uint8(buf, 0xb1), 439 | &F32ConvertSI32 => size += write_uint8(buf, 0xb2), 440 | &F32ConvertUI32 => size += write_uint8(buf, 0xb3), 441 | &F32ConvertSI64 => size += write_uint8(buf, 0xb4), 442 | &F32ConvertUI64 => size += write_uint8(buf, 0xb5), 443 | &F32DemoteF64 => size += write_uint8(buf, 0xb6), 444 | &F64ConvertSI32 => size += write_uint8(buf, 0xb7), 445 | &F64ConvertUI32 => size += write_uint8(buf, 0xb8), 446 | &F64ConvertSI64 => size += write_uint8(buf, 0xb9), 447 | &F64ConvertUI64 => size += write_uint8(buf, 0xba), 448 | &F64PromoteF32 => size += write_uint8(buf, 0xbb), 449 | &I32ReinterpretF32 => size += write_uint8(buf, 0xbc), 450 | &I64ReinterpretF64 => size += write_uint8(buf, 0xbd), 451 | &F32ReinterpretI32 => size += write_uint8(buf, 0xbe), 452 | &F64ReinterpretI64 => size += write_uint8(buf, 0xbf), 453 | }; 454 | size 455 | } 456 | } 457 | 458 | impl From for Op { 459 | fn from(i: i32) -> Self { 460 | Op::I32Const(i) 461 | } 462 | } 463 | impl From for Op { 464 | fn from(i: i64) -> Self { 465 | Op::I64Const(i) 466 | } 467 | } 468 | impl From for Op { 469 | fn from(f: f32) -> Self { 470 | Op::F32Const(f) 471 | } 472 | } 473 | impl From for Op { 474 | fn from(f: f64) -> Self { 475 | Op::F64Const(f) 476 | } 477 | } 478 | 479 | 480 | 481 | #[derive(Debug, Clone)] 482 | pub struct MemoryImmediate { 483 | pub flags: u32, 484 | pub offset: u32, 485 | } 486 | 487 | 488 | impl Dump for MemoryImmediate { 489 | fn dump(&self, buf: &mut Vec) -> usize { 490 | let mut size = 0; 491 | 492 | size += write_varuint32(buf, self.flags); 493 | size += write_varuint32(buf, self.offset); 494 | 495 | size 496 | } 497 | } 498 | 499 | 500 | #[derive(Debug, Clone)] 501 | pub struct BrTarget { 502 | // TODO: use relative block index 503 | pub table: Vec, 504 | pub default_target: u32, 505 | } 506 | 507 | impl Dump for BrTarget { 508 | fn dump(&self, buf: &mut Vec) -> usize { 509 | let mut size = 0; 510 | let table = &self.table; 511 | 512 | size += write_varuint32(buf, table.len() as u32); 513 | for t in table { 514 | size += write_varuint32(buf, *t); 515 | } 516 | 517 | size += write_varuint32(buf, self.default_target); 518 | 519 | size 520 | } 521 | } 522 | -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Deref; 2 | use util::*; 3 | use ops::Op; 4 | use Dump; 5 | 6 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 7 | pub enum ValueType { 8 | I32, 9 | I64, 10 | F32, 11 | F64, 12 | } 13 | 14 | 15 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 16 | pub struct BlockType(pub Option); 17 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 18 | pub enum ElemType { 19 | AnyFunc, 20 | } 21 | 22 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 23 | pub struct FuncType { 24 | pub params: Vec, 25 | pub ret: Option, 26 | } 27 | 28 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 29 | pub struct GlobalType { 30 | pub content: ValueType, 31 | pub mutable: bool, 32 | } 33 | 34 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 35 | pub struct TableType { 36 | pub element: ElemType, 37 | pub limits: ResizableLimits, 38 | } 39 | 40 | 41 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 42 | pub struct MemoryType { 43 | pub limits: ResizableLimits, 44 | } 45 | 46 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 47 | pub struct ResizableLimits { 48 | pub flags: u32, 49 | pub initial: u32, 50 | pub maximum: Option, 51 | } 52 | 53 | #[derive(Debug, Clone)] 54 | pub struct Code(pub Vec); 55 | 56 | #[derive(Debug, Clone)] 57 | pub struct InitExpr(pub Code); 58 | 59 | 60 | impl Dump for ValueType { 61 | fn dump(&self, buf: &mut Vec) -> usize { 62 | use self::ValueType::*; 63 | match self { 64 | &I32 => write_varint7(buf, -0x01), 65 | &I64 => write_varint7(buf, -0x02), 66 | &F32 => write_varint7(buf, -0x03), 67 | &F64 => write_varint7(buf, -0x04), 68 | } 69 | } 70 | } 71 | 72 | impl Dump for BlockType { 73 | fn dump(&self, buf: &mut Vec) -> usize { 74 | match &self.0 { 75 | &Some(ref v) => v.dump(buf), 76 | &None => write_varint7(buf, -0x40), 77 | } 78 | } 79 | } 80 | 81 | impl Dump for ElemType { 82 | fn dump(&self, buf: &mut Vec) -> usize { 83 | use self::ElemType::*; 84 | match self { 85 | &AnyFunc => write_varint7(buf, -0x10), 86 | } 87 | } 88 | } 89 | impl Dump for FuncType { 90 | fn dump(&self, buf: &mut Vec) -> usize { 91 | let params = &self.params; 92 | let ret = &self.ret; 93 | 94 | let mut size = 0; 95 | size += write_varint7(buf, -0x20); 96 | 97 | size += write_varuint32(buf, params.len() as u32); 98 | for param in params { 99 | size += param.dump(buf); 100 | } 101 | 102 | size += write_varuint1(buf, ret.is_some() as u8); 103 | for ret in ret { 104 | size += ret.dump(buf); 105 | } 106 | size 107 | } 108 | } 109 | 110 | impl Dump for GlobalType { 111 | fn dump(&self, buf: &mut Vec) -> usize { 112 | let mut size = 0; 113 | size += self.content.dump(buf); 114 | size += write_varuint1(buf, self.mutable as u8); 115 | size 116 | } 117 | } 118 | 119 | impl Dump for TableType { 120 | fn dump(&self, buf: &mut Vec) -> usize { 121 | let mut size = 0; 122 | size += self.element.dump(buf); 123 | size += self.limits.dump(buf); 124 | size 125 | } 126 | } 127 | 128 | impl Dump for MemoryType { 129 | fn dump(&self, buf: &mut Vec) -> usize { 130 | self.limits.dump(buf) 131 | } 132 | } 133 | 134 | 135 | impl ResizableLimits { 136 | pub fn new(limit: u32) -> Self { 137 | ResizableLimits { 138 | flags: 0, 139 | initial: limit, 140 | maximum: None, 141 | } 142 | } 143 | 144 | pub fn max(mut self, maximum: u32) -> Self { 145 | self.maximum = Some(maximum); 146 | self 147 | } 148 | 149 | /// unstable 150 | pub fn flags(mut self, flags: u32) -> Self { 151 | self.flags = flags; 152 | self 153 | } 154 | } 155 | 156 | impl Dump for ResizableLimits { 157 | fn dump(&self, buf: &mut Vec) -> usize { 158 | let mut size = 0; 159 | let flags = self.flags | (self.maximum.is_some() as u32); 160 | size += write_varuint32(buf, flags); 161 | size += write_varuint32(buf, self.initial); 162 | if let Some(m) = self.maximum { 163 | size += write_varuint32(buf, m); 164 | } 165 | size 166 | } 167 | } 168 | 169 | impl Dump for Code { 170 | fn dump(&self, buf: &mut Vec) -> usize { 171 | let mut size = 0; 172 | for op in self.0.iter() { 173 | size += op.dump(buf); 174 | } 175 | size 176 | } 177 | } 178 | 179 | 180 | impl Dump for InitExpr { 181 | fn dump(&self, buf: &mut Vec) -> usize { 182 | self.0.dump(buf) 183 | } 184 | } 185 | 186 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 187 | pub struct TypeIndex(u32); 188 | impl Deref for TypeIndex { 189 | type Target = u32; 190 | fn deref(&self) -> &u32 { 191 | &self.0 192 | } 193 | } 194 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 195 | pub struct ImportIndex(u32); 196 | impl Deref for ImportIndex { 197 | type Target = u32; 198 | fn deref(&self) -> &u32 { 199 | &self.0 200 | } 201 | } 202 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 203 | /// restrict to this crate 204 | pub struct FunctionIndex(pub u32); 205 | impl Deref for FunctionIndex { 206 | type Target = u32; 207 | fn deref(&self) -> &u32 { 208 | &self.0 209 | } 210 | } 211 | 212 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 213 | pub struct ImportedFunctionIndex(pub u32); 214 | 215 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 216 | pub enum InnerFunctionSpaceIndex { 217 | Import(ImportedFunctionIndex), 218 | Function(FunctionIndex), 219 | } 220 | 221 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 222 | pub struct FunctionSpaceIndex(pub InnerFunctionSpaceIndex); 223 | 224 | impl Deref for FunctionSpaceIndex { 225 | type Target = u32; 226 | fn deref(&self) -> &u32 { 227 | use self::InnerFunctionSpaceIndex::*; 228 | match self.0 { 229 | Import(ref i) => &i.0, 230 | Function(ref f) => &**f, 231 | } 232 | } 233 | } 234 | 235 | impl Into for FunctionIndex { 236 | fn into(self) -> FunctionSpaceIndex { 237 | FunctionSpaceIndex(InnerFunctionSpaceIndex::Function(self)) 238 | } 239 | } 240 | 241 | 242 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 243 | pub struct TableIndex(u32); 244 | impl Deref for TableIndex { 245 | type Target = u32; 246 | fn deref(&self) -> &u32 { 247 | &self.0 248 | } 249 | } 250 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 251 | pub struct MemoryIndex(u32); 252 | impl Deref for MemoryIndex { 253 | type Target = u32; 254 | fn deref(&self) -> &u32 { 255 | &self.0 256 | } 257 | } 258 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 259 | pub struct GlobalIndex(u32); 260 | impl Deref for GlobalIndex { 261 | type Target = u32; 262 | fn deref(&self) -> &u32 { 263 | &self.0 264 | } 265 | } 266 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 267 | pub struct ExportIndex(u32); 268 | impl Deref for ExportIndex { 269 | type Target = u32; 270 | fn deref(&self) -> &u32 { 271 | &self.0 272 | } 273 | } 274 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 275 | pub struct ElementIndex(u32); 276 | impl Deref for ElementIndex { 277 | type Target = u32; 278 | fn deref(&self) -> &u32 { 279 | &self.0 280 | } 281 | } 282 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 283 | pub struct CodeIndex(u32); 284 | impl Deref for CodeIndex { 285 | type Target = u32; 286 | fn deref(&self) -> &u32 { 287 | &self.0 288 | } 289 | } 290 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 291 | pub struct DataIndex(u32); 292 | impl Deref for DataIndex { 293 | type Target = u32; 294 | fn deref(&self) -> &u32 { 295 | &self.0 296 | } 297 | } 298 | 299 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 300 | pub struct LocalIndex(u32); 301 | impl Deref for LocalIndex { 302 | type Target = u32; 303 | fn deref(&self) -> &u32 { 304 | &self.0 305 | } 306 | } 307 | 308 | 309 | pub mod internal { 310 | use types::*; 311 | macro_rules! impl_new { 312 | ($name: tt) => { 313 | impl $name { 314 | pub fn new(u: u32) -> Self { 315 | $name(u) 316 | } 317 | } 318 | } 319 | } 320 | 321 | impl_new!(TypeIndex); 322 | impl_new!(ImportIndex); 323 | impl_new!(FunctionIndex); 324 | impl_new!(TableIndex); 325 | impl_new!(MemoryIndex); 326 | impl_new!(GlobalIndex); 327 | impl_new!(ExportIndex); 328 | impl_new!(ElementIndex); 329 | impl_new!(CodeIndex); 330 | impl_new!(DataIndex); 331 | 332 | impl_new!(LocalIndex); 333 | } 334 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | #[inline] 2 | pub fn write_uint8(buf: &mut Vec, u: u8) -> usize { 3 | buf.push(u); 4 | 1 5 | } 6 | 7 | #[inline] 8 | pub fn write_uint16(buf: &mut Vec, u: u16) -> usize { 9 | let mut size = 0; 10 | size += write_uint8(buf, (u & 0xff) as u8); 11 | size += write_uint8(buf, ((u >> 8) & 0xff) as u8); 12 | size 13 | } 14 | 15 | #[inline] 16 | pub fn write_uint32(buf: &mut Vec, u: u32) -> usize { 17 | let mut size = 0; 18 | size += write_uint16(buf, (u & 0xffff) as u16); 19 | size += write_uint16(buf, ((u >> 16) & 0xffff) as u16); 20 | size 21 | } 22 | 23 | #[inline] 24 | pub fn write_uint64(buf: &mut Vec, u: u64) -> usize { 25 | let mut size = 0; 26 | size += write_uint32(buf, (u & 0xffffffff) as u32); 27 | size += write_uint32(buf, ((u >> 32) & 0xffffffff) as u32); 28 | size 29 | } 30 | 31 | #[inline] 32 | pub fn write_varuint1(buf: &mut Vec, u: u8) -> usize { 33 | write_uint8(buf, u) 34 | } 35 | 36 | #[allow(dead_code)] 37 | #[inline] 38 | pub fn write_varuint7(buf: &mut Vec, u: u8) -> usize { 39 | write_uint8(buf, u) 40 | } 41 | 42 | #[inline] 43 | pub fn write_varint7(buf: &mut Vec, i: i8) -> usize { 44 | write_uint8(buf, (i as u8) ^ 0x80) 45 | } 46 | 47 | macro_rules! gen_write_var { 48 | ($name: ident, $ty: ty) => { 49 | #[inline] 50 | #[allow(unused_comparisons)] 51 | #[allow(overflowing_literals)] 52 | pub fn $name(buf: &mut Vec, mut u: $ty) -> usize { 53 | let end: i8 = if u < 0 { 0xff } else { 0 }; 54 | 55 | let mut size = 0; 56 | let bit7 = 0b01111111; 57 | let mut cur: u8 = (u & bit7) as u8; 58 | // rust generates sar for i32 by >> 59 | u >>= 7; 60 | while u != (end as $ty) { 61 | size += write_uint8(buf, cur | 0x80); 62 | cur = (u & bit7) as u8; 63 | u >>= 7; 64 | } 65 | size += write_uint8(buf, cur); 66 | size 67 | } 68 | 69 | } 70 | } 71 | 72 | gen_write_var!(write_varuint32, u32); 73 | gen_write_var!(write_varint32, i32); 74 | gen_write_var!(write_varint64, i64); 75 | 76 | 77 | 78 | #[inline] 79 | pub fn write_slice(buf: &mut Vec, u: &[u8]) -> usize { 80 | buf.extend_from_slice(u); 81 | u.len() 82 | } 83 | --------------------------------------------------------------------------------