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(usize), 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 FlagsSize::Size4Plus(ceiling_divide(count, 32)) 77 } 78 } 79 } 80 81 /// Divide `n` by `d`, rounding up in the case of a non-zero remainder. 82 const fn ceiling_divide(n: usize, d: usize) -> usize { 83 (n + d - 1) / d 84 } 85 86 /// A simple bump allocator which can be used with modules 87 pub const REALLOC_AND_FREE: &str = r#" 88 (global $last (mut i32) (i32.const 8)) 89 (func $realloc (export "realloc") 90 (param $old_ptr i32) 91 (param $old_size i32) 92 (param $align i32) 93 (param $new_size i32) 94 (result i32) 95 96 (local $ret i32) 97 98 ;; Test if the old pointer is non-null 99 local.get $old_ptr 100 if 101 ;; If the old size is bigger than the new size then 102 ;; this is a shrink and transparently allow it 103 local.get $old_size 104 local.get $new_size 105 i32.gt_u 106 if 107 local.get $old_ptr 108 return 109 end 110 111 ;; otherwise fall through to allocate a new chunk which will later 112 ;; copy data over 113 end 114 115 ;; align up `$last` 116 (global.set $last 117 (i32.and 118 (i32.add 119 (global.get $last) 120 (i32.add 121 (local.get $align) 122 (i32.const -1))) 123 (i32.xor 124 (i32.add 125 (local.get $align) 126 (i32.const -1)) 127 (i32.const -1)))) 128 129 ;; save the current value of `$last` as the return value 130 global.get $last 131 local.set $ret 132 133 ;; bump our pointer 134 (global.set $last 135 (i32.add 136 (global.get $last) 137 (local.get $new_size))) 138 139 ;; while `memory.size` is less than `$last`, grow memory 140 ;; by one page 141 (loop $loop 142 (if 143 (i32.lt_u 144 (i32.mul (memory.size) (i32.const 65536)) 145 (global.get $last)) 146 (then 147 i32.const 1 148 memory.grow 149 ;; test to make sure growth succeeded 150 i32.const -1 151 i32.eq 152 if unreachable end 153 154 br $loop))) 155 156 157 ;; ensure anything necessary is set to valid data by spraying a bit 158 ;; pattern that is invalid 159 local.get $ret 160 i32.const 0xde 161 local.get $new_size 162 memory.fill 163 164 ;; If the old pointer is present then that means this was a reallocation 165 ;; of an existing chunk which means the existing data must be copied. 166 local.get $old_ptr 167 if 168 local.get $ret ;; destination 169 local.get $old_ptr ;; source 170 local.get $old_size ;; size 171 memory.copy 172 end 173 174 local.get $ret 175 ) 176 "#; 177