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