swamp_abi_memtypes/
lib.rs1use std::fmt::{Display, Formatter};
2use std::ops::{Add, Div, Sub};
3
4#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5pub enum MemoryAlignment {
6 U8,
8 U16,
9 U32,
10 U64,
11}
12
13impl MemoryAlignment {
14 #[must_use]
15 const fn rank(&self) -> usize {
16 match self {
17 Self::U8 => 1,
18 Self::U16 => 2,
19 Self::U32 => 3,
20 Self::U64 => 4,
21 }
22 }
23 #[must_use]
24 pub const fn greater_than(&self, other: Self) -> bool {
25 self.rank() > other.rank()
26 }
27}
28
29impl From<MemoryAlignment> for usize {
30 fn from(val: MemoryAlignment) -> Self {
31 match val {
32 MemoryAlignment::U8 => 1,
33 MemoryAlignment::U16 => 2,
34 MemoryAlignment::U32 => 4,
35 MemoryAlignment::U64 => 8,
36 }
37 }
38}
39
40impl From<MemoryAlignment> for u8 {
41 fn from(val: MemoryAlignment) -> Self {
42 match val {
43 MemoryAlignment::U8 => 1,
44 MemoryAlignment::U16 => 2,
45 MemoryAlignment::U32 => 4,
46 MemoryAlignment::U64 => 8,
47 }
48 }
49}
50
51impl TryInto<MemoryAlignment> for usize {
52 type Error = ();
53
54 fn try_into(self) -> Result<MemoryAlignment, Self::Error> {
55 let converted = match self {
56 1 => MemoryAlignment::U8,
57 2 => MemoryAlignment::U16,
58 4 => MemoryAlignment::U32,
59 8 => MemoryAlignment::U64,
60
61 _ => return Err(()),
62 };
63 Ok(converted)
64 }
65}
66
67
68#[derive(Debug, Copy, Clone, PartialOrd, Ord, Eq, PartialEq)]
69pub struct MemorySize(pub u32);
70
71impl Display for MemorySize {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 let description = human_memsize::human_size(self.0.into());
74 write!(f, "{description}")
75 }
76}
77
78
79
80#[derive(Debug, Copy, Eq, PartialEq, Hash, Clone, Ord, PartialOrd)]
81pub struct MemoryOffset(pub u32);
82
83impl MemoryOffset {
84 #[must_use]
85 pub const fn to_size(&self) -> MemorySize {
86 MemorySize(self.0)
87 }
88}
89
90impl Display for MemoryOffset {
91 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
92 write!(f, "+{:X}", self.0)
93 }
94}
95
96impl MemoryOffset {
97 pub fn space(&mut self, memory_size: MemorySize, alignment: MemoryAlignment) -> Self {
98 let start = align(self.0 as usize, alignment.into()) as u32;
99 self.0 = start + memory_size.0;
100 Self(start)
101 }
102}
103
104impl Add<MemorySize> for MemoryOffset {
105 type Output = Self;
106
107 fn add(self, rhs: MemorySize) -> Self {
108 Self(self.0 + rhs.0)
109 }
110}
111
112impl From<MemoryAlignment> for MemoryOffset {
113 fn from(val: MemoryAlignment) -> Self {
114 let octets: usize = val.into();
115 Self(octets as u32)
116 }
117}
118
119impl From<MemorySize> for usize {
120 fn from(val: MemorySize) -> Self {
121 val.0 as Self
122 }
123}
124
125
126#[must_use]
127pub fn align_to(addr: MemoryOffset, alignment: MemoryAlignment) -> MemoryOffset {
128 MemoryOffset(align(addr.0 as usize, alignment.into()) as u32)
129}
130
131#[must_use]
149pub fn adjust_size_to_alignment(
150 unaligned_size: MemorySize,
151 max_alignment: MemoryAlignment,
152) -> MemorySize {
153 align_to(MemoryOffset(unaligned_size.0), max_alignment).to_size()
154}
155
156
157#[derive(Copy, Clone)]
158pub struct CountU32(pub u32);
159
160
161
162impl Div<Self> for MemorySize {
163 type Output = CountU32;
164
165 fn div(self, rhs: Self) -> Self::Output {
166 assert!(rhs.0 > 0, "Division by zero in MemorySize");
167 assert!(
168 self.0 > 0,
169 "Numerator must be positive in MemorySize division"
170 );
171 assert_eq!(
172 self.0 % rhs.0,
173 0,
174 "MemorySize division must be exact and positive"
175 );
176
177 CountU32(self.0 / rhs.0)
178 }
179}
180
181impl Add<Self> for MemoryOffset {
182 type Output = Self;
183
184 fn add(self, rhs: Self) -> Self {
185 Self(self.0 + rhs.0)
186 }
187}
188
189impl Sub<Self> for MemoryOffset {
190 type Output = Self;
191
192 fn sub(self, rhs: Self) -> Self {
193 assert!(rhs.0 <= self.0);
194 Self(self.0 - rhs.0)
195 }
196}
197
198impl MemoryOffset {
199 #[must_use]
200 pub const fn as_size(&self) -> MemorySize {
201 MemorySize(self.0)
202 }
203}
204
205pub const SAFE_ALIGNMENT: usize = 8;
206
207#[must_use]
208pub fn align(addr: usize, alignment: usize) -> usize {
209 debug_assert!(
210 alignment.is_power_of_two(),
211 "alignment must be a power of two"
212 );
213 (addr + alignment - 1) & !(alignment - 1)
214}
215
216
217impl MemoryOffset {
218 #[must_use]
219 pub fn add(&self, size: MemorySize, alignment: MemoryAlignment) -> Self {
220 let new_start = align(self.0 as usize, alignment.into()) as u32;
221 Self(new_start + size.0)
222 }
223}