1use alloc::vec::Vec;
16use core::ops::Deref;
17
18use num_enum::{TryFromPrimitive, UnsafeFromPrimitive};
19
20#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, UnsafeFromPrimitive)]
21#[repr(u8)]
22pub enum NumType {
23 I32 = 0x7f,
24 I64 = 0x7e,
25 F32 = 0x7d,
26 F64 = 0x7c,
27}
28
29#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, UnsafeFromPrimitive)]
30#[repr(u8)]
31pub enum VecType {
32 V128 = 0x7b,
33}
34
35#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, UnsafeFromPrimitive)]
36#[repr(u8)]
37pub enum RefType {
38 FuncRef = 0x70,
39 ExternRef = 0x6f,
40}
41
42#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, UnsafeFromPrimitive)]
43#[repr(u8)]
44pub enum ValType {
45 I32 = 0x7f,
46 I64 = 0x7e,
47 F32 = 0x7d,
48 F64 = 0x7c,
49 V128 = 0x7b,
50 FuncRef = 0x70,
51 ExternRef = 0x6f,
52}
53
54#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
55pub struct ResultType<'m>(&'m [ValType]);
56
57#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
58pub struct FuncType<'m> {
59 pub params: ResultType<'m>,
60 pub results: ResultType<'m>,
61}
62
63#[derive(Debug, Copy, Clone, PartialEq, Eq)]
64pub struct Limits {
65 pub min: u32,
66 pub max: u32,
67}
68
69pub const TABLE_MAX: u32 = u32::MAX;
70pub const MEM_MAX: u32 = 0x10000;
71
72impl Limits {
73 pub fn valid(&self, k: u32) -> bool {
74 self.min <= self.max && self.max <= k
75 }
76
77 pub fn matches(self, other: Limits) -> bool {
78 self.min >= other.min && self.max <= other.max
79 }
80}
81
82pub type MemType = Limits;
83
84#[derive(Debug, Copy, Clone, PartialEq, Eq)]
85pub struct TableType {
86 pub limits: Limits,
87 pub item: RefType,
88}
89
90#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, UnsafeFromPrimitive)]
91#[repr(u8)]
92pub enum Mut {
93 Const = 0,
94 Var = 1,
95}
96
97#[derive(Debug, Copy, Clone, PartialEq, Eq)]
98pub struct GlobalType {
99 pub mutable: Mut,
100 pub value: ValType,
101}
102
103#[derive(Debug, Copy, Clone, PartialEq, Eq)]
104pub enum Sx {
105 U,
106 S,
107}
108
109#[derive(Debug, Copy, Clone, PartialEq, Eq)]
110pub enum Nx {
111 N32,
112 N64,
113}
114
115#[derive(Debug, Copy, Clone, PartialEq, Eq)]
116pub enum Bx {
117 N32B8,
118 N32B16,
119 N64B8,
120 N64B16,
121 N64B32,
122}
123
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub enum ITestOp {
126 Eqz,
127}
128
129#[derive(Debug, Clone, PartialEq, Eq)]
130pub enum IRelOp {
131 Eq,
132 Ne,
133 Lt(Sx),
134 Gt(Sx),
135 Le(Sx),
136 Ge(Sx),
137}
138
139#[derive(Debug, Clone, PartialEq, Eq)]
140pub enum IUnOp {
141 Clz,
142 Ctz,
143 PopCnt,
144}
145
146#[derive(Debug, Clone, PartialEq, Eq)]
147pub enum IBinOp {
148 Add,
149 Sub,
150 Mul,
151 Div(Sx),
152 Rem(Sx),
153 And,
154 Or,
155 Xor,
156 Shl,
157 Shr(Sx),
158 Rotl,
159 Rotr,
160}
161
162#[cfg(feature = "float-types")]
163#[derive(Debug, Clone, PartialEq, Eq)]
164pub enum FRelOp {
165 Eq,
166 Ne,
167 Lt,
168 Gt,
169 Le,
170 Ge,
171}
172
173#[cfg(feature = "float-types")]
174#[derive(Debug, Clone, PartialEq, Eq)]
175pub enum FUnOp {
176 Abs,
177 Neg,
178 Ceil,
179 Floor,
180 Trunc,
181 Nearest,
182 Sqrt,
183}
184
185#[cfg(feature = "float-types")]
186#[derive(Debug, Clone, PartialEq, Eq)]
187pub enum FBinOp {
188 Add,
189 Sub,
190 Mul,
191 Div,
192 Min,
193 Max,
194 CopySign,
195}
196
197#[derive(Debug, Clone, PartialEq, Eq)]
198pub enum CvtOp {
199 Wrap,
200 Extend(Sx),
201 #[cfg(feature = "float-types")]
202 Trunc(Nx, Nx, Sx),
203 #[cfg(feature = "float-types")]
204 TruncSat(Nx, Nx, Sx),
205 #[cfg(feature = "float-types")]
206 Convert(Nx, Nx, Sx),
207 #[cfg(feature = "float-types")]
208 Demote,
209 #[cfg(feature = "float-types")]
210 Promote,
211 #[cfg(feature = "float-types")]
212 IReinterpret(Nx),
213 #[cfg(feature = "float-types")]
214 FReinterpret(Nx),
215}
216
217#[derive(Debug, Clone, PartialEq, Eq)]
218pub enum Instr<'m> {
219 Unreachable,
220 Nop,
221 Block(BlockType),
222 Loop(BlockType),
223 If(BlockType),
224 Else,
225 End,
226 Br(LabelIdx),
227 BrIf(LabelIdx),
228 BrTable(Vec<LabelIdx>, LabelIdx),
229 Return,
230 Call(FuncIdx),
231 CallIndirect(TableIdx, TypeIdx), Drop,
233 Select(Option<ResultType<'m>>),
234 LocalGet(LocalIdx),
235 LocalSet(LocalIdx),
236 LocalTee(LocalIdx),
237 GlobalGet(GlobalIdx),
238 GlobalSet(GlobalIdx),
239 TableGet(TableIdx),
240 TableSet(TableIdx),
241 ILoad(Nx, MemArg),
242 #[cfg(feature = "float-types")]
243 FLoad(Nx, MemArg),
244 ILoad_(Bx, Sx, MemArg),
245 IStore(Nx, MemArg),
246 #[cfg(feature = "float-types")]
247 FStore(Nx, MemArg),
248 IStore_(Bx, MemArg),
249 MemorySize,
250 MemoryGrow,
251 I32Const(u32),
252 I64Const(u64),
253 #[cfg(feature = "float-types")]
254 F32Const(u32),
255 #[cfg(feature = "float-types")]
256 F64Const(u64),
257 ITestOp(Nx, ITestOp),
258 IRelOp(Nx, IRelOp),
259 #[cfg(feature = "float-types")]
260 FRelOp(Nx, FRelOp),
261 IUnOp(Nx, IUnOp),
262 #[cfg(feature = "float-types")]
263 FUnOp(Nx, FUnOp),
264 IBinOp(Nx, IBinOp),
265 #[cfg(feature = "float-types")]
266 FBinOp(Nx, FBinOp),
267 CvtOp(CvtOp),
268 IExtend(Bx),
269 RefNull(RefType),
270 RefIsNull,
271 RefFunc(FuncIdx),
272 MemoryInit(DataIdx),
273 DataDrop(DataIdx),
274 MemoryCopy,
275 MemoryFill,
276 TableInit(TableIdx, ElemIdx), ElemDrop(ElemIdx),
278 TableCopy(TableIdx, TableIdx),
279 TableGrow(TableIdx),
280 TableSize(TableIdx),
281 TableFill(TableIdx),
282}
283
284pub type TypeIdx = u32;
285pub type FuncIdx = u32;
286pub type TableIdx = u32;
287pub type MemIdx = u32;
288pub type GlobalIdx = u32;
289pub type ElemIdx = u32;
290pub type DataIdx = u32;
291pub type LocalIdx = u32;
292pub type LabelIdx = u32;
293
294#[derive(Debug, Clone, PartialEq, Eq)]
295pub enum ExportDesc {
296 Func(FuncIdx),
297 Table(TableIdx),
298 Mem(MemIdx),
299 Global(GlobalIdx),
300}
301
302#[derive(Debug, Clone, PartialEq, Eq)]
303pub enum ImportDesc {
304 Func(TypeIdx),
305 Table(TableType),
306 Mem(MemType),
307 Global(GlobalType),
308}
309
310#[derive(Debug, Clone)]
311pub struct Import<'m> {
312 pub module: &'m str,
313 pub name: &'m str,
314 pub desc: ImportDesc,
315}
316
317#[derive(Debug, Clone, PartialEq, Eq)]
318pub enum ExternType<'m> {
319 Func(FuncType<'m>),
320 Table(TableType),
321 Mem(MemType),
322 Global(GlobalType),
323}
324
325impl<'m> ExternType<'m> {
326 pub fn matches(&self, other: &ExternType<'m>) -> bool {
327 match (self, other) {
328 (ExternType::Func(x), ExternType::Func(y)) => x == y,
329 (
330 ExternType::Table(TableType { limits: t, item: x }),
331 ExternType::Table(TableType { limits: s, item: y }),
332 ) => t.matches(*s) && x == y,
333 (ExternType::Mem(t), ExternType::Mem(s)) => t.matches(*s),
334 (ExternType::Global(x), ExternType::Global(y)) => x == y,
335 _ => false,
336 }
337 }
338}
339
340#[derive(Debug, Clone, PartialEq, Eq)]
341pub enum BlockType {
342 None,
343 Type(ValType),
344 Index(TypeIdx),
345}
346
347#[derive(Debug, Copy, Clone, PartialEq, Eq)]
348pub struct MemArg {
349 pub align: u32,
350 pub offset: u32,
351}
352
353#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, UnsafeFromPrimitive)]
354#[repr(u8)]
355pub enum SectionId {
356 Custom = 0,
357 Type = 1,
358 Import = 2,
359 Function = 3,
360 Table = 4,
361 Memory = 5,
362 Global = 6,
363 Export = 7,
364 Start = 8,
365 Element = 9,
366 Code = 10,
367 Data = 11,
368 DataCount = 12,
369}
370
371impl Deref for ResultType<'_> {
372 type Target = [ValType];
373
374 fn deref(&self) -> &Self::Target {
375 self.0
376 }
377}
378
379impl<'m> From<&'m [ValType]> for ResultType<'m> {
380 fn from(xs: &'m [ValType]) -> Self {
381 Self(xs)
382 }
383}
384
385impl From<ValType> for ResultType<'_> {
386 fn from(x: ValType) -> Self {
387 macro_rules! make {
388 ($($x:ident),*) => {{
389 static VAL_TYPES: &[ValType] = &[$(ValType::$x),*];
390 make!([][0][$($x)*])
391 }};
392 ([$($output:tt)*][$i:expr][]) => {
393 Self(match x { $($output)* })
394 };
395 ([$($output:tt)*][$i:expr][$x:ident $($input:ident)*]) => {
396 make!([$($output)* ValType::$x => core::slice::from_ref(&VAL_TYPES[$i]),]
397 [$i + 1][$($input)*])
398 };
399 }
400 make!(I32, I64, F32, F64, V128, FuncRef, ExternRef)
401 }
402}
403
404impl From<()> for ResultType<'_> {
405 fn from(_: ()) -> Self {
406 Self(&[])
407 }
408}
409
410impl NumType {
411 pub fn i(n: Nx) -> Self {
412 match n {
413 Nx::N32 => NumType::I32,
414 Nx::N64 => NumType::I64,
415 }
416 }
417
418 #[cfg(feature = "float-types")]
419 pub fn f(n: Nx) -> Self {
420 match n {
421 Nx::N32 => NumType::F32,
422 Nx::N64 => NumType::F64,
423 }
424 }
425}
426
427impl From<Nx> for usize {
428 fn from(x: Nx) -> Self {
429 match x {
430 Nx::N32 => 32,
431 Nx::N64 => 64,
432 }
433 }
434}
435
436impl From<Bx> for Nx {
437 fn from(x: Bx) -> Self {
438 match x {
439 Bx::N32B8 | Bx::N32B16 => Nx::N32,
440 Bx::N64B8 | Bx::N64B16 | Bx::N64B32 => Nx::N64,
441 }
442 }
443}
444
445impl From<Bx> for usize {
446 fn from(x: Bx) -> Self {
447 match x {
448 Bx::N32B8 | Bx::N64B8 => 8,
449 Bx::N32B16 | Bx::N64B16 => 16,
450 Bx::N64B32 => 32,
451 }
452 }
453}
454
455impl CvtOp {
456 pub fn dst(&self) -> NumType {
457 match *self {
458 CvtOp::Wrap => NumType::I32,
459 CvtOp::Extend(_) => NumType::I64,
460 #[cfg(feature = "float-types")]
461 CvtOp::Trunc(n, _, _) => NumType::i(n),
462 #[cfg(feature = "float-types")]
463 CvtOp::TruncSat(n, _, _) => NumType::i(n),
464 #[cfg(feature = "float-types")]
465 CvtOp::Convert(n, _, _) => NumType::f(n),
466 #[cfg(feature = "float-types")]
467 CvtOp::Demote => NumType::F32,
468 #[cfg(feature = "float-types")]
469 CvtOp::Promote => NumType::F64,
470 #[cfg(feature = "float-types")]
471 CvtOp::IReinterpret(n) => NumType::i(n),
472 #[cfg(feature = "float-types")]
473 CvtOp::FReinterpret(n) => NumType::f(n),
474 }
475 }
476
477 pub fn src(&self) -> NumType {
478 match *self {
479 CvtOp::Wrap => NumType::I64,
480 CvtOp::Extend(_) => NumType::I32,
481 #[cfg(feature = "float-types")]
482 CvtOp::Trunc(_, m, _) => NumType::f(m),
483 #[cfg(feature = "float-types")]
484 CvtOp::TruncSat(_, m, _) => NumType::f(m),
485 #[cfg(feature = "float-types")]
486 CvtOp::Convert(_, m, _) => NumType::i(m),
487 #[cfg(feature = "float-types")]
488 CvtOp::Demote => NumType::F64,
489 #[cfg(feature = "float-types")]
490 CvtOp::Promote => NumType::F32,
491 #[cfg(feature = "float-types")]
492 CvtOp::IReinterpret(n) => NumType::f(n),
493 #[cfg(feature = "float-types")]
494 CvtOp::FReinterpret(n) => NumType::i(n),
495 }
496 }
497}
498
499macro_rules! impl_op {
500 ($n:ident, $u:ident, $i:ident, $f:ident) => {
501 impl ITestOp {
502 pub fn $n(&self, x: $u) -> bool {
503 match self {
504 ITestOp::Eqz => x == 0,
505 }
506 }
507 }
508
509 impl IRelOp {
510 pub fn $n(&self, x: $u, y: $u) -> bool {
511 match self {
512 IRelOp::Eq => x == y,
513 IRelOp::Ne => x != y,
514 IRelOp::Lt(Sx::U) => x < y,
515 IRelOp::Lt(Sx::S) => (x as $i) < (y as $i),
516 IRelOp::Gt(Sx::U) => x > y,
517 IRelOp::Gt(Sx::S) => (x as $i) > (y as $i),
518 IRelOp::Le(Sx::U) => x <= y,
519 IRelOp::Le(Sx::S) => (x as $i) <= (y as $i),
520 IRelOp::Ge(Sx::U) => x >= y,
521 IRelOp::Ge(Sx::S) => (x as $i) >= (y as $i),
522 }
523 }
524 }
525
526 impl IUnOp {
527 pub fn $n(&self, x: $u) -> Option<$u> {
528 Some(match self {
529 IUnOp::Clz => x.leading_zeros(),
530 IUnOp::Ctz => x.trailing_zeros(),
531 IUnOp::PopCnt => x.count_ones(),
532 } as $u)
533 }
534 }
535
536 impl IBinOp {
537 pub fn $n(&self, x: $u, y: $u) -> Option<$u> {
538 match self {
539 IBinOp::Add => Some(x.wrapping_add(y)),
540 IBinOp::Sub => Some(x.wrapping_sub(y)),
541 IBinOp::Mul => Some(x.wrapping_mul(y)),
542 IBinOp::Div(Sx::U) => x.checked_div(y),
543 IBinOp::Div(Sx::S) => (x as $i).checked_div(y as $i).map(|z| z as $u),
544 IBinOp::Rem(Sx::U) => x.checked_rem(y),
545 IBinOp::Rem(Sx::S) if y == 0 => None,
546 IBinOp::Rem(Sx::S) => Some((x as $i).wrapping_rem(y as $i) as $u),
547 IBinOp::And => Some(x & y),
548 IBinOp::Or => Some(x | y),
549 IBinOp::Xor => Some(x ^ y),
550 IBinOp::Shl => Some(x.wrapping_shl(y as u32)),
551 IBinOp::Shr(Sx::U) => Some(x.wrapping_shr(y as u32)),
552 IBinOp::Shr(Sx::S) => Some((x as $i).wrapping_shr(y as u32) as $u),
553 IBinOp::Rotl => Some(x.rotate_left(y as u32)),
554 IBinOp::Rotr => Some(x.rotate_right(y as u32)),
555 }
556 }
557 }
558
559 #[cfg(feature = "float-types")]
560 impl FRelOp {
561 pub fn $n(&self, x: $u, y: $u) -> bool {
562 let x = $f::from_bits(x);
563 let y = $f::from_bits(y);
564 match self {
565 FRelOp::Eq => x == y,
566 FRelOp::Ne => x != y,
567 FRelOp::Lt => x < y,
568 FRelOp::Gt => x > y,
569 FRelOp::Le => x <= y,
570 FRelOp::Ge => x >= y,
571 }
572 }
573 }
574
575 #[cfg(feature = "float-types")]
576 impl FUnOp {
577 pub fn $n(&self, x: $u) -> $u {
578 let x = $f::from_bits(x);
579 let z = match self {
580 FUnOp::Abs => float::$f::abs(x),
581 FUnOp::Neg => -x,
582 FUnOp::Ceil => float::$f::ceil(x),
583 FUnOp::Floor => float::$f::floor(x),
584 FUnOp::Trunc => float::$f::trunc(x),
585 FUnOp::Nearest => {
586 let round = float::$f::round(x);
587 if float::$f::abs(x - round) == 0.5 {
588 match round % 2. {
589 r if r == 1. => float::$f::floor(x),
590 r if r == -1. => float::$f::ceil(x),
591 r if r == 0. => round,
592 _ => unreachable!(),
593 }
594 } else {
595 round
596 }
597 }
598 FUnOp::Sqrt => float::$f::sqrt(x),
599 };
600 z.to_bits()
601 }
602 }
603
604 #[cfg(feature = "float-types")]
605 impl FBinOp {
606 pub fn $n(&self, x_: $u, y_: $u) -> $u {
607 let x = $f::from_bits(x_);
608 let y = $f::from_bits(y_);
609 let z = match self {
610 FBinOp::Add => x + y,
611 FBinOp::Sub => x - y,
612 FBinOp::Mul => x * y,
613 FBinOp::Div => x / y,
614 FBinOp::Min => x.minimum(y),
615 FBinOp::Max => x.maximum(y),
616 FBinOp::CopySign => {
617 const M: $u = 1 << ($u::BITS - 1);
618 return (x_ & !M) | (y_ & M);
619 }
620 };
621 z.to_bits()
622 }
623 }
624 };
625}
626impl_op!(n32, u32, i32, f32);
627impl_op!(n64, u64, i64, f64);
628
629#[cfg(feature = "float-types")]
630#[allow(non_upper_case_globals)]
631mod float {
632 pub mod f32 {
633 pub const abs: fn(f32) -> f32 = libm::fabsf;
634 pub const ceil: fn(f32) -> f32 = libm::ceilf;
635 pub const floor: fn(f32) -> f32 = libm::floorf;
636 pub const round: fn(f32) -> f32 = libm::roundf;
637 pub const sqrt: fn(f32) -> f32 = libm::sqrtf;
638 pub const trunc: fn(f32) -> f32 = libm::truncf;
639 }
640
641 pub mod f64 {
642 pub const abs: fn(f64) -> f64 = libm::fabs;
643 pub const ceil: fn(f64) -> f64 = libm::ceil;
644 pub const floor: fn(f64) -> f64 = libm::floor;
645 pub const round: fn(f64) -> f64 = libm::round;
646 pub const sqrt: fn(f64) -> f64 = libm::sqrt;
647 pub const trunc: fn(f64) -> f64 = libm::trunc;
648 }
649}
650
651impl From<u8> for Sx {
652 fn from(x: u8) -> Self {
653 match x {
654 0 => Sx::S,
655 1 => Sx::U,
656 _ => unreachable!(),
657 }
658 }
659}
660
661impl From<u8> for Nx {
662 fn from(x: u8) -> Self {
663 match x {
664 0 => Nx::N32,
665 1 => Nx::N64,
666 _ => unreachable!(),
667 }
668 }
669}
670
671impl From<u8> for Bx {
672 fn from(x: u8) -> Self {
673 match x {
674 0 => Bx::N32B8,
675 1 => Bx::N32B16,
676 2 => Bx::N64B8,
677 3 => Bx::N64B16,
678 4 => Bx::N64B32,
679 _ => unreachable!(),
680 }
681 }
682}
683
684impl From<u8> for IRelOp {
685 fn from(x: u8) -> Self {
686 match x {
687 0 => IRelOp::Eq,
688 1 => IRelOp::Ne,
689 x @ 2 ..= 3 => IRelOp::Lt((x - 2).into()),
690 x @ 4 ..= 5 => IRelOp::Gt((x - 4).into()),
691 x @ 6 ..= 7 => IRelOp::Le((x - 6).into()),
692 x @ 8 ..= 9 => IRelOp::Ge((x - 8).into()),
693 _ => unreachable!(),
694 }
695 }
696}
697
698impl From<u8> for IUnOp {
699 fn from(x: u8) -> Self {
700 match x {
701 0 => IUnOp::Clz,
702 1 => IUnOp::Ctz,
703 2 => IUnOp::PopCnt,
704 _ => unreachable!(),
705 }
706 }
707}
708
709impl From<u8> for IBinOp {
710 fn from(x: u8) -> Self {
711 match x {
712 0 => IBinOp::Add,
713 1 => IBinOp::Sub,
714 2 => IBinOp::Mul,
715 x @ 3 ..= 4 => IBinOp::Div((x - 3).into()),
716 x @ 5 ..= 6 => IBinOp::Rem((x - 5).into()),
717 7 => IBinOp::And,
718 8 => IBinOp::Or,
719 9 => IBinOp::Xor,
720 10 => IBinOp::Shl,
721 x @ 11 ..= 12 => IBinOp::Shr((x - 11).into()),
722 13 => IBinOp::Rotl,
723 14 => IBinOp::Rotr,
724 _ => unreachable!(),
725 }
726 }
727}
728
729#[cfg(feature = "float-types")]
730impl From<u8> for FRelOp {
731 fn from(x: u8) -> Self {
732 match x {
733 0 => FRelOp::Eq,
734 1 => FRelOp::Ne,
735 2 => FRelOp::Lt,
736 3 => FRelOp::Gt,
737 4 => FRelOp::Le,
738 5 => FRelOp::Ge,
739 _ => unreachable!(),
740 }
741 }
742}
743
744#[cfg(feature = "float-types")]
745impl From<u8> for FUnOp {
746 fn from(x: u8) -> Self {
747 match x {
748 0 => FUnOp::Abs,
749 1 => FUnOp::Neg,
750 2 => FUnOp::Ceil,
751 3 => FUnOp::Floor,
752 4 => FUnOp::Trunc,
753 5 => FUnOp::Nearest,
754 6 => FUnOp::Sqrt,
755 _ => unreachable!(),
756 }
757 }
758}
759
760#[cfg(feature = "float-types")]
761impl From<u8> for FBinOp {
762 fn from(x: u8) -> Self {
763 match x {
764 0 => FBinOp::Add,
765 1 => FBinOp::Sub,
766 2 => FBinOp::Mul,
767 3 => FBinOp::Div,
768 4 => FBinOp::Min,
769 5 => FBinOp::Max,
770 6 => FBinOp::CopySign,
771 _ => unreachable!(),
772 }
773 }
774}
775
776impl SectionId {
777 pub fn order(self) -> u8 {
778 match self as u8 {
780 x @ 0 ..= 9 => x,
781 12 => 10,
782 x @ 10 ..= 11 => x + 1,
783 _ => unreachable!(),
784 }
785 }
786}
787
788pub trait TryFromByte: Sized {
789 fn try_from_byte(byte: u8) -> Option<Self>;
790}
791
792pub trait UnsafeFromByte {
793 unsafe fn from_byte_unchecked(byte: u8) -> Self;
795}
796
797impl TryFromByte for bool {
798 fn try_from_byte(byte: u8) -> Option<Self> {
799 Some(match byte {
800 0 => false,
801 1 => true,
802 _ => return None,
803 })
804 }
805}
806
807impl UnsafeFromByte for bool {
808 unsafe fn from_byte_unchecked(byte: u8) -> Self {
809 unsafe { Self::try_from_byte(byte).unwrap_unchecked() }
810 }
811}
812
813macro_rules! impl_from_byte {
814 ($name:ident) => {
815 impl UnsafeFromByte for $name {
816 unsafe fn from_byte_unchecked(byte: u8) -> Self {
817 unsafe { Self::unchecked_transmute_from(byte) }
818 }
819 }
820 impl TryFromByte for $name {
821 fn try_from_byte(byte: u8) -> Option<Self> {
822 Self::try_from_primitive(byte).ok()
823 }
824 }
825 };
826}
827impl_from_byte!(RefType);
828impl_from_byte!(ValType);
829impl_from_byte!(Mut);
830impl_from_byte!(SectionId);