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		*<[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		*<[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		*<[T]>::get_unchecked_mut(self, index) = value;
85	}
86}
87
88/// A subrange adapter of a collection of scalars.
89#[derive(Clone)]
90pub struct SequenceSubrange<'a, T: Copy, Inner: RandomAccessSequence<T>> {
91	inner: &'a Inner,
92	offset: usize,
93	len: usize,
94	_marker: std::marker::PhantomData<T>,
95}
96
97impl<'a, T: Copy, Inner: RandomAccessSequence<T>> SequenceSubrange<'a, T, Inner> {
98	#[inline(always)]
99	pub fn new(inner: &'a Inner, offset: usize, len: usize) -> Self {
100		assert!(offset + len <= inner.len(), "subrange out of bounds");
101
102		Self {
103			inner,
104			offset,
105			len,
106			_marker: std::marker::PhantomData,
107		}
108	}
109}
110
111impl<T: Copy, Inner: RandomAccessSequence<T>> RandomAccessSequence<T>
112	for SequenceSubrange<'_, T, Inner>
113{
114	#[inline(always)]
115	fn len(&self) -> usize {
116		self.len
117	}
118
119	#[inline(always)]
120	unsafe fn get_unchecked(&self, index: usize) -> T {
121		self.inner.get_unchecked(index + self.offset)
122	}
123}
124
125/// A subrange adapter of a mutable collection of scalars.
126pub struct SequenceSubrangeMut<'a, T: Copy, Inner: RandomAccessSequenceMut<T>> {
127	inner: &'a mut Inner,
128	offset: usize,
129	len: usize,
130	_marker: std::marker::PhantomData<&'a T>,
131}
132
133impl<'a, T: Copy, Inner: RandomAccessSequenceMut<T>> SequenceSubrangeMut<'a, T, Inner> {
134	#[inline(always)]
135	pub fn new(inner: &'a mut Inner, offset: usize, len: usize) -> Self {
136		assert!(offset + len <= inner.len(), "subrange out of bounds");
137
138		Self {
139			inner,
140			offset,
141			len,
142			_marker: std::marker::PhantomData,
143		}
144	}
145}
146impl<T: Copy, Inner: RandomAccessSequenceMut<T>> RandomAccessSequence<T>
147	for SequenceSubrangeMut<'_, T, Inner>
148{
149	#[inline(always)]
150	fn len(&self) -> usize {
151		self.len
152	}
153
154	#[inline(always)]
155	unsafe fn get_unchecked(&self, index: usize) -> T {
156		self.inner.get_unchecked(index + self.offset)
157	}
158}
159impl<T: Copy, Inner: RandomAccessSequenceMut<T>> RandomAccessSequenceMut<T>
160	for SequenceSubrangeMut<'_, T, Inner>
161{
162	#[inline(always)]
163	unsafe fn set_unchecked(&mut self, index: usize, value: T) {
164		self.inner.set_unchecked(index + self.offset, value);
165	}
166}
167
168#[cfg(test)]
169mod tests {
170	use std::fmt::Debug;
171
172	use rand::{rngs::StdRng, Rng, SeedableRng};
173
174	use super::*;
175
176	fn check_collection<T: Copy + Eq + Debug>(
177		collection: &impl RandomAccessSequence<T>,
178		expected: &[T],
179	) {
180		assert_eq!(collection.len(), expected.len());
181
182		for (i, v) in expected.iter().enumerate() {
183			assert_eq!(&collection.get(i), v);
184			assert_eq!(&unsafe { collection.get_unchecked(i) }, v);
185		}
186	}
187
188	fn check_collection_get_set<T: Eq + Copy + Debug>(
189		collection: &mut impl RandomAccessSequenceMut<T>,
190		gen: &mut impl FnMut() -> T,
191	) {
192		for i in 0..collection.len() {
193			let value = gen();
194			collection.set(i, value);
195			assert_eq!(collection.get(i), value);
196			assert_eq!(unsafe { collection.get_unchecked(i) }, value);
197		}
198	}
199
200	#[test]
201	fn check_slice() {
202		let slice: &[usize] = &[];
203		check_collection::<usize>(&slice, slice);
204
205		let slice: &[usize] = &[1usize, 2, 3];
206		check_collection(&slice, slice);
207	}
208
209	#[test]
210	fn check_slice_mut() {
211		let mut rng = StdRng::seed_from_u64(0);
212		let mut gen = || -> usize { rng.gen() };
213
214		let mut slice: &mut [usize] = &mut [];
215
216		check_collection(&slice, slice);
217		check_collection_get_set(&mut slice, &mut gen);
218
219		let mut slice: &mut [usize] = &mut [1, 2, 3];
220		check_collection(&slice, slice);
221		check_collection_get_set(&mut slice, &mut gen);
222	}
223
224	#[test]
225	fn test_subrange() {
226		let slice: &[usize] = &[1, 2, 3, 4, 5];
227		let subrange = SequenceSubrange::new(&slice, 1, 3);
228		check_collection(&subrange, &[2, 3, 4]);
229	}
230
231	#[test]
232	fn test_subrange_mut() {
233		let mut rng = StdRng::seed_from_u64(0);
234		let mut gen = || -> usize { rng.gen() };
235
236		let mut slice: &mut [usize] = &mut [1, 2, 3, 4, 5];
237		let values = slice[1..4].to_vec();
238		let mut subrange = SequenceSubrangeMut::new(&mut slice, 1, 3);
239		check_collection(&subrange, &values);
240		check_collection_get_set(&mut subrange, &mut gen);
241	}
242}