1use std::{
2 iter::Sum,
3 ops::{Add, AddAssign, Div, Mul},
4};
5
6use msgpack_tagged::MsgpackTagged;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
12#[derive(Serialize, Deserialize, MsgpackTagged)]
13pub struct SemanticLength(pub u32);
14
15impl SemanticLength {
16 pub fn to_usize(self) -> usize {
17 assert_usize(self.0)
18 }
19}
20
21impl Add<SemanticLength> for SemanticLength {
22 type Output = SemanticLength;
23
24 fn add(self, rhs: SemanticLength) -> Self::Output {
26 SemanticLength(checked_add(self.0, rhs.0))
27 }
28}
29
30impl AddAssign for SemanticLength {
31 fn add_assign(&mut self, rhs: Self) {
33 self.0 = checked_add(self.0, rhs.0);
34 }
35}
36
37impl Mul<ElementTypesLength> for SemanticLength {
38 type Output = SemiFlattenedLength;
39
40 fn mul(self, rhs: ElementTypesLength) -> Self::Output {
43 SemiFlattenedLength(checked_mul(self.0, rhs.0))
44 }
45}
46
47impl std::fmt::Display for SemanticLength {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 write!(f, "{}", self.0)
50 }
51}
52
53#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Hash)]
60pub struct ElementTypesLength(pub u32);
61
62impl ElementTypesLength {
63 pub fn to_usize(self) -> usize {
64 assert_usize(self.0)
65 }
66}
67
68impl Mul<SemanticLength> for ElementTypesLength {
69 type Output = SemiFlattenedLength;
70
71 fn mul(self, rhs: SemanticLength) -> Self::Output {
74 SemiFlattenedLength(checked_mul(self.0, rhs.0))
75 }
76}
77
78impl Mul<ElementsFlattenedLength> for SemanticLength {
79 type Output = FlattenedLength;
80
81 fn mul(self, rhs: ElementsFlattenedLength) -> Self::Output {
84 FlattenedLength(checked_mul(self.0, rhs.0))
85 }
86}
87
88impl std::fmt::Display for ElementTypesLength {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 write!(f, "{}", self.0)
91 }
92}
93
94#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
109#[derive(Serialize, Deserialize, MsgpackTagged)]
110#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
111pub struct SemiFlattenedLength(pub u32);
112
113impl SemiFlattenedLength {
114 pub fn to_usize(self) -> usize {
115 assert_usize(self.0)
116 }
117}
118
119impl std::fmt::Display for SemiFlattenedLength {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 write!(f, "{}", self.0)
122 }
123}
124
125impl Div<ElementTypesLength> for SemiFlattenedLength {
126 type Output = SemanticLength;
127
128 fn div(self, rhs: ElementTypesLength) -> Self::Output {
129 if !self.0.is_multiple_of(rhs.0) {
130 panic!(
131 "Division of SemiFlattenedLength {} by ElementTypesLength {} has remainder",
132 self.0, rhs.0
133 );
134 }
135 SemanticLength(self.0 / rhs.0)
136 }
137}
138
139#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Hash)]
145pub struct ElementsFlattenedLength(pub u32);
146
147impl ElementsFlattenedLength {
148 pub fn to_usize(self) -> usize {
149 assert_usize(self.0)
150 }
151}
152
153impl std::fmt::Display for ElementsFlattenedLength {
154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155 write!(f, "{}", self.0)
156 }
157}
158
159impl Mul<SemanticLength> for ElementsFlattenedLength {
160 type Output = FlattenedLength;
161
162 fn mul(self, rhs: SemanticLength) -> Self::Output {
165 FlattenedLength(checked_mul(self.0, rhs.0))
166 }
167}
168
169impl From<FlattenedLength> for ElementsFlattenedLength {
170 fn from(flattened_length: FlattenedLength) -> Self {
172 Self(flattened_length.0)
173 }
174}
175
176#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Hash)]
179pub struct FlattenedLength(pub u32);
180
181impl FlattenedLength {
182 pub fn to_usize(self) -> usize {
183 assert_usize(self.0)
184 }
185}
186
187impl std::fmt::Display for FlattenedLength {
188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189 write!(f, "{}", self.0)
190 }
191}
192
193impl Add for FlattenedLength {
194 type Output = FlattenedLength;
195
196 fn add(self, rhs: Self) -> Self::Output {
197 FlattenedLength(checked_add(self.0, rhs.0))
198 }
199}
200
201impl AddAssign for FlattenedLength {
202 fn add_assign(&mut self, rhs: Self) {
203 self.0 = checked_add(self.0, rhs.0);
204 }
205}
206
207impl Sum for FlattenedLength {
208 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
209 iter.fold(FlattenedLength(0), |acc, x| acc + x)
210 }
211}
212
213impl Div<ElementsFlattenedLength> for FlattenedLength {
214 type Output = SemanticLength;
215
216 fn div(self, rhs: ElementsFlattenedLength) -> Self::Output {
217 if !self.0.is_multiple_of(rhs.0) {
218 panic!(
219 "Division of FlattenedLength {} by ElementsFlattenedLength {} has remainder",
220 self.0, rhs.0
221 );
222 }
223
224 SemanticLength(self.0 / rhs.0)
225 }
226}
227
228fn checked_mul(lhs: u32, rhs: u32) -> u32 {
234 lhs.checked_mul(rhs).unwrap_or_else(|| panic!("Length overflow multiplying {lhs} by {rhs}"))
235}
236
237fn checked_add(lhs: u32, rhs: u32) -> u32 {
239 lhs.checked_add(rhs).unwrap_or_else(|| panic!("Length overflow adding {rhs} to {lhs}"))
240}
241
242fn assert_usize(value: u32) -> usize {
244 value.try_into().expect("Failed conversion from u32 to usize")
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
254 #[should_panic(expected = "Length overflow multiplying 65536 by 65536")]
255 fn multiplying_lengths_does_not_wrap() {
256 let _ = ElementsFlattenedLength(1 << 16) * SemanticLength(1 << 16);
257 }
258
259 #[test]
260 #[should_panic(expected = "Length overflow adding")]
261 fn adding_lengths_does_not_wrap() {
262 let _ = FlattenedLength(u32::MAX) + FlattenedLength(1);
263 }
264
265 #[test]
266 fn multiplying_lengths_in_range_is_unchanged() {
267 assert_eq!(
268 ElementsFlattenedLength(6) * SemanticLength(8),
269 FlattenedLength(48),
270 "[(u8, u16, [u32; 4]); 8] occupies 48 slots"
271 );
272 }
273
274 #[test]
275 fn flattened_length_divides_evenly_by_elements_flattened_length() {
276 assert_eq!(FlattenedLength(6) / ElementsFlattenedLength(2), SemanticLength(3));
277 }
278
279 #[test]
280 #[should_panic(
281 expected = "Division of FlattenedLength 5 by ElementsFlattenedLength 2 has remainder"
282 )]
283 fn flattened_length_division_with_remainder_panics() {
284 let _ = FlattenedLength(5) / ElementsFlattenedLength(2);
285 }
286
287 #[test]
288 fn semi_flattened_length_divides_evenly_by_element_types_length() {
289 assert_eq!(SemiFlattenedLength(6) / ElementTypesLength(3), SemanticLength(2));
290 }
291
292 #[test]
293 #[should_panic(
294 expected = "Division of SemiFlattenedLength 7 by ElementTypesLength 3 has remainder"
295 )]
296 fn semi_flattened_length_division_with_remainder_panics() {
297 let _ = SemiFlattenedLength(7) / ElementTypesLength(3);
298 }
299}