binius_math/
field_buffer.rs

1// Copyright 2025 Irreducible Inc.
2
3use std::{
4	ops::{Deref, DerefMut, Index, IndexMut},
5	slice,
6};
7
8use binius_field::{
9	Field, PackedField,
10	packed::{get_packed_slice_unchecked, set_packed_slice_unchecked},
11};
12use binius_utils::{
13	checked_arithmetics::{checked_log_2, strict_log_2},
14	rayon::{prelude::*, slice::ParallelSlice},
15};
16use bytemuck::zeroed_vec;
17
18use crate::Error;
19
20/// A power-of-two-sized buffer containing field elements, stored in packed fields.
21///
22/// This struct maintains a set of invariants:
23///  1) `values.len()` is a power of two
24///  2) `values.len() >= 1 << log_len.saturating_sub(P::LOG_WIDTH)`.
25#[derive(Debug, Clone, Eq)]
26pub struct FieldBuffer<P: PackedField, Data: Deref<Target = [P]> = Box<[P]>> {
27	/// log2 the number over elements in the buffer.
28	log_len: usize,
29	/// The packed values.
30	values: Data,
31}
32
33impl<P: PackedField, Data: Deref<Target = [P]>> PartialEq for FieldBuffer<P, Data> {
34	fn eq(&self, other: &Self) -> bool {
35		// Custom equality impl is needed because values beyond length until capacity can be
36		// arbitrary.
37		if self.log_len < P::LOG_WIDTH {
38			let iter_1 = self
39				.values
40				.first()
41				.expect("len >= 1")
42				.iter()
43				.take(1 << self.log_len);
44			let iter_2 = other
45				.values
46				.first()
47				.expect("len >= 1")
48				.iter()
49				.take(1 << self.log_len);
50			iter_1.eq(iter_2)
51		} else {
52			let prefix = 1 << (self.log_len - P::LOG_WIDTH);
53			self.log_len == other.log_len && self.values[..prefix] == other.values[..prefix]
54		}
55	}
56}
57
58impl<P: PackedField> FieldBuffer<P> {
59	/// Create a new FieldBuffer from a vector of values.
60	///
61	/// # Throws
62	///
63	/// * `PowerOfTwoLengthRequired` if the number of values is not a power of two.
64	pub fn from_values(values: &[P::Scalar]) -> Result<Self, Error> {
65		let Some(log_len) = strict_log_2(values.len()) else {
66			return Err(Error::PowerOfTwoLengthRequired);
67		};
68
69		Self::from_values_truncated(values, log_len)
70	}
71
72	/// Create a new FieldBuffer from a vector of values.
73	///
74	/// Capacity `log_cap` is bumped to at least `P::LOG_WIDTH`.
75	///
76	/// # Throws
77	///
78	/// * `PowerOfTwoLengthRequired` if the number of values is not a power of two.
79	/// * `IncorrectArgumentLength` if the number of values exceeds `1 << log_cap`.
80	pub fn from_values_truncated(values: &[P::Scalar], log_cap: usize) -> Result<Self, Error> {
81		if !values.len().is_power_of_two() {
82			return Err(Error::PowerOfTwoLengthRequired);
83		}
84
85		let log_len = values.len().ilog2() as usize;
86		if log_len > log_cap {
87			return Err(Error::IncorrectArgumentLength {
88				arg: "values".to_string(),
89				expected: 1 << log_cap,
90			});
91		}
92
93		let packed_cap = 1 << log_cap.saturating_sub(P::LOG_WIDTH);
94		let mut packed_values = Vec::with_capacity(packed_cap);
95		packed_values.extend(
96			values
97				.chunks(P::WIDTH)
98				.map(|chunk| P::from_scalars(chunk.iter().copied())),
99		);
100		packed_values.resize(packed_cap, P::zero());
101
102		Ok(Self {
103			log_len,
104			values: packed_values.into_boxed_slice(),
105		})
106	}
107
108	/// Create a new [`FieldBuffer`] of zeros with the given log_len.
109	pub fn zeros(log_len: usize) -> Self {
110		Self::zeros_truncated(log_len, log_len).expect("log_len == log_cap")
111	}
112
113	/// Create a new [`FieldBuffer`] of zeros with the given log_len and capacity log_cap.
114	///
115	/// Capacity `log_cap` is bumped to at least `P::LOG_WIDTH`.
116	pub fn zeros_truncated(log_len: usize, log_cap: usize) -> Result<Self, Error> {
117		if log_len > log_cap {
118			return Err(Error::IncorrectArgumentLength {
119				arg: "log_len".to_string(),
120				expected: log_cap,
121			});
122		}
123		let packed_len = 1 << log_cap.saturating_sub(P::LOG_WIDTH);
124		let values = zeroed_vec(packed_len).into_boxed_slice();
125		Ok(Self { log_len, values })
126	}
127}
128
129#[allow(clippy::len_without_is_empty)]
130impl<P: PackedField, Data: Deref<Target = [P]>> FieldBuffer<P, Data> {
131	/// Create a new FieldBuffer from a slice of packed values.
132	///
133	/// # Throws
134	///
135	/// * `IncorrectArgumentLength` if the number of field elements does not fit the `values.len()`
136	///   exactly.
137	pub fn new(log_len: usize, values: Data) -> Result<Self, Error> {
138		let expected_packed_len = 1 << log_len.saturating_sub(P::LOG_WIDTH);
139		if values.len() != expected_packed_len {
140			return Err(Error::IncorrectArgumentLength {
141				arg: "values".to_string(),
142				expected: expected_packed_len,
143			});
144		}
145		Self::new_truncated(log_len, values)
146	}
147
148	/// Create a new FieldBuffer from a slice of packed values.
149	///
150	/// # Throws
151	///
152	/// * `IncorrectArgumentLength` if the number of field elements does not fit into the `values`.
153	/// * `PowerOfTwoLengthRequired` if the `values.len()` is not a power of two.
154	pub fn new_truncated(log_len: usize, values: Data) -> Result<Self, Error> {
155		let min_packed_len = 1 << log_len.saturating_sub(P::LOG_WIDTH);
156		if values.len() < min_packed_len {
157			return Err(Error::IncorrectArgumentLength {
158				arg: "values".to_string(),
159				expected: min_packed_len,
160			});
161		}
162
163		if !values.len().is_power_of_two() {
164			return Err(Error::PowerOfTwoLengthRequired);
165		}
166
167		Ok(Self { log_len, values })
168	}
169
170	/// Returns log2 the number of field elements that the underlying collection may take.
171	pub fn log_cap(&self) -> usize {
172		checked_log_2(self.values.len()) + P::LOG_WIDTH
173	}
174
175	/// Returns the number of field elements that the underlying collection may take.
176	pub fn cap(&self) -> usize {
177		1 << self.log_cap()
178	}
179
180	/// Returns log2 the number of field elements.
181	pub fn log_len(&self) -> usize {
182		self.log_len
183	}
184
185	/// Returns the number of field elements.
186	pub fn len(&self) -> usize {
187		1 << self.log_len
188	}
189
190	/// Borrows the buffer as a [`FieldSlice`].
191	pub fn to_ref(&self) -> FieldSlice<'_, P> {
192		FieldSlice::from_slice(self.log_len, self.as_ref())
193			.expect("log_len matches values.len() by struct invariant")
194	}
195
196	/// Get a field element at the given index.
197	///
198	/// # Preconditions
199	///
200	/// * the index is in the range `0..self.len()`
201	pub fn get(&self, index: usize) -> P::Scalar {
202		self.get_checked(index)
203			.expect("precondition: index is in range")
204	}
205
206	/// Get a field element at the given index.
207	///
208	/// # Throws
209	///
210	/// * `Error::ArgumentRangeError` if the index is out of bounds.
211	pub fn get_checked(&self, index: usize) -> Result<P::Scalar, Error> {
212		if index >= self.len() {
213			return Err(Error::ArgumentRangeError {
214				arg: "index".to_string(),
215				range: 0..self.len(),
216			});
217		}
218
219		// Safety: bound check on index performed above. The buffer length is at least
220		// `self.len() >> P::LOG_WIDTH` by struct invariant.
221		let val = unsafe { get_packed_slice_unchecked(&self.values, index) };
222		Ok(val)
223	}
224
225	/// Returns an iterator over the scalar elements in the buffer.
226	pub fn iter_scalars(&self) -> impl Iterator<Item = P::Scalar> + Send + Clone + '_ {
227		P::iter_slice(self.as_ref()).take(self.len())
228	}
229
230	/// Get an aligned chunk of size `2^log_chunk_size`.
231	///
232	/// Chunk start offset divides chunk size; the result is essentially
233	/// `chunks(log_chunk_size).nth(chunk_index)` but unlike `chunks` it does
234	/// support sizes smaller than packing width.
235	pub fn chunk(
236		&self,
237		log_chunk_size: usize,
238		chunk_index: usize,
239	) -> Result<FieldSlice<'_, P>, Error> {
240		if log_chunk_size > self.log_len {
241			return Err(Error::ArgumentRangeError {
242				arg: "log_chunk_size".to_string(),
243				range: 0..self.log_len + 1,
244			});
245		}
246
247		let chunk_count = 1 << (self.log_len - log_chunk_size);
248		if chunk_index >= chunk_count {
249			return Err(Error::ArgumentRangeError {
250				arg: "chunk_index".to_string(),
251				range: 0..chunk_count,
252			});
253		}
254
255		let values = if log_chunk_size >= P::LOG_WIDTH {
256			let packed_log_chunk_size = log_chunk_size - P::LOG_WIDTH;
257			let chunk =
258				&self.values[chunk_index << packed_log_chunk_size..][..1 << packed_log_chunk_size];
259			FieldSliceData::Slice(chunk)
260		} else {
261			let packed_log_chunks = P::LOG_WIDTH - log_chunk_size;
262			let packed = self.values[chunk_index >> packed_log_chunks];
263			let chunk_subindex = chunk_index & ((1 << packed_log_chunks) - 1);
264			let chunk = P::from_scalars(
265				(0..1 << log_chunk_size).map(|i| packed.get(chunk_subindex << log_chunk_size | i)),
266			);
267			FieldSliceData::Single(chunk)
268		};
269
270		Ok(FieldBuffer {
271			log_len: log_chunk_size,
272			values,
273		})
274	}
275
276	/// Split the buffer into chunks of size `2^log_chunk_size`.
277	///
278	/// # Errors
279	///
280	/// * [`Error::ArgumentRangeError`] if `log_chunk_size < P::LOG_WIDTH` or `log_chunk_size >
281	///   log_len`.
282	pub fn chunks(
283		&self,
284		log_chunk_size: usize,
285	) -> Result<impl Iterator<Item = FieldSlice<'_, P>> + Clone, Error> {
286		if log_chunk_size < P::LOG_WIDTH || log_chunk_size > self.log_len {
287			return Err(Error::ArgumentRangeError {
288				arg: "log_chunk_size".to_string(),
289				range: P::LOG_WIDTH..self.log_len + 1,
290			});
291		}
292
293		let chunk_count = 1 << (self.log_len - log_chunk_size);
294		let packed_chunk_size = 1 << (log_chunk_size - P::LOG_WIDTH);
295		let chunks = self
296			.values
297			.chunks(packed_chunk_size)
298			.take(chunk_count)
299			.map(move |chunk| FieldBuffer {
300				log_len: log_chunk_size,
301				values: FieldSliceData::Slice(chunk),
302			});
303
304		Ok(chunks)
305	}
306
307	/// Creates an iterator over chunks of size `2^log_chunk_size` in parallel.
308	///
309	/// # Throws
310	///
311	/// * [`Error::ArgumentRangeError`] if `log_chunk_size < P::LOG_WIDTH` or `log_chunk_size >
312	///   log_len`.
313	pub fn chunks_par(
314		&self,
315		log_chunk_size: usize,
316	) -> Result<impl IndexedParallelIterator<Item = FieldSlice<'_, P>>, Error> {
317		if log_chunk_size < P::LOG_WIDTH || log_chunk_size > self.log_len {
318			return Err(Error::ArgumentRangeError {
319				arg: "log_chunk_size".to_string(),
320				range: P::LOG_WIDTH..self.log_len + 1,
321			});
322		}
323
324		let log_len = log_chunk_size.min(self.log_len);
325		let packed_chunk_size = 1 << (log_chunk_size - P::LOG_WIDTH);
326		let chunks = self
327			.values
328			.par_chunks(packed_chunk_size)
329			.map(move |chunk| FieldBuffer {
330				log_len,
331				values: FieldSliceData::Slice(chunk),
332			});
333
334		Ok(chunks)
335	}
336
337	/// Splits the buffer in half and returns a pair of borrowed slices.
338	///
339	/// # Throws
340	///
341	/// * [`Error::CannotSplit`] if `self.log_len() == 0`
342	pub fn split_half(&self) -> Result<(FieldSlice<'_, P>, FieldSlice<'_, P>), Error> {
343		if self.log_len == 0 {
344			return Err(Error::CannotSplit);
345		}
346
347		let new_log_len = self.log_len - 1;
348		let (first, second) = if new_log_len < P::LOG_WIDTH {
349			// The result will be two Single variants
350			// We have exactly one packed element that needs to be split
351			let packed = self.values[0];
352			let zeros = P::default();
353
354			let (first_half, second_half) = packed.interleave(zeros, new_log_len);
355
356			let first = FieldBuffer {
357				log_len: new_log_len,
358				values: FieldSliceData::Single(first_half),
359			};
360			let second = FieldBuffer {
361				log_len: new_log_len,
362				values: FieldSliceData::Single(second_half),
363			};
364
365			(first, second)
366		} else {
367			// Split the packed values slice in half
368			let half_len = 1 << (new_log_len - P::LOG_WIDTH);
369			let (first_half, second_half) = self.values.split_at(half_len);
370			let second_half = &second_half[..half_len];
371
372			let first = FieldBuffer {
373				log_len: new_log_len,
374				values: FieldSliceData::Slice(first_half),
375			};
376			let second = FieldBuffer {
377				log_len: new_log_len,
378				values: FieldSliceData::Slice(second_half),
379			};
380
381			(first, second)
382		};
383
384		Ok((first, second))
385	}
386}
387
388impl<P: PackedField, Data: DerefMut<Target = [P]>> FieldBuffer<P, Data> {
389	/// Borrows the buffer mutably as a [`FieldSliceMut`].
390	pub fn to_mut(&mut self) -> FieldSliceMut<'_, P> {
391		FieldSliceMut::from_slice(self.log_len, self.as_mut())
392			.expect("log_len matches values.len() by struct invariant")
393	}
394
395	/// Set a field element at the given index.
396	///
397	/// # Preconditions
398	///
399	/// * the index is in the range `0..self.len()`
400	pub fn set(&mut self, index: usize, value: P::Scalar) {
401		self.set_checked(index, value)
402			.expect("precondition: index is in range");
403	}
404
405	/// Set a field element at the given index.
406	///
407	/// # Throws
408	///
409	/// * `Error::ArgumentRangeError` if the index is out of bounds.
410	pub fn set_checked(&mut self, index: usize, value: P::Scalar) -> Result<(), Error> {
411		if index >= self.len() {
412			return Err(Error::ArgumentRangeError {
413				arg: "index".to_string(),
414				range: 0..self.len(),
415			});
416		}
417
418		// Safety: bound check on index performed above. The buffer length is at least
419		// `self.len() >> P::LOG_WIDTH` by struct invariant.
420		unsafe { set_packed_slice_unchecked(&mut self.values, index, value) };
421		Ok(())
422	}
423
424	/// Truncates a field buffer to a shorter length.
425	///
426	/// If `new_log_len` is not less than current `log_len()`, this has no effect.
427	pub fn truncate(&mut self, new_log_len: usize) {
428		self.log_len = self.log_len.min(new_log_len);
429	}
430
431	/// Zero extends a field buffer to a longer length.
432	///
433	/// If `new_log_len` is not greater than current `log_len()`, this has no effect.
434	///
435	/// # Throws
436	/// * `Error::IncorrectArgumentLength` if the zero extended size exceeds underlying capacity.
437	pub fn zero_extend(&mut self, new_log_len: usize) -> Result<(), Error> {
438		if new_log_len <= self.log_len {
439			return Ok(());
440		}
441
442		if new_log_len > self.log_cap() {
443			return Err(Error::IncorrectArgumentLength {
444				arg: "new_log_len".to_string(),
445				expected: self.log_cap(),
446			});
447		}
448
449		if self.log_len < P::LOG_WIDTH {
450			let first_elem = self.values.first_mut().expect("values.len() >= 1");
451			for i in 1 << self.log_len..(1 << new_log_len).min(P::WIDTH) {
452				first_elem.set(i, P::Scalar::ZERO);
453			}
454		}
455
456		let packed_start = 1 << self.log_len.saturating_sub(P::LOG_WIDTH);
457		let packed_end = 1 << new_log_len.saturating_sub(P::LOG_WIDTH);
458		self.values[packed_start..packed_end].fill(P::zero());
459
460		self.log_len = new_log_len;
461		Ok(())
462	}
463
464	/// Sets the new log length. If the new log length is bigger than the current log length,
465	/// the new values (in case when `self.log_len < new_log_len`) will be filled with
466	/// the values from the existing buffer.
467	///
468	/// # Throws
469	///
470	/// * `Error::IncorrectArgumentLength` if the new log length exceeds the buffer's capacity.
471	pub fn resize(&mut self, new_log_len: usize) -> Result<(), Error> {
472		if new_log_len > self.log_cap() {
473			return Err(Error::IncorrectArgumentLength {
474				arg: "new_log_len".to_string(),
475				expected: self.log_cap(),
476			});
477		}
478
479		self.log_len = new_log_len;
480		Ok(())
481	}
482
483	/// Split the buffer into mutable chunks of size `2^log_chunk_size`.
484	///
485	/// # Throws
486	///
487	/// * [`Error::ArgumentRangeError`] if `log_chunk_size < P::LOG_WIDTH` or `log_chunk_size >
488	///   log_len`.
489	pub fn chunks_mut(
490		&mut self,
491		log_chunk_size: usize,
492	) -> Result<impl Iterator<Item = FieldSliceMut<'_, P>>, Error> {
493		if log_chunk_size < P::LOG_WIDTH || log_chunk_size > self.log_len {
494			return Err(Error::ArgumentRangeError {
495				arg: "log_chunk_size".to_string(),
496				range: P::LOG_WIDTH..self.log_len + 1,
497			});
498		}
499
500		let chunk_count = 1 << (self.log_len - log_chunk_size);
501		let packed_chunk_size = 1 << log_chunk_size.saturating_sub(P::LOG_WIDTH);
502		let chunks = self
503			.values
504			.chunks_mut(packed_chunk_size)
505			.take(chunk_count)
506			.map(move |chunk| FieldBuffer {
507				log_len: log_chunk_size,
508				values: FieldSliceDataMut::Slice(chunk),
509			});
510
511		Ok(chunks)
512	}
513
514	/// Splits the buffer in half and calls a closure with the two halves.
515	///
516	/// If the buffer contains a single packed element that needs to be split,
517	/// this method will create temporary copies, call the closure, and then
518	/// write the results back to the original buffer.
519	///
520	/// # Throws
521	///
522	/// * [`Error::CannotSplit`] if `self.log_len() == 0`
523	pub fn split_half_mut<F, R>(&mut self, f: F) -> Result<R, Error>
524	where
525		F: FnOnce(&mut FieldSliceMut<'_, P>, &mut FieldSliceMut<'_, P>) -> R,
526	{
527		if self.log_len == 0 {
528			return Err(Error::CannotSplit);
529		}
530
531		let new_log_len = self.log_len - 1;
532
533		if new_log_len < P::LOG_WIDTH {
534			// Extract the values using interleave
535			let packed = self.values[0];
536			let zeros = P::default();
537			let (mut first_half, mut second_half) = packed.interleave(zeros, new_log_len);
538
539			// Create temporary buffers
540			//
541			// We use Slice instead of Single variants because:
542			// 1. The closure takes ownership of the FieldBuffers
543			// 2. We need to retrieve the potentially modified values after the closure runs
544			// 3. With arrays, we maintain access to the modified values through the array
545			let mut first = FieldBuffer {
546				log_len: new_log_len,
547				values: FieldSliceDataMut::Slice(slice::from_mut(&mut first_half)),
548			};
549			let mut second = FieldBuffer {
550				log_len: new_log_len,
551				values: FieldSliceDataMut::Slice(slice::from_mut(&mut second_half)),
552			};
553
554			// Call the closure with the temporary buffers
555			let result = f(&mut first, &mut second);
556
557			// Write back the results by interleaving them back together
558			// The arrays may have been modified by the closure
559			(self.values[0], _) = first_half.interleave(second_half, new_log_len);
560
561			Ok(result)
562		} else {
563			// Normal case: split the packed values slice in half
564			let half_len = 1 << (new_log_len - P::LOG_WIDTH);
565			let (first_half, second_half) = self.values.split_at_mut(half_len);
566			let second_half = &mut second_half[..half_len];
567
568			let mut first = FieldBuffer {
569				log_len: new_log_len,
570				values: FieldSliceDataMut::Slice(first_half),
571			};
572			let mut second = FieldBuffer {
573				log_len: new_log_len,
574				values: FieldSliceDataMut::Slice(second_half),
575			};
576
577			Ok(f(&mut first, &mut second))
578		}
579	}
580
581	/// Splits the buffer in half and returns a [`FieldBufferSplitMut`] for accessing the halves.
582	///
583	/// This returns an object that can be used to access mutable references to the two halves.
584	/// This method unfortunately can't simply return a tuple of slices because the buffer may have
585	/// only one packed element. If the buffer contains a single packed element that needs to be
586	/// split, this method will create temporary copies, call the closure, and then write the
587	/// results back to the original buffer when the returned [`FieldBufferSplitMut`] is dropped.
588	///
589	/// # Throws
590	///
591	/// * [`Error::CannotSplit`] if `self.log_len() == 0`
592	pub fn split_half_mut_no_closure(&mut self) -> Result<FieldBufferSplitMut<'_, P>, Error> {
593		if self.log_len == 0 {
594			return Err(Error::CannotSplit);
595		}
596
597		let new_log_len = self.log_len - 1;
598		if new_log_len < P::LOG_WIDTH {
599			// Extract the values using interleave
600			let packed = self.values[0];
601			let zeros = P::default();
602			let (lo_half, hi_half) = packed.interleave(zeros, new_log_len);
603
604			Ok(FieldBufferSplitMut(FieldBufferSplitMutInner::Singles {
605				log_len: new_log_len,
606				lo_half,
607				hi_half,
608				parent: &mut self.values[0],
609			}))
610		} else {
611			// Normal case: split the packed values slice in half
612			let half_len = 1 << (new_log_len - P::LOG_WIDTH);
613			let (lo_half, hi_half) = self.values.split_at_mut(half_len);
614			let hi_half = &mut hi_half[..half_len];
615
616			Ok(FieldBufferSplitMut(FieldBufferSplitMutInner::Slices {
617				log_len: new_log_len,
618				lo_half,
619				hi_half,
620			}))
621		}
622	}
623}
624
625impl<P: PackedField, Data: Deref<Target = [P]>> AsRef<[P]> for FieldBuffer<P, Data> {
626	#[inline]
627	fn as_ref(&self) -> &[P] {
628		&self.values[..1 << self.log_len.saturating_sub(P::LOG_WIDTH)]
629	}
630}
631
632impl<P: PackedField, Data: DerefMut<Target = [P]>> AsMut<[P]> for FieldBuffer<P, Data> {
633	#[inline]
634	fn as_mut(&mut self) -> &mut [P] {
635		&mut self.values[..1 << self.log_len.saturating_sub(P::LOG_WIDTH)]
636	}
637}
638
639impl<F: Field, Data: Deref<Target = [F]>> Index<usize> for FieldBuffer<F, Data> {
640	type Output = F;
641
642	fn index(&self, index: usize) -> &Self::Output {
643		&self.values[index]
644	}
645}
646
647impl<F: Field, Data: DerefMut<Target = [F]>> IndexMut<usize> for FieldBuffer<F, Data> {
648	fn index_mut(&mut self, index: usize) -> &mut Self::Output {
649		&mut self.values[index]
650	}
651}
652
653/// Alias for a field buffer over a borrowed slice.
654pub type FieldSlice<'a, P> = FieldBuffer<P, FieldSliceData<'a, P>>;
655
656/// Alias for a field buffer over a mutably borrowed slice.
657pub type FieldSliceMut<'a, P> = FieldBuffer<P, FieldSliceDataMut<'a, P>>;
658
659impl<'a, P: PackedField> FieldSlice<'a, P> {
660	/// Create a new FieldSlice from a slice of packed values.
661	///
662	/// # Throws
663	///
664	/// * `IncorrectArgumentLength` if the number of field elements does not fit the `slice.len()`
665	///   exactly.
666	pub fn from_slice(log_len: usize, slice: &'a [P]) -> Result<Self, Error> {
667		FieldBuffer::new(log_len, FieldSliceData::Slice(slice))
668	}
669}
670
671impl<'a, P: PackedField, Data: Deref<Target = [P]>> From<&'a FieldBuffer<P, Data>>
672	for FieldSlice<'a, P>
673{
674	fn from(buffer: &'a FieldBuffer<P, Data>) -> Self {
675		buffer.to_ref()
676	}
677}
678
679impl<'a, P: PackedField> FieldSliceMut<'a, P> {
680	/// Create a new FieldSliceMut from a mutable slice of packed values.
681	///
682	/// # Throws
683	///
684	/// * `IncorrectArgumentLength` if the number of field elements does not fit the `slice.len()`
685	///   exactly.
686	pub fn from_slice(log_len: usize, slice: &'a mut [P]) -> Result<Self, Error> {
687		FieldBuffer::new(log_len, FieldSliceDataMut::Slice(slice))
688	}
689}
690
691impl<'a, P: PackedField, Data: DerefMut<Target = [P]>> From<&'a mut FieldBuffer<P, Data>>
692	for FieldSliceMut<'a, P>
693{
694	fn from(buffer: &'a mut FieldBuffer<P, Data>) -> Self {
695		buffer.to_mut()
696	}
697}
698
699#[derive(Debug)]
700pub enum FieldSliceData<'a, P> {
701	Single(P),
702	Slice(&'a [P]),
703}
704
705impl<'a, P> Deref for FieldSliceData<'a, P> {
706	type Target = [P];
707
708	fn deref(&self) -> &Self::Target {
709		match self {
710			FieldSliceData::Single(val) => slice::from_ref(val),
711			FieldSliceData::Slice(slice) => slice,
712		}
713	}
714}
715
716#[derive(Debug)]
717pub enum FieldSliceDataMut<'a, P> {
718	Single(P),
719	Slice(&'a mut [P]),
720}
721
722impl<'a, P> Deref for FieldSliceDataMut<'a, P> {
723	type Target = [P];
724
725	fn deref(&self) -> &Self::Target {
726		match self {
727			FieldSliceDataMut::Single(val) => slice::from_ref(val),
728			FieldSliceDataMut::Slice(slice) => slice,
729		}
730	}
731}
732
733impl<'a, P> DerefMut for FieldSliceDataMut<'a, P> {
734	fn deref_mut(&mut self) -> &mut Self::Target {
735		match self {
736			FieldSliceDataMut::Single(val) => slice::from_mut(val),
737			FieldSliceDataMut::Slice(slice) => slice,
738		}
739	}
740}
741
742/// Return type of [`FieldBuffer::split_half_mut_no_closure`].
743#[derive(Debug)]
744pub struct FieldBufferSplitMut<'a, P: PackedField>(FieldBufferSplitMutInner<'a, P>);
745
746impl<'a, P: PackedField> FieldBufferSplitMut<'a, P> {
747	pub fn halves(&mut self) -> (FieldSliceMut<'_, P>, FieldSliceMut<'_, P>) {
748		match &mut self.0 {
749			FieldBufferSplitMutInner::Singles {
750				log_len,
751				lo_half,
752				hi_half,
753				parent: _,
754			} => (
755				FieldBuffer {
756					log_len: *log_len,
757					values: FieldSliceDataMut::Slice(slice::from_mut(lo_half)),
758				},
759				FieldBuffer {
760					log_len: *log_len,
761					values: FieldSliceDataMut::Slice(slice::from_mut(hi_half)),
762				},
763			),
764			FieldBufferSplitMutInner::Slices {
765				log_len,
766				lo_half,
767				hi_half,
768			} => (
769				FieldBuffer {
770					log_len: *log_len,
771					values: FieldSliceDataMut::Slice(lo_half),
772				},
773				FieldBuffer {
774					log_len: *log_len,
775					values: FieldSliceDataMut::Slice(hi_half),
776				},
777			),
778		}
779	}
780}
781
782#[derive(Debug)]
783enum FieldBufferSplitMutInner<'a, P: PackedField> {
784	Singles {
785		log_len: usize,
786		lo_half: P,
787		hi_half: P,
788		parent: &'a mut P,
789	},
790	Slices {
791		log_len: usize,
792		lo_half: &'a mut [P],
793		hi_half: &'a mut [P],
794	},
795}
796
797impl<'a, P: PackedField> Drop for FieldBufferSplitMutInner<'a, P> {
798	fn drop(&mut self) {
799		match self {
800			Self::Singles {
801				log_len,
802				lo_half,
803				hi_half,
804				parent,
805			} => {
806				// Write back the results by interleaving them back together
807				// The arrays may have been modified by the closure
808				(**parent, _) = (*lo_half).interleave(*hi_half, *log_len);
809			}
810			Self::Slices { .. } => {}
811		}
812	}
813}
814
815#[cfg(test)]
816mod tests {
817	use super::*;
818	use crate::test_utils::{B128, Packed128b};
819
820	type P = Packed128b;
821	type F = B128;
822
823	#[test]
824	fn test_zeros() {
825		// Make a buffer with `zeros()` and check that all elements are zero.
826		// Test with log_len >= LOG_WIDTH
827		let buffer = FieldBuffer::<P>::zeros(6); // 64 elements
828		assert_eq!(buffer.log_len(), 6);
829		assert_eq!(buffer.len(), 64);
830
831		// Check all elements are zero
832		for i in 0..64 {
833			assert_eq!(buffer.get_checked(i).unwrap(), F::ZERO);
834		}
835
836		// Test with log_len < LOG_WIDTH
837		let buffer = FieldBuffer::<P>::zeros(1); // 2 elements
838		assert_eq!(buffer.log_len(), 1);
839		assert_eq!(buffer.len(), 2);
840
841		// Check all elements are zero
842		for i in 0..2 {
843			assert_eq!(buffer.get_checked(i).unwrap(), F::ZERO);
844		}
845	}
846
847	#[test]
848	fn test_from_values_below_packing_width() {
849		// Make a buffer using `from_values()`, where the number of scalars is below the packing
850		// width
851		// P::LOG_WIDTH = 2, so P::WIDTH = 4
852		let values = vec![F::new(1), F::new(2)]; // 2 elements < 4
853		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
854
855		assert_eq!(buffer.log_len(), 1); // log2(2) = 1
856		assert_eq!(buffer.len(), 2);
857
858		// Verify the values
859		assert_eq!(buffer.get_checked(0).unwrap(), F::new(1));
860		assert_eq!(buffer.get_checked(1).unwrap(), F::new(2));
861	}
862
863	#[test]
864	fn test_from_values_above_packing_width() {
865		// Make a buffer using `from_values()`, where the number of scalars is above the packing
866		// width
867		// P::LOG_WIDTH = 2, so P::WIDTH = 4
868		let values: Vec<F> = (0..16).map(F::new).collect(); // 16 elements > 4
869		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
870
871		assert_eq!(buffer.log_len(), 4); // log2(16) = 4
872		assert_eq!(buffer.len(), 16);
873
874		// Verify all values
875		for i in 0..16 {
876			assert_eq!(buffer.get_checked(i).unwrap(), F::new(i as u128));
877		}
878	}
879
880	#[test]
881	fn test_from_values_non_power_of_two() {
882		// Fail to make a buffer using `from_values()`, where the number of scalars is not a power
883		// of two
884		let values: Vec<F> = (0..7).map(F::new).collect(); // 7 is not a power of two
885		let result = FieldBuffer::<P>::from_values(&values);
886
887		assert!(matches!(result, Err(Error::PowerOfTwoLengthRequired)));
888
889		// Also test with 0 elements
890		let values: Vec<F> = vec![];
891		let result = FieldBuffer::<P>::from_values(&values);
892		assert!(matches!(result, Err(Error::PowerOfTwoLengthRequired)));
893	}
894
895	#[test]
896	fn test_new_below_packing_width() {
897		// Make a buffer using `new()`, where the number of scalars is below the packing
898		// width
899		// P::LOG_WIDTH = 2, so P::WIDTH = 4
900		// For log_len = 1 (2 elements), we need 1 packed value
901		let mut packed_values = vec![P::default()];
902		let mut buffer = FieldBuffer::new(1, packed_values.as_mut_slice()).unwrap();
903
904		assert_eq!(buffer.log_len(), 1);
905		assert_eq!(buffer.len(), 2);
906
907		// Set and verify values
908		buffer.set_checked(0, F::new(10)).unwrap();
909		buffer.set_checked(1, F::new(20)).unwrap();
910		assert_eq!(buffer.get_checked(0).unwrap(), F::new(10));
911		assert_eq!(buffer.get_checked(1).unwrap(), F::new(20));
912	}
913
914	#[test]
915	fn test_new_above_packing_width() {
916		// Make a buffer using `new()`, where the number of scalars is above the packing
917		// width
918		// P::LOG_WIDTH = 2, so P::WIDTH = 4
919		// For log_len = 4 (16 elements), we need 4 packed values
920		let mut packed_values = vec![P::default(); 4];
921		let mut buffer = FieldBuffer::new(4, packed_values.as_mut_slice()).unwrap();
922
923		assert_eq!(buffer.log_len(), 4);
924		assert_eq!(buffer.len(), 16);
925
926		// Set and verify values
927		for i in 0..16 {
928			buffer.set_checked(i, F::new(i as u128 * 10)).unwrap();
929		}
930		for i in 0..16 {
931			assert_eq!(buffer.get_checked(i).unwrap(), F::new(i as u128 * 10));
932		}
933	}
934
935	#[test]
936	fn test_new_non_power_of_two() {
937		// Fail to make a buffer using `new()`, where the number of scalars is not a power of two
938		// For log_len = 4 (16 elements), we need 4 packed values
939		// Provide wrong number of packed values
940		let packed_values = vec![P::default(); 3]; // Wrong: should be 4
941		let result = FieldBuffer::new(4, packed_values.as_slice());
942
943		assert!(matches!(result, Err(Error::IncorrectArgumentLength { .. })));
944
945		// Another test with too many packed values
946		let packed_values = vec![P::default(); 5]; // Wrong: should be 4
947		let result = FieldBuffer::new(4, packed_values.as_slice());
948
949		assert!(matches!(result, Err(Error::IncorrectArgumentLength { .. })));
950	}
951
952	#[test]
953	fn test_get_set() {
954		let mut buffer = FieldBuffer::<P>::zeros(3); // 8 elements
955
956		// Set some values
957		for i in 0..8 {
958			buffer.set_checked(i, F::new(i as u128)).unwrap();
959		}
960
961		// Get them back
962		for i in 0..8 {
963			assert_eq!(buffer.get_checked(i).unwrap(), F::new(i as u128));
964		}
965
966		// Test out of bounds
967		assert!(buffer.get_checked(8).is_err());
968		assert!(buffer.set_checked(8, F::new(0)).is_err());
969	}
970
971	#[test]
972	fn test_chunk() {
973		let log_len = 8;
974		let values: Vec<F> = (0..1 << log_len).map(F::new).collect();
975		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
976
977		// Test invalid chunk size (too large)
978		assert!(buffer.chunk(log_len + 1, 0).is_err());
979
980		for log_chunk_size in 0..=log_len {
981			let chunk_count = 1 << (log_len - log_chunk_size);
982
983			// Test invalid chunk index
984			assert!(buffer.chunk(log_chunk_size, chunk_count).is_err());
985
986			for chunk_index in 0..chunk_count {
987				let chunk = buffer.chunk(log_chunk_size, chunk_index).unwrap();
988				for i in 0..1 << log_chunk_size {
989					assert_eq!(
990						chunk.get_checked(i).unwrap(),
991						buffer
992							.get_checked(chunk_index << log_chunk_size | i)
993							.unwrap()
994					);
995				}
996			}
997		}
998	}
999
1000	#[test]
1001	fn test_chunks() {
1002		let values: Vec<F> = (0..16).map(F::new).collect();
1003		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
1004
1005		// Split into 4 chunks of size 4
1006		let chunks: Vec<_> = buffer.chunks(2).unwrap().collect();
1007		assert_eq!(chunks.len(), 4);
1008
1009		for (chunk_idx, chunk) in chunks.into_iter().enumerate() {
1010			assert_eq!(chunk.len(), 4);
1011			for i in 0..4 {
1012				let expected = F::new((chunk_idx * 4 + i) as u128);
1013				assert_eq!(chunk.get_checked(i).unwrap(), expected);
1014			}
1015		}
1016
1017		// Test invalid chunk size (too large)
1018		assert!(buffer.chunks(5).is_err());
1019
1020		// Test invalid chunk size (too small - below P::LOG_WIDTH)
1021		// P::LOG_WIDTH = 2, so chunks(0) and chunks(1) should fail
1022		assert!(buffer.chunks(0).is_err());
1023		assert!(buffer.chunks(1).is_err());
1024	}
1025
1026	#[test]
1027	fn test_chunks_par() {
1028		let values: Vec<F> = (0..16).map(F::new).collect();
1029		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
1030
1031		// Split into 4 chunks of size 4
1032		let chunks: Vec<_> = buffer.chunks_par(2).unwrap().collect();
1033		assert_eq!(chunks.len(), 4);
1034
1035		for (chunk_idx, chunk) in chunks.into_iter().enumerate() {
1036			assert_eq!(chunk.len(), 4);
1037			for i in 0..4 {
1038				let expected = F::new((chunk_idx * 4 + i) as u128);
1039				assert_eq!(chunk.get_checked(i).unwrap(), expected);
1040			}
1041		}
1042
1043		// Test invalid chunk size (too large)
1044		assert!(buffer.chunks_par(5).is_err());
1045
1046		// Test invalid chunk size (too small - below P::LOG_WIDTH)
1047		// P::LOG_WIDTH = 2, so chunks_par(0) and chunks_par(1) should fail
1048		assert!(buffer.chunks_par(0).is_err());
1049		assert!(buffer.chunks_par(1).is_err());
1050	}
1051
1052	#[test]
1053	fn test_chunks_mut() {
1054		let mut buffer = FieldBuffer::<P>::zeros(4); // 16 elements
1055
1056		// Modify via chunks
1057		let mut chunks: Vec<_> = buffer.chunks_mut(2).unwrap().collect();
1058		assert_eq!(chunks.len(), 4);
1059
1060		for (chunk_idx, chunk) in chunks.iter_mut().enumerate() {
1061			for i in 0..chunk.len() {
1062				chunk
1063					.set_checked(i, F::new((chunk_idx * 10 + i) as u128))
1064					.unwrap();
1065			}
1066		}
1067
1068		// Verify modifications
1069		for chunk_idx in 0..4 {
1070			for i in 0..4 {
1071				let expected = F::new((chunk_idx * 10 + i) as u128);
1072				assert_eq!(buffer.get_checked(chunk_idx * 4 + i).unwrap(), expected);
1073			}
1074		}
1075
1076		// Test invalid chunk size (too small - below P::LOG_WIDTH)
1077		assert!(buffer.chunks_mut(0).is_err());
1078		assert!(buffer.chunks_mut(1).is_err());
1079	}
1080
1081	#[test]
1082	fn test_to_ref_to_mut() {
1083		let mut buffer = FieldBuffer::<P>::zeros_truncated(3, 5).unwrap();
1084
1085		// Test to_ref
1086		let slice_ref = buffer.to_ref();
1087		assert_eq!(slice_ref.len(), buffer.len());
1088		assert_eq!(slice_ref.log_len(), buffer.log_len());
1089		assert_eq!(slice_ref.as_ref().len(), 1 << slice_ref.log_len().saturating_sub(P::LOG_WIDTH));
1090
1091		// Test to_mut
1092		let mut slice_mut = buffer.to_mut();
1093		slice_mut.set_checked(0, F::new(123)).unwrap();
1094		assert_eq!(slice_mut.as_mut().len(), 1 << slice_mut.log_len().saturating_sub(P::LOG_WIDTH));
1095		assert_eq!(buffer.get_checked(0).unwrap(), F::new(123));
1096	}
1097
1098	#[test]
1099	fn test_split_half() {
1100		// Test with buffer size > P::WIDTH (multiple packed elements)
1101		let values: Vec<F> = (0..16).map(F::new).collect();
1102		// Leave spare capacity for 32 elements
1103		let buffer = FieldBuffer::<P>::from_values_truncated(&values, 5).unwrap();
1104
1105		let (first, second) = buffer.split_half().unwrap();
1106		assert_eq!(first.len(), 8);
1107		assert_eq!(second.len(), 8);
1108
1109		// Verify values
1110		for i in 0..8 {
1111			assert_eq!(first.get_checked(i).unwrap(), F::new(i as u128));
1112			assert_eq!(second.get_checked(i).unwrap(), F::new((i + 8) as u128));
1113		}
1114
1115		// Test with buffer size = P::WIDTH (single packed element)
1116		// P::LOG_WIDTH = 2, so P::WIDTH = 4
1117		// Note that underlying collection has two packed fields.
1118		let values: Vec<F> = (0..4).map(F::new).collect();
1119		let buffer = FieldBuffer::<P>::from_values_truncated(&values, 3).unwrap();
1120
1121		let (first, second) = buffer.split_half().unwrap();
1122		assert_eq!(first.len(), 2);
1123		assert_eq!(second.len(), 2);
1124
1125		// Verify we got Single variants
1126		match &first.values {
1127			FieldSliceData::Single(_) => {}
1128			_ => panic!("Expected Single variant for first half"),
1129		}
1130		match &second.values {
1131			FieldSliceData::Single(_) => {}
1132			_ => panic!("Expected Single variant for second half"),
1133		}
1134
1135		// Verify values
1136		assert_eq!(first.get_checked(0).unwrap(), F::new(0));
1137		assert_eq!(first.get_checked(1).unwrap(), F::new(1));
1138		assert_eq!(second.get_checked(0).unwrap(), F::new(2));
1139		assert_eq!(second.get_checked(1).unwrap(), F::new(3));
1140
1141		// Test with buffer size = 2 (less than P::WIDTH)
1142		let values: Vec<F> = vec![F::new(10), F::new(20)];
1143		let buffer = FieldBuffer::<P>::from_values_truncated(&values, 3).unwrap();
1144
1145		let (first, second) = buffer.split_half().unwrap();
1146		assert_eq!(first.len(), 1);
1147		assert_eq!(second.len(), 1);
1148
1149		// Verify we got Single variants
1150		match &first.values {
1151			FieldSliceData::Single(_) => {}
1152			_ => panic!("Expected Single variant for first half"),
1153		}
1154		match &second.values {
1155			FieldSliceData::Single(_) => {}
1156			_ => panic!("Expected Single variant for second half"),
1157		}
1158
1159		assert_eq!(first.get_checked(0).unwrap(), F::new(10));
1160		assert_eq!(second.get_checked(0).unwrap(), F::new(20));
1161
1162		// Test error case: buffer of size 1
1163		let values = vec![F::new(42)];
1164		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
1165
1166		let result = buffer.split_half();
1167		assert!(matches!(result, Err(Error::CannotSplit)));
1168	}
1169
1170	#[test]
1171	fn test_split_half_mut() {
1172		// Test with buffer size > P::WIDTH (multiple packed elements)
1173		let mut buffer = FieldBuffer::<P>::zeros_truncated(4, 5).unwrap(); // 16 elements, 32 element capacity
1174
1175		// Fill with test data
1176		for i in 0..16 {
1177			buffer.set_checked(i, F::new(i as u128)).unwrap();
1178		}
1179
1180		buffer
1181			.split_half_mut(|first, second| {
1182				assert_eq!(first.len(), 8);
1183				assert_eq!(second.len(), 8);
1184
1185				// Modify through the split halves
1186				for i in 0..8 {
1187					first.set_checked(i, F::new((i * 10) as u128)).unwrap();
1188					second.set_checked(i, F::new((i * 20) as u128)).unwrap();
1189				}
1190			})
1191			.unwrap();
1192
1193		// Verify changes were made to original buffer
1194		for i in 0..8 {
1195			assert_eq!(buffer.get_checked(i).unwrap(), F::new((i * 10) as u128));
1196			assert_eq!(buffer.get_checked(i + 8).unwrap(), F::new((i * 20) as u128));
1197		}
1198
1199		// Test with buffer size = P::WIDTH (single packed element)
1200		// P::LOG_WIDTH = 2, so a buffer with log_len = 2 (4 elements) can now be split
1201		let mut buffer = FieldBuffer::<P>::zeros_truncated(2, 4).unwrap(); // 4 elements, 16 element capacity
1202
1203		// Fill with test data
1204		for i in 0..4 {
1205			buffer.set_checked(i, F::new(i as u128)).unwrap();
1206		}
1207
1208		buffer
1209			.split_half_mut(|first, second| {
1210				assert_eq!(first.len(), 2);
1211				assert_eq!(second.len(), 2);
1212
1213				// Modify values
1214				first.set_checked(0, F::new(100)).unwrap();
1215				first.set_checked(1, F::new(101)).unwrap();
1216				second.set_checked(0, F::new(200)).unwrap();
1217				second.set_checked(1, F::new(201)).unwrap();
1218			})
1219			.unwrap();
1220
1221		// Verify changes were written back
1222		assert_eq!(buffer.get_checked(0).unwrap(), F::new(100));
1223		assert_eq!(buffer.get_checked(1).unwrap(), F::new(101));
1224		assert_eq!(buffer.get_checked(2).unwrap(), F::new(200));
1225		assert_eq!(buffer.get_checked(3).unwrap(), F::new(201));
1226
1227		// Test with buffer size = 2
1228		let mut buffer = FieldBuffer::<P>::zeros_truncated(1, 4).unwrap(); // 2 elements, 16 element capacity
1229
1230		buffer.set_checked(0, F::new(10)).unwrap();
1231		buffer.set_checked(1, F::new(20)).unwrap();
1232
1233		buffer
1234			.split_half_mut(|first, second| {
1235				assert_eq!(first.len(), 1);
1236				assert_eq!(second.len(), 1);
1237
1238				// Modify values
1239				first.set_checked(0, F::new(30)).unwrap();
1240				second.set_checked(0, F::new(40)).unwrap();
1241			})
1242			.unwrap();
1243
1244		// Verify changes
1245		assert_eq!(buffer.get_checked(0).unwrap(), F::new(30));
1246		assert_eq!(buffer.get_checked(1).unwrap(), F::new(40));
1247
1248		// Test error case: buffer of size 1
1249		let mut buffer = FieldBuffer::<P>::zeros(0); // 1 element
1250
1251		let result = buffer.split_half_mut(|_, _| {});
1252		assert!(matches!(result, Err(Error::CannotSplit)));
1253	}
1254
1255	#[test]
1256	fn test_zero_extend() {
1257		let log_len = 10;
1258		let nonzero_scalars = (0..1 << log_len).map(|i| F::new(i + 1)).collect::<Vec<_>>();
1259		let mut buffer = FieldBuffer::<P>::from_values(&nonzero_scalars).unwrap();
1260		buffer.truncate(0);
1261
1262		for i in 0..log_len {
1263			buffer.zero_extend(i + 1).unwrap();
1264
1265			for j in 1 << i..1 << (i + 1) {
1266				assert!(buffer.get_checked(j).unwrap().is_zero());
1267			}
1268		}
1269	}
1270
1271	#[test]
1272	fn test_resize() {
1273		let mut buffer = FieldBuffer::<P>::zeros(4); // 16 elements
1274
1275		// Fill with test data
1276		for i in 0..16 {
1277			buffer.set_checked(i, F::new(i as u128)).unwrap();
1278		}
1279
1280		buffer.resize(3).unwrap();
1281		assert_eq!(buffer.log_len(), 3);
1282		assert_eq!(buffer.get_checked(7).unwrap(), F::new(7));
1283
1284		buffer.resize(4).unwrap();
1285		assert_eq!(buffer.log_len(), 4);
1286		assert_eq!(buffer.get_checked(15).unwrap(), F::new(15));
1287
1288		assert!(
1289			matches!(buffer.resize(5), Err(Error::IncorrectArgumentLength { arg, expected }) if arg == "new_log_len" && expected == 4)
1290		);
1291
1292		buffer.resize(2).unwrap();
1293		assert_eq!(buffer.log_len(), 2);
1294	}
1295
1296	#[test]
1297	fn test_iter_scalars() {
1298		// Test with buffer size below packing width
1299		// P::LOG_WIDTH = 2, so P::WIDTH = 4
1300		let values = vec![F::new(10), F::new(20)]; // 2 elements < 4
1301		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
1302
1303		let collected: Vec<F> = buffer.iter_scalars().collect();
1304		assert_eq!(collected, values);
1305
1306		// Verify it matches individual get calls
1307		for (i, &val) in collected.iter().enumerate() {
1308			assert_eq!(val, buffer.get(i));
1309		}
1310
1311		// Test with buffer size equal to packing width
1312		let values = vec![F::new(1), F::new(2), F::new(3), F::new(4)]; // 4 elements = P::WIDTH
1313		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
1314
1315		let collected: Vec<F> = buffer.iter_scalars().collect();
1316		assert_eq!(collected, values);
1317
1318		// Test with buffer size above packing width
1319		let values: Vec<F> = (0..16).map(F::new).collect(); // 16 elements > 4
1320		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
1321
1322		let collected: Vec<F> = buffer.iter_scalars().collect();
1323		assert_eq!(collected, values);
1324
1325		// Verify it matches individual get calls
1326		for (i, &val) in collected.iter().enumerate() {
1327			assert_eq!(val, buffer.get(i));
1328		}
1329
1330		// Test with single element buffer
1331		let values = vec![F::new(42)];
1332		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
1333
1334		let collected: Vec<F> = buffer.iter_scalars().collect();
1335		assert_eq!(collected, values);
1336
1337		// Test with large buffer
1338		let values: Vec<F> = (0..256).map(F::new).collect();
1339		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
1340
1341		let collected: Vec<F> = buffer.iter_scalars().collect();
1342		assert_eq!(collected, values);
1343
1344		// Test that iterator is cloneable and can be used multiple times
1345		let values: Vec<F> = (0..8).map(F::new).collect();
1346		let buffer = FieldBuffer::<P>::from_values(&values).unwrap();
1347
1348		let iter1 = buffer.iter_scalars();
1349		let iter2 = iter1.clone();
1350
1351		let collected1: Vec<F> = iter1.collect();
1352		let collected2: Vec<F> = iter2.collect();
1353		assert_eq!(collected1, collected2);
1354		assert_eq!(collected1, values);
1355
1356		// Test with buffer that has extra capacity
1357		let values: Vec<F> = (0..8).map(F::new).collect();
1358		let buffer = FieldBuffer::<P>::from_values_truncated(&values, 5).unwrap(); // 8 elements, capacity for 32
1359
1360		let collected: Vec<F> = buffer.iter_scalars().collect();
1361		assert_eq!(collected, values);
1362		assert_eq!(collected.len(), 8); // Should only iterate over actual elements, not capacity
1363	}
1364
1365	#[test]
1366	fn test_split_half_mut_no_closure() {
1367		// Test with buffer size > P::WIDTH (multiple packed elements)
1368		let mut buffer = FieldBuffer::<P>::zeros(4); // 16 elements
1369
1370		// Fill with test data
1371		for i in 0..16 {
1372			buffer.set_checked(i, F::new(i as u128)).unwrap();
1373		}
1374
1375		{
1376			let mut split = buffer.split_half_mut_no_closure().unwrap();
1377			let (mut first, mut second) = split.halves();
1378
1379			assert_eq!(first.len(), 8);
1380			assert_eq!(second.len(), 8);
1381
1382			// Modify through the split halves
1383			for i in 0..8 {
1384				first.set_checked(i, F::new((i * 10) as u128)).unwrap();
1385				second.set_checked(i, F::new((i * 20) as u128)).unwrap();
1386			}
1387			// split drops here and writes back the changes
1388		}
1389
1390		// Verify changes were made to original buffer
1391		for i in 0..8 {
1392			assert_eq!(buffer.get_checked(i).unwrap(), F::new((i * 10) as u128));
1393			assert_eq!(buffer.get_checked(i + 8).unwrap(), F::new((i * 20) as u128));
1394		}
1395
1396		// Test with buffer size = P::WIDTH (single packed element)
1397		// P::LOG_WIDTH = 2, so a buffer with log_len = 2 (4 elements) can now be split
1398		let mut buffer = FieldBuffer::<P>::zeros(2); // 4 elements
1399
1400		// Fill with test data
1401		for i in 0..4 {
1402			buffer.set_checked(i, F::new(i as u128)).unwrap();
1403		}
1404
1405		{
1406			let mut split = buffer.split_half_mut_no_closure().unwrap();
1407			let (mut first, mut second) = split.halves();
1408
1409			assert_eq!(first.len(), 2);
1410			assert_eq!(second.len(), 2);
1411
1412			// Modify values
1413			first.set_checked(0, F::new(100)).unwrap();
1414			first.set_checked(1, F::new(101)).unwrap();
1415			second.set_checked(0, F::new(200)).unwrap();
1416			second.set_checked(1, F::new(201)).unwrap();
1417			// split drops here and writes back the changes using interleave
1418		}
1419
1420		// Verify changes were written back
1421		assert_eq!(buffer.get_checked(0).unwrap(), F::new(100));
1422		assert_eq!(buffer.get_checked(1).unwrap(), F::new(101));
1423		assert_eq!(buffer.get_checked(2).unwrap(), F::new(200));
1424		assert_eq!(buffer.get_checked(3).unwrap(), F::new(201));
1425
1426		// Test with buffer size = 2
1427		let mut buffer = FieldBuffer::<P>::zeros(1); // 2 elements
1428
1429		buffer.set_checked(0, F::new(10)).unwrap();
1430		buffer.set_checked(1, F::new(20)).unwrap();
1431
1432		{
1433			let mut split = buffer.split_half_mut_no_closure().unwrap();
1434			let (mut first, mut second) = split.halves();
1435
1436			assert_eq!(first.len(), 1);
1437			assert_eq!(second.len(), 1);
1438
1439			// Modify values
1440			first.set_checked(0, F::new(30)).unwrap();
1441			second.set_checked(0, F::new(40)).unwrap();
1442			// split drops here and writes back the changes using interleave
1443		}
1444
1445		// Verify changes
1446		assert_eq!(buffer.get_checked(0).unwrap(), F::new(30));
1447		assert_eq!(buffer.get_checked(1).unwrap(), F::new(40));
1448
1449		// Test error case: buffer of size 1
1450		let mut buffer = FieldBuffer::<P>::zeros(0); // 1 element
1451
1452		let result = buffer.split_half_mut_no_closure();
1453		assert!(matches!(result, Err(Error::CannotSplit)));
1454	}
1455}