1 /// Represents the possible sizes in bytes of the discriminant of a variant type in the component model 2 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 3 pub enum DiscriminantSize { 4 /// 8-bit discriminant 5 Size1, 6 /// 16-bit discriminant 7 Size2, 8 /// 32-bit discriminant 9 Size4, 10 } 11 12 impl DiscriminantSize { 13 /// Calculate the size of discriminant needed to represent a variant with the specified number of cases. 14 pub const fn from_count(count: usize) -> Option<Self> { 15 if count <= 0xFF { 16 Some(Self::Size1) 17 } else if count <= 0xFFFF { 18 Some(Self::Size2) 19 } else if count <= 0xFFFF_FFFF { 20 Some(Self::Size4) 21 } else { 22 None 23 } 24 } 25 26 /// Returns the size, in bytes, of this discriminant 27 pub const fn byte_size(&self) -> u32 { 28 match self { 29 DiscriminantSize::Size1 => 1, 30 DiscriminantSize::Size2 => 2, 31 DiscriminantSize::Size4 => 4, 32 } 33 } 34 } 35 36 impl From<DiscriminantSize> for u32 { 37 /// Size of the discriminant as a `u32` 38 fn from(size: DiscriminantSize) -> u32 { 39 size.byte_size() 40 } 41 } 42 43 impl From<DiscriminantSize> for usize { 44 /// Size of the discriminant as a `usize` 45 fn from(size: DiscriminantSize) -> usize { 46 match size { 47 DiscriminantSize::Size1 => 1, 48 DiscriminantSize::Size2 => 2, 49 DiscriminantSize::Size4 => 4, 50 } 51 } 52 } 53 54 /// Represents the number of bytes required to store a flags value in the component model 55 pub enum FlagsSize { 56 /// There are no flags 57 Size0, 58 /// Flags can fit in a u8 59 Size1, 60 /// Flags can fit in a u16 61 Size2, 62 /// Flags can fit in a specified number of u32 fields 63 Size4Plus(u8), 64 } 65 66 impl FlagsSize { 67 /// Calculate the size needed to represent a value with the specified number of flags. 68 pub const fn from_count(count: usize) -> FlagsSize { 69 if count == 0 { 70 FlagsSize::Size0 71 } else if count <= 8 { 72 FlagsSize::Size1 73 } else if count <= 16 { 74 FlagsSize::Size2 75 } else { 76 let amt = ceiling_divide(count, 32); 77 if amt > (u8::MAX as usize) { 78 panic!("too many flags"); 79 } 80 FlagsSize::Size4Plus(amt as u8) 81 } 82 } 83 } 84 85 /// Divide `n` by `d`, rounding up in the case of a non-zero remainder. 86 const fn ceiling_divide(n: usize, d: usize) -> usize { 87 (n + d - 1) / d 88 } 89 90 /// A simple bump allocator which can be used with modules 91 pub const REALLOC_AND_FREE: &str = r#" 92 (global $last (mut i32) (i32.const 8)) 93 (func $realloc (export "realloc") 94 (param $old_ptr i32) 95 (param $old_size i32) 96 (param $align i32) 97 (param $new_size i32) 98 (result i32) 99 100 (local $ret i32) 101 102 ;; Test if the old pointer is non-null 103 local.get $old_ptr 104 if 105 ;; If the old size is bigger than the new size then 106 ;; this is a shrink and transparently allow it 107 local.get $old_size 108 local.get $new_size 109 i32.gt_u 110 if 111 local.get $old_ptr 112 return 113 end 114 115 ;; otherwise fall through to allocate a new chunk which will later 116 ;; copy data over 117 end 118 119 ;; align up `$last` 120 (global.set $last 121 (i32.and 122 (i32.add 123 (global.get $last) 124 (i32.add 125 (local.get $align) 126 (i32.const -1))) 127 (i32.xor 128 (i32.add 129 (local.get $align) 130 (i32.const -1)) 131 (i32.const -1)))) 132 133 ;; save the current value of `$last` as the return value 134 global.get $last 135 local.set $ret 136 137 ;; bump our pointer 138 (global.set $last 139 (i32.add 140 (global.get $last) 141 (local.get $new_size))) 142 143 ;; while `memory.size` is less than `$last`, grow memory 144 ;; by one page 145 (loop $loop 146 (if 147 (i32.lt_u 148 (i32.mul (memory.size) (i32.const 65536)) 149 (global.get $last)) 150 (then 151 i32.const 1 152 memory.grow 153 ;; test to make sure growth succeeded 154 i32.const -1 155 i32.eq 156 if unreachable end 157 158 br $loop))) 159 160 161 ;; ensure anything necessary is set to valid data by spraying a bit 162 ;; pattern that is invalid 163 local.get $ret 164 i32.const 0xde 165 local.get $new_size 166 memory.fill 167 168 ;; If the old pointer is present then that means this was a reallocation 169 ;; of an existing chunk which means the existing data must be copied. 170 local.get $old_ptr 171 if 172 local.get $ret ;; destination 173 local.get $old_ptr ;; source 174 local.get $old_size ;; size 175 memory.copy 176 end 177 178 local.get $ret 179 ) 180 "#; 181