binius_utils/
random_access_sequence.rs

1// Copyright 2025 Irreducible Inc.
2
3/// A trait for a collection that allows indexed access by value.
4/// This trait is used to abstract over different types of collections - scalar slices,
5/// slices of packed field elements including subranges of collections.
6pub trait RandomAccessSequence<T: Copy> {
7	fn len(&self) -> usize;
8
9	#[inline(always)]
10	fn is_empty(&self) -> bool {
11		self.len() == 0
12	}
13
14	#[inline(always)]
15	fn get(&self, index: usize) -> T {
16		assert!(index < self.len(), "Index out of bounds");
17		unsafe { self.get_unchecked(index) }
18	}
19
20	/// Returns a copy of the element at the given index.
21	///
22	/// # Safety
23	/// The caller must ensure that the `index` < `self.len()`.
24	unsafe fn get_unchecked(&self, index: usize) -> T;
25}
26
27/// A trait for a mutable access to a collection of scalars.
28pub trait RandomAccessSequenceMut<T: Copy>: RandomAccessSequence<T> {
29	#[inline(always)]
30	fn set(&mut self, index: usize, value: T) {
31		assert!(index < self.len(), "Index out of bounds");
32		unsafe { self.set_unchecked(index, value) }
33	}
34
35	/// Sets the element at the given index to the given value.
36	///
37	/// # Safety
38	/// The caller must ensure that the `index` < `self.len()`.
39	unsafe fn set_unchecked(&mut self, index: usize, value: T);
40}
41
42impl<T: Copy> RandomAccessSequence<T> for &[T] {
43	#[inline(always)]
44	fn len(&self) -> usize {
45		<[T]>::len(self)
46	}
47
48	#[inline(always)]
49	fn get(&self, index: usize) -> T {
50		self[index]
51	}
52
53	#[inline(always)]
54	unsafe fn get_unchecked(&self, index: usize) -> T {
55		unsafe { *<[T]>::get_unchecked(self, index) }
56	}
57}
58
59impl<T: Copy> RandomAccessSequence<T> for &mut [T] {
60	#[inline(always)]
61	fn len(&self) -> usize {
62		<[T]>::len(self)
63	}
64
65	#[inline(always)]
66	fn get(&self, index: usize) -> T {
67		self[index]
68	}
69
70	#[inline(always)]
71	unsafe fn get_unchecked(&self, index: usize) -> T {
72		unsafe { *<[T]>::get_unchecked(self, index) }
73	}
74}
75
76impl<T: Copy> RandomAccessSequenceMut<T> for &mut [T] {
77	#[inline(always)]
78	fn set(&mut self, index: usize, value: T) {
79		self[index] = value;
80	}
81
82	#[inline(always)]
83	unsafe fn set_unchecked(&mut self, index: usize, value: T) {
84		unsafe {
85			*<[T]>::get_unchecked_mut(self, index) = value;
86		}
87	}
88}
89
90/// A subrange adapter of a collection of scalars.
91#[derive(Clone)]
92pub struct SequenceSubrange<'a, T: Copy, Inner: RandomAccessSequence<T>> {
93	inner: &'a Inner,
94	offset: usize,
95	len: usize,
96	_marker: std::marker::PhantomData<T>,
97}
98
99impl<'a, T: Copy, Inner: RandomAccessSequence<T>> SequenceSubrange<'a, T, Inner> {
100	#[inline(always)]
101	pub fn new(inner: &'a Inner, offset: usize, len: usize) -> Self {
102		assert!(offset + len <= inner.len(), "subrange out of bounds");
103
104		Self {
105			inner,
106			offset,
107			len,
108			_marker: std::marker::PhantomData,
109		}
110	}
111}
112
113impl<T: Copy, Inner: RandomAccessSequence<T>> RandomAccessSequence<T>
114	for SequenceSubrange<'_, T, Inner>
115{
116	#[inline(always)]
117	fn len(&self) -> usize {
118		self.len
119	}
120
121	#[inline(always)]
122	unsafe fn get_unchecked(&self, index: usize) -> T {
123		unsafe { self.inner.get_unchecked(index + self.offset) }
124	}
125}
126
127/// A subrange adapter of a mutable collection of scalars.
128pub struct SequenceSubrangeMut<'a, T: Copy, Inner: RandomAccessSequenceMut<T>> {
129	inner: &'a mut Inner,
130	offset: usize,
131	len: usize,
132	_marker: std::marker::PhantomData<&'a T>,
133}
134
135impl<'a, T: Copy, Inner: RandomAccessSequenceMut<T>> SequenceSubrangeMut<'a, T, Inner> {
136	#[inline(always)]
137	pub fn new(inner: &'a mut Inner, offset: usize, len: usize) -> Self {
138		assert!(offset + len <= inner.len(), "subrange out of bounds");
139
140		Self {
141			inner,
142			offset,
143			len,
144			_marker: std::marker::PhantomData,
145		}
146	}
147}
148impl<T: Copy, Inner: RandomAccessSequenceMut<T>> RandomAccessSequence<T>
149	for SequenceSubrangeMut<'_, T, Inner>
150{
151	#[inline(always)]
152	fn len(&self) -> usize {
153		self.len
154	}
155
156	#[inline(always)]
157	unsafe fn get_unchecked(&self, index: usize) -> T {
158		unsafe { self.inner.get_unchecked(index + self.offset) }
159	}
160}
161impl<T: Copy, Inner: RandomAccessSequenceMut<T>> RandomAccessSequenceMut<T>
162	for SequenceSubrangeMut<'_, T, Inner>
163{
164	#[inline(always)]
165	unsafe fn set_unchecked(&mut self, index: usize, value: T) {
166		unsafe {
167			self.inner.set_unchecked(index + self.offset, value);
168		}
169	}
170}
171
172#[cfg(test)]
173mod tests {
174	use std::fmt::Debug;
175
176	use rand::{Rng, SeedableRng, rngs::StdRng};
177
178	use super::*;
179
180	fn check_collection<T: Copy + Eq + Debug>(
181		collection: &impl RandomAccessSequence<T>,
182		expected: &[T],
183	) {
184		assert_eq!(collection.len(), expected.len());
185
186		for (i, v) in expected.iter().enumerate() {
187			assert_eq!(&collection.get(i), v);
188			assert_eq!(&unsafe { collection.get_unchecked(i) }, v);
189		}
190	}
191
192	fn check_collection_get_set<T: Eq + Copy + Debug>(
193		collection: &mut impl RandomAccessSequenceMut<T>,
194		r#gen: &mut impl FnMut() -> T,
195	) {
196		for i in 0..collection.len() {
197			let value = r#gen();
198			collection.set(i, value);
199			assert_eq!(collection.get(i), value);
200			assert_eq!(unsafe { collection.get_unchecked(i) }, value);
201		}
202	}
203
204	#[test]
205	fn check_slice() {
206		let slice: &[usize] = &[];
207		check_collection::<usize>(&slice, slice);
208
209		let slice: &[usize] = &[1usize, 2, 3];
210		check_collection(&slice, slice);
211	}
212
213	#[test]
214	fn check_slice_mut() {
215		let mut rng = StdRng::seed_from_u64(0);
216		let mut r#gen = || -> usize { rng.r#gen() };
217
218		let mut slice: &mut [usize] = &mut [];
219
220		check_collection(&slice, slice);
221		check_collection_get_set(&mut slice, &mut r#gen);
222
223		let mut slice: &mut [usize] = &mut [1, 2, 3];
224		check_collection(&slice, slice);
225		check_collection_get_set(&mut slice, &mut r#gen);
226	}
227
228	#[test]
229	fn test_subrange() {
230		let slice: &[usize] = &[1, 2, 3, 4, 5];
231		let subrange = SequenceSubrange::new(&slice, 1, 3);
232		check_collection(&subrange, &[2, 3, 4]);
233	}
234
235	#[test]
236	fn test_subrange_mut() {
237		let mut rng = StdRng::seed_from_u64(0);
238		let mut r#gen = || -> usize { rng.r#gen() };
239
240		let mut slice: &mut [usize] = &mut [1, 2, 3, 4, 5];
241		let values = slice[1..4].to_vec();
242		let mut subrange = SequenceSubrangeMut::new(&mut slice, 1, 3);
243		check_collection(&subrange, &values);
244		check_collection_get_set(&mut subrange, &mut r#gen);
245	}
246}