1use alloc::boxed::Box;
2use core::{
3 fmt::{Display, Formatter},
4 ops::{Add, AddAssign, Bound, Index, IndexMut, Mul, RangeBounds, Sub, SubAssign},
5};
6
7use miden_core::Felt;
8
9#[derive(Debug, thiserror::Error)]
12pub enum RowIndexError {
13 #[error("value {0} is larger than u32::MAX so it cannot be converted into a RowIndex")]
15 InvalidSize(Box<str>),
16}
17
18#[derive(Debug, Default, Copy, Clone, Eq, Ord, PartialOrd)]
23pub struct RowIndex(u32);
24
25impl RowIndex {
26 pub fn as_usize(&self) -> usize {
27 self.0 as usize
28 }
29
30 pub fn as_u32(&self) -> u32 {
31 self.0
32 }
33}
34
35impl Display for RowIndex {
36 fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
37 write!(f, "{}", self.0)
38 }
39}
40
41impl From<RowIndex> for u32 {
45 fn from(step: RowIndex) -> u32 {
46 step.0
47 }
48}
49
50impl From<RowIndex> for u64 {
51 fn from(step: RowIndex) -> u64 {
52 step.0 as u64
53 }
54}
55
56impl From<RowIndex> for usize {
57 fn from(step: RowIndex) -> usize {
58 step.0 as usize
59 }
60}
61
62impl From<RowIndex> for Felt {
63 fn from(step: RowIndex) -> Felt {
64 Felt::from(step.0)
65 }
66}
67
68impl From<usize> for RowIndex {
78 fn from(value: usize) -> Self {
79 let value = u32::try_from(value)
80 .map_err(|_| RowIndexError::InvalidSize(format!("{value}_usize").into()))
81 .unwrap();
82 value.into()
83 }
84}
85
86impl TryFrom<u64> for RowIndex {
93 type Error = RowIndexError;
94
95 fn try_from(value: u64) -> Result<Self, Self::Error> {
96 let value = u32::try_from(value)
97 .map_err(|_| RowIndexError::InvalidSize(format!("{value}_u64").into()))?;
98 Ok(RowIndex::from(value))
99 }
100}
101
102impl From<u32> for RowIndex {
103 fn from(value: u32) -> Self {
104 Self(value)
105 }
106}
107
108impl miden_utils_indexing::Idx for RowIndex {}
109
110impl From<i32> for RowIndex {
116 fn from(value: i32) -> Self {
117 let value = u32::try_from(value)
118 .map_err(|_| RowIndexError::InvalidSize(format!("{value}_i32").into()))
119 .unwrap();
120 RowIndex(value)
121 }
122}
123
124impl Sub<usize> for RowIndex {
134 type Output = RowIndex;
135
136 fn sub(self, rhs: usize) -> Self::Output {
137 let rhs = u32::try_from(rhs)
138 .map_err(|_| RowIndexError::InvalidSize(format!("{rhs}_usize").into()))
139 .unwrap();
140 RowIndex(self.0 - rhs)
141 }
142}
143
144impl SubAssign<u32> for RowIndex {
145 fn sub_assign(&mut self, rhs: u32) {
146 self.0 -= rhs;
147 }
148}
149
150impl Sub<RowIndex> for RowIndex {
151 type Output = usize;
152
153 fn sub(self, rhs: RowIndex) -> Self::Output {
154 (self.0 - rhs.0) as usize
155 }
156}
157
158impl RowIndex {
159 pub fn saturating_sub(self, rhs: u32) -> Self {
160 RowIndex(self.0.saturating_sub(rhs))
161 }
162
163 pub fn max(self, other: RowIndex) -> Self {
164 RowIndex(self.0.max(other.0))
165 }
166}
167
168impl Add<usize> for RowIndex {
175 type Output = RowIndex;
176
177 fn add(self, rhs: usize) -> Self::Output {
178 let rhs = u32::try_from(rhs)
179 .map_err(|_| RowIndexError::InvalidSize(format!("{rhs}_usize").into()))
180 .unwrap();
181 RowIndex(self.0 + rhs)
182 }
183}
184
185impl Add<RowIndex> for u32 {
186 type Output = RowIndex;
187
188 fn add(self, rhs: RowIndex) -> Self::Output {
189 RowIndex(self + rhs.0)
190 }
191}
192
193impl AddAssign<u32> for RowIndex {
200 fn add_assign(&mut self, rhs: u32) {
201 self.0 += rhs;
202 }
203}
204
205impl AddAssign<usize> for RowIndex {
212 fn add_assign(&mut self, rhs: usize) {
213 let rhs = u32::try_from(rhs)
214 .map_err(|_| RowIndexError::InvalidSize(format!("{rhs}_usize").into()))
215 .unwrap();
216 self.0 += rhs;
217 }
218}
219
220impl Mul<RowIndex> for usize {
221 type Output = RowIndex;
222
223 fn mul(self, rhs: RowIndex) -> Self::Output {
224 (self * rhs.0 as usize).into()
225 }
226}
227
228impl PartialEq<RowIndex> for RowIndex {
232 fn eq(&self, rhs: &RowIndex) -> bool {
233 self.0 == rhs.0
234 }
235}
236
237impl PartialEq<usize> for RowIndex {
238 fn eq(&self, rhs: &usize) -> bool {
239 self.0
240 == u32::try_from(*rhs)
241 .map_err(|_| RowIndexError::InvalidSize(format!("{}_usize", *rhs).into()))
242 .unwrap()
243 }
244}
245
246impl PartialEq<RowIndex> for i32 {
247 fn eq(&self, rhs: &RowIndex) -> bool {
248 *self as u32 == u32::from(*rhs)
249 }
250}
251
252impl PartialOrd<usize> for RowIndex {
253 fn partial_cmp(&self, rhs: &usize) -> Option<core::cmp::Ordering> {
254 let rhs = u32::try_from(*rhs)
255 .map_err(|_| RowIndexError::InvalidSize(format!("{}_usize", *rhs).into()))
256 .unwrap();
257 self.0.partial_cmp(&rhs)
258 }
259}
260
261impl<T> Index<RowIndex> for [T] {
262 type Output = T;
263 fn index(&self, i: RowIndex) -> &Self::Output {
264 &self[i.0 as usize]
265 }
266}
267
268impl<T> IndexMut<RowIndex> for [T] {
269 fn index_mut(&mut self, i: RowIndex) -> &mut Self::Output {
270 &mut self[i.0 as usize]
271 }
272}
273
274impl RangeBounds<RowIndex> for RowIndex {
275 fn start_bound(&self) -> Bound<&Self> {
276 Bound::Included(self)
277 }
278 fn end_bound(&self) -> Bound<&Self> {
279 Bound::Included(self)
280 }
281}
282
283#[cfg(test)]
286mod tests {
287 use alloc::collections::BTreeMap;
288
289 #[test]
290 fn row_index_conversions() {
291 use super::RowIndex;
292 let _: RowIndex = 5.into();
294 let _: RowIndex = 5u32.into();
295 let _: RowIndex = (5usize).into();
296
297 let _: u32 = RowIndex(5).into();
299 let _: u64 = RowIndex(5).into();
300 let _: usize = RowIndex(5).into();
301 }
302
303 #[test]
304 fn row_index_ops() {
305 use super::RowIndex;
306
307 assert_eq!(RowIndex(5), 5);
309 assert_eq!(RowIndex(5), RowIndex(5));
310 assert!(RowIndex(5) == RowIndex(5));
311 assert!(RowIndex(5) >= RowIndex(5));
312 assert!(RowIndex(6) >= RowIndex(5));
313 assert!(RowIndex(5) > RowIndex(4));
314 assert!(RowIndex(5) <= RowIndex(5));
315 assert!(RowIndex(4) <= RowIndex(5));
316 assert!(RowIndex(5) < RowIndex(6));
317
318 assert_eq!(RowIndex(5) + 3, 8);
320 assert_eq!(RowIndex(5) - 3, 2);
321 assert_eq!(3 + RowIndex(5), 8);
322 assert_eq!(2 * RowIndex(5), 10);
323
324 let mut step = RowIndex(5);
326 step += 5_u32;
327 assert_eq!(step, 10);
328 }
329
330 #[test]
331 fn row_index_range() {
332 use super::RowIndex;
333 let mut tree: BTreeMap<RowIndex, usize> = BTreeMap::new();
334 tree.insert(RowIndex(0), 0);
335 tree.insert(RowIndex(1), 1);
336 tree.insert(RowIndex(2), 2);
337 let acc =
338 tree.range(RowIndex::from(0)..RowIndex::from(tree.len()))
339 .fold(0, |acc, (key, val)| {
340 assert_eq!(*key, RowIndex::from(acc));
341 assert_eq!(*val, acc);
342 acc + 1
343 });
344 assert_eq!(acc, 3);
345 }
346
347 #[test]
348 fn row_index_display() {
349 assert_eq!(format!("{}", super::RowIndex(5)), "5");
350 }
351}