1use alloc::{boxed::Box, vec::Vec};
2use core::{
3 fmt::{Display, Formatter},
4 ops::{Add, AddAssign, Bound, Index, IndexMut, Mul, RangeBounds, Sub, SubAssign},
5};
6
7use miden_core::{
8 Felt,
9 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
10};
11
12#[derive(Debug, thiserror::Error)]
18pub enum RowIndexError {
19 #[error("value {0} is larger than u32::MAX so it cannot be converted into a RowIndex")]
21 InvalidSize(Box<str>),
22}
23
24#[derive(Debug, Default, Copy, Clone, Eq, Ord, PartialOrd)]
26#[cfg_attr(
27 all(feature = "arbitrary", test),
28 miden_test_serialization_macros::serialization_test
29)]
30pub struct RowIndex(u32);
31
32impl RowIndex {
33 pub fn as_usize(&self) -> usize {
34 self.0 as usize
35 }
36
37 pub fn as_u32(&self) -> u32 {
38 self.0
39 }
40}
41
42impl Display for RowIndex {
43 fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
44 write!(f, "{}", self.0)
45 }
46}
47
48impl From<RowIndex> for u32 {
52 fn from(step: RowIndex) -> u32 {
53 step.0
54 }
55}
56
57impl From<RowIndex> for u64 {
58 fn from(step: RowIndex) -> u64 {
59 step.0 as u64
60 }
61}
62
63impl From<RowIndex> for usize {
64 fn from(step: RowIndex) -> usize {
65 step.0 as usize
66 }
67}
68
69impl From<RowIndex> for Felt {
70 fn from(step: RowIndex) -> Felt {
71 Felt::from_u32(step.0)
72 }
73}
74
75impl From<usize> for RowIndex {
85 fn from(value: usize) -> Self {
86 let value = u32::try_from(value)
87 .map_err(|_| RowIndexError::InvalidSize(format!("{value}_usize").into()))
88 .unwrap();
89 value.into()
90 }
91}
92
93impl TryFrom<u64> for RowIndex {
100 type Error = RowIndexError;
101
102 fn try_from(value: u64) -> Result<Self, Self::Error> {
103 let value = u32::try_from(value)
104 .map_err(|_| RowIndexError::InvalidSize(format!("{value}_u64").into()))?;
105 Ok(RowIndex::from(value))
106 }
107}
108
109impl From<u32> for RowIndex {
110 fn from(value: u32) -> Self {
111 Self(value)
112 }
113}
114
115impl miden_utils_indexing::Idx for RowIndex {}
116
117impl Serializable for RowIndex {
118 fn write_into<W: ByteWriter>(&self, target: &mut W) {
119 self.0.write_into(target);
120 }
121}
122
123impl Deserializable for RowIndex {
124 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
125 Ok(Self(u32::read_from(source)?))
126 }
127
128 fn min_serialized_size() -> usize {
129 u32::min_serialized_size()
130 }
131}
132
133impl From<i32> for RowIndex {
139 fn from(value: i32) -> Self {
140 let value = u32::try_from(value)
141 .map_err(|_| RowIndexError::InvalidSize(format!("{value}_i32").into()))
142 .unwrap();
143 RowIndex(value)
144 }
145}
146
147impl Sub<usize> for RowIndex {
157 type Output = RowIndex;
158
159 fn sub(self, rhs: usize) -> Self::Output {
160 let rhs = u32::try_from(rhs)
161 .map_err(|_| RowIndexError::InvalidSize(format!("{rhs}_usize").into()))
162 .unwrap();
163 RowIndex(self.0 - rhs)
164 }
165}
166
167impl SubAssign<u32> for RowIndex {
168 fn sub_assign(&mut self, rhs: u32) {
169 self.0 -= rhs;
170 }
171}
172
173impl Sub<RowIndex> for RowIndex {
174 type Output = usize;
175
176 fn sub(self, rhs: RowIndex) -> Self::Output {
177 (self.0 - rhs.0) as usize
178 }
179}
180
181impl RowIndex {
182 pub fn saturating_sub(self, rhs: u32) -> Self {
183 RowIndex(self.0.saturating_sub(rhs))
184 }
185
186 pub fn max(self, other: RowIndex) -> Self {
187 RowIndex(self.0.max(other.0))
188 }
189}
190
191impl Add<usize> for RowIndex {
198 type Output = RowIndex;
199
200 fn add(self, rhs: usize) -> Self::Output {
201 let rhs = u32::try_from(rhs)
202 .map_err(|_| RowIndexError::InvalidSize(format!("{rhs}_usize").into()))
203 .unwrap();
204 RowIndex(self.0 + rhs)
205 }
206}
207
208impl Add<RowIndex> for u32 {
209 type Output = RowIndex;
210
211 fn add(self, rhs: RowIndex) -> Self::Output {
212 RowIndex(self + rhs.0)
213 }
214}
215
216impl AddAssign<u32> for RowIndex {
223 fn add_assign(&mut self, rhs: u32) {
224 self.0 += rhs;
225 }
226}
227
228impl AddAssign<usize> for RowIndex {
235 fn add_assign(&mut self, rhs: usize) {
236 let rhs = u32::try_from(rhs)
237 .map_err(|_| RowIndexError::InvalidSize(format!("{rhs}_usize").into()))
238 .unwrap();
239 self.0 += rhs;
240 }
241}
242
243impl Mul<RowIndex> for usize {
244 type Output = RowIndex;
245
246 fn mul(self, rhs: RowIndex) -> Self::Output {
247 (self * rhs.0 as usize).into()
248 }
249}
250
251impl PartialEq<RowIndex> for RowIndex {
255 fn eq(&self, rhs: &RowIndex) -> bool {
256 self.0 == rhs.0
257 }
258}
259
260impl PartialEq<usize> for RowIndex {
261 fn eq(&self, rhs: &usize) -> bool {
262 self.0
263 == u32::try_from(*rhs)
264 .map_err(|_| RowIndexError::InvalidSize(format!("{}_usize", *rhs).into()))
265 .unwrap()
266 }
267}
268
269impl PartialEq<RowIndex> for i32 {
270 fn eq(&self, rhs: &RowIndex) -> bool {
271 *self as u32 == u32::from(*rhs)
272 }
273}
274
275impl PartialOrd<usize> for RowIndex {
276 fn partial_cmp(&self, rhs: &usize) -> Option<core::cmp::Ordering> {
277 let rhs = u32::try_from(*rhs)
278 .map_err(|_| RowIndexError::InvalidSize(format!("{}_usize", *rhs).into()))
279 .unwrap();
280 self.0.partial_cmp(&rhs)
281 }
282}
283
284impl<T> Index<RowIndex> for [T] {
285 type Output = T;
286 fn index(&self, i: RowIndex) -> &Self::Output {
287 &self[i.0 as usize]
288 }
289}
290
291impl<T> IndexMut<RowIndex> for [T] {
292 fn index_mut(&mut self, i: RowIndex) -> &mut Self::Output {
293 &mut self[i.0 as usize]
294 }
295}
296
297impl<T> Index<RowIndex> for Vec<T> {
298 type Output = T;
299 fn index(&self, i: RowIndex) -> &Self::Output {
300 &self.as_slice()[i]
301 }
302}
303
304impl RangeBounds<RowIndex> for RowIndex {
305 fn start_bound(&self) -> Bound<&Self> {
306 Bound::Included(self)
307 }
308 fn end_bound(&self) -> Bound<&Self> {
309 Bound::Included(self)
310 }
311}
312
313#[cfg(any(test, feature = "arbitrary"))]
320mod arbitrary {
321 use proptest::prelude::*;
322
323 use super::RowIndex;
324
325 impl Arbitrary for RowIndex {
326 type Parameters = ();
327 type Strategy = BoxedStrategy<Self>;
328
329 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
330 any::<u32>().prop_map(RowIndex).boxed()
332 }
333 }
334}
335
336#[cfg(test)]
337mod tests {
338 use alloc::collections::BTreeMap;
339
340 use miden_core::serde::{Deserializable, Serializable};
341
342 #[test]
343 fn row_index_ops() {
344 use super::RowIndex;
345
346 assert_eq!(RowIndex(5), 5);
348 assert_eq!(RowIndex(5), RowIndex(5));
349 assert!(RowIndex(5) == RowIndex(5));
350 assert!(RowIndex(5) >= RowIndex(5));
351 assert!(RowIndex(6) >= RowIndex(5));
352 assert!(RowIndex(5) > RowIndex(4));
353 assert!(RowIndex(5) <= RowIndex(5));
354 assert!(RowIndex(4) <= RowIndex(5));
355 assert!(RowIndex(5) < RowIndex(6));
356
357 assert_eq!(RowIndex(5) + 3, 8);
359 assert_eq!(RowIndex(5) - 3, 2);
360 assert_eq!(3 + RowIndex(5), 8);
361 assert_eq!(2 * RowIndex(5), 10);
362
363 let mut step = RowIndex(5);
365 step += 5_u32;
366 assert_eq!(step, 10);
367 }
368
369 #[test]
370 fn row_index_range() {
371 use super::RowIndex;
372 let mut tree: BTreeMap<RowIndex, usize> = BTreeMap::new();
373 tree.insert(RowIndex(0), 0);
374 tree.insert(RowIndex(1), 1);
375 tree.insert(RowIndex(2), 2);
376 let acc =
377 tree.range(RowIndex::from(0)..RowIndex::from(tree.len()))
378 .fold(0, |acc, (key, val)| {
379 assert_eq!(*key, RowIndex::from(acc));
380 assert_eq!(*val, acc);
381 acc + 1
382 });
383 assert_eq!(acc, 3);
384 }
385
386 #[test]
387 fn row_index_display() {
388 assert_eq!(format!("{}", super::RowIndex(5)), "5");
389 }
390
391 #[test]
392 fn row_index_serialization_roundtrip() {
393 let original = super::RowIndex(u32::MAX);
394 let bytes = original.to_bytes();
395
396 assert_eq!(bytes, u32::MAX.to_bytes());
397 assert_eq!(super::RowIndex::read_from_bytes(&bytes).unwrap(), original);
398 }
399}