1use std::{
34 mem::MaybeUninit,
35 ops::{Deref, DerefMut},
36 slice,
37};
38
39use binius_compute::{Allocator, BufferData, VecLike};
40use binius_field::{
41 Field, PackedField,
42 packed::{get_packed_slice_unchecked, set_packed_slice_unchecked},
43};
44use binius_utils::{
45 checked_arithmetics::strict_log_2,
46 rayon::{
47 prelude::*,
48 task_size::{IndexedParallelIteratorExt, task_chunk_len},
49 },
50};
51use bytemuck::zeroed_vec;
52
53mod chunks;
54mod view;
55
56pub use chunks::{ChunkMut, Chunks, ChunksMut};
57pub use view::{FieldSlice, FieldSliceData, FieldSliceMut, FieldVec};
58
59#[allow(clippy::multiple_inherent_impl)]
85#[derive(Debug, Clone, Eq)]
86pub struct FieldBuffer<P: PackedField, Data: Deref<Target = [P]> = Vec<P>> {
87 log_len: usize,
89 words: Data,
91}
92
93impl<P: PackedField, Data: Deref<Target = [P]> + Copy> Copy for FieldBuffer<P, Data> {}
94
95impl<P: PackedField, Data: Deref<Target = [P]>> PartialEq for FieldBuffer<P, Data> {
96 fn eq(&self, other: &Self) -> bool {
97 if self.log_len != other.log_len {
105 return false;
106 }
107 if self.log_len < P::LOG_WIDTH {
108 let iter_1 = self
109 .words
110 .first()
111 .expect("len >= 1")
112 .iter()
113 .take(1 << self.log_len);
114 let iter_2 = other
115 .words
116 .first()
117 .expect("len >= 1")
118 .iter()
119 .take(1 << self.log_len);
120 iter_1.eq(iter_2)
121 } else {
122 let prefix = 1 << (self.log_len - P::LOG_WIDTH);
123 self.words[..prefix] == other.words[..prefix]
124 }
125 }
126}
127
128impl<P: PackedField> FieldBuffer<P> {
129 #[track_caller]
135 pub fn from_values(values: &[P::Scalar]) -> Self {
136 let log_len =
137 strict_log_2(values.len()).expect("precondition: values.len() must be a power of two");
138
139 let packed_len = 1 << log_len.saturating_sub(P::LOG_WIDTH);
140 let mut words = Vec::with_capacity(packed_len);
141 words.extend(
142 values
143 .chunks(P::WIDTH)
144 .map(|chunk| P::from_scalars(chunk.iter().copied())),
145 );
146
147 Self { log_len, words }
148 }
149
150 pub fn zeros(log_len: usize) -> Self {
152 let packed_len = 1 << log_len.saturating_sub(P::LOG_WIDTH);
153 let words = zeroed_vec(packed_len);
154 Self { log_len, words }
155 }
156
157 pub fn scalar_with_capacity(value: P::Scalar, log_capacity: usize) -> Self {
162 let mut words = Vec::with_capacity(1 << log_capacity.saturating_sub(P::LOG_WIDTH));
163 words.push(P::from_scalars([value]));
164 Self { log_len: 0, words }
165 }
166}
167
168impl<P: PackedField, Data: VecLike<P>> FieldBuffer<P, Data> {
169 pub fn zeros_in<A>(alloc: &A, log_len: usize) -> Self
174 where
175 A: Allocator<Vec<P> = Data>,
176 {
177 let packed_len = 1 << log_len.saturating_sub(P::LOG_WIDTH);
178 let mut words = alloc.alloc::<P>(packed_len);
180 words.resize(packed_len, P::default());
181 FieldBuffer::new(log_len, words)
182 }
183
184 pub fn from_view_in<A>(alloc: &A, src: FieldSlice<'_, P>) -> Self
189 where
190 A: Allocator<Vec<P> = Data>,
191 {
192 Self::from_view_with_capacity_in(alloc, src, src.log_len())
193 }
194
195 #[track_caller]
208 pub fn from_view_with_capacity_in<A>(
209 alloc: &A,
210 src: FieldSlice<'_, P>,
211 log_capacity: usize,
212 ) -> Self
213 where
214 A: Allocator<Vec<P> = Data>,
215 {
216 assert!(
217 log_capacity >= src.log_len(),
218 "precondition: log_capacity must be at least src.log_len()"
219 );
220
221 let mut words = alloc.alloc::<P>(1 << log_capacity.saturating_sub(P::LOG_WIDTH));
222
223 let source = src.as_ref();
225 let head = &mut words.spare_capacity_mut()[..source.len()];
226
227 (head.par_iter_mut(), source.par_iter())
229 .into_par_iter()
230 .with_min_task_bytes::<P>()
231 .for_each(|(dst, src)| {
232 dst.write(*src);
233 });
234
235 unsafe { words.set_len(source.len()) };
237
238 FieldBuffer::new(src.log_len(), words)
239 }
240
241 #[track_caller]
257 pub fn repeat_extend(&mut self, log_len: usize) {
258 assert!(
259 log_len >= self.log_len,
260 "precondition: log_len must be at least the buffer's own log_len"
261 );
262 if log_len == self.log_len {
263 return;
264 }
265
266 let total = 1 << log_len.saturating_sub(P::LOG_WIDTH);
267 assert!(
268 total <= self.words.capacity(),
269 "precondition: the store must have room reserved for 2^log_len elements"
270 );
271
272 if self.log_len < P::LOG_WIDTH {
273 let word = P::from_scalars(self.iter_scalars().cycle());
275 self.words.clear();
276 self.words.resize(total, word);
277 } else {
278 let prefix = self.words.len();
279
280 let run = prefix.min(task_chunk_len::<P>().next_power_of_two());
283
284 unsafe { self.words.set_len(0) };
289 let store = &mut self.words.spare_capacity_mut()[..total];
290 let (head, tail) = store.split_at_mut(prefix);
291
292 let head = unsafe { &*(head as *const [MaybeUninit<P>] as *const [P]) };
295
296 repeat_words(head, tail, run);
297
298 unsafe { self.words.set_len(total) };
300 }
301
302 self.log_len = log_len;
303 }
304
305 #[track_caller]
315 pub fn from_values_in<A>(alloc: &A, values: &[P::Scalar]) -> Self
316 where
317 A: Allocator<Vec<P> = Data>,
318 {
319 let log_len =
320 strict_log_2(values.len()).expect("precondition: values.len() must be a power of two");
321
322 let packed_len = 1 << log_len.saturating_sub(P::LOG_WIDTH);
323 let mut words = alloc.alloc::<P>(packed_len);
324 words.extend(
325 values
326 .chunks(P::WIDTH)
327 .map(|chunk| P::from_scalars(chunk.iter().copied())),
328 );
329
330 FieldBuffer::new(log_len, words)
331 }
332
333 #[track_caller]
347 pub fn zero_extend_in<A>(self, alloc: &A, log_len: usize) -> Self
348 where
349 A: Allocator<Vec<P> = Data>,
350 {
351 assert!(
352 log_len >= self.log_len,
353 "precondition: log_len must be at least the buffer's own log_len"
354 );
355 if log_len == self.log_len {
357 return self;
358 }
359
360 let mut extended = Self::zeros_in(alloc, log_len);
362
363 if self.log_len < P::LOG_WIDTH {
364 extended.as_mut()[0] = P::from_scalars(self.iter_scalars());
370 } else {
371 extended.as_mut()[..self.as_ref().len()].copy_from_slice(self.as_ref());
373 }
374
375 extended
376 }
377}
378
379#[allow(clippy::len_without_is_empty)]
380impl<P: PackedField, Data: Deref<Target = [P]>> FieldBuffer<P, Data> {
381 #[track_caller]
387 pub fn new(log_len: usize, words: Data) -> Self {
388 let expected_packed_len = 1 << log_len.saturating_sub(P::LOG_WIDTH);
389 assert!(
390 words.len() == expected_packed_len,
391 "precondition: words.len() must equal expected packed length"
392 );
393
394 Self { log_len, words }
395 }
396
397 pub fn into_inner(self) -> Data {
399 self.words
400 }
401
402 pub const fn log_len(&self) -> usize {
404 self.log_len
405 }
406
407 pub const fn len(&self) -> usize {
409 1 << self.log_len
410 }
411
412 pub fn as_view(&self) -> FieldSlice<'_, P> {
414 FieldSlice::from_slice(self.log_len, self.as_ref())
415 }
416
417 #[track_caller]
423 pub fn get(&self, index: usize) -> P::Scalar {
424 assert!(
425 index < self.len(),
426 "precondition: index {index} must be less than len {}",
427 self.len()
428 );
429
430 unsafe { get_packed_slice_unchecked(&self.words, index) }
433 }
434
435 pub fn iter_scalars(&self) -> impl Iterator<Item = P::Scalar> + Send + Clone + '_ {
437 P::iter_slice(self.as_ref()).take(self.len())
438 }
439
440 #[inline]
445 pub fn iter_packed(&self) -> slice::Iter<'_, P> {
446 self.as_ref().iter()
447 }
448
449 #[track_caller]
455 pub fn split_half(&self) -> (FieldSlice<'_, P>, FieldSlice<'_, P>) {
456 assert!(self.log_len > 0, "precondition: cannot split a buffer of length 1");
457
458 let new_log_len = self.log_len - 1;
459 if new_log_len < P::LOG_WIDTH {
460 let packed = self.words[0];
463 let zeros = P::default();
464
465 let (first_half, second_half) = packed.interleave(zeros, new_log_len);
466
467 let first = FieldBuffer {
468 log_len: new_log_len,
469 words: FieldSliceData::Single(first_half),
470 };
471 let second = FieldBuffer {
472 log_len: new_log_len,
473 words: FieldSliceData::Single(second_half),
474 };
475
476 (first, second)
477 } else {
478 let half_len = 1 << (new_log_len - P::LOG_WIDTH);
480 let (first_half, second_half) = self.words.split_at(half_len);
481 let second_half = &second_half[..half_len];
482
483 let first = FieldBuffer {
484 log_len: new_log_len,
485 words: FieldSliceData::Slice(first_half),
486 };
487 let second = FieldBuffer {
488 log_len: new_log_len,
489 words: FieldSliceData::Slice(second_half),
490 };
491
492 (first, second)
493 }
494 }
495}
496
497impl<P: PackedField, Data: DerefMut<Target = [P]>> FieldBuffer<P, Data> {
498 pub fn as_mut_view(&mut self) -> FieldSliceMut<'_, P> {
500 FieldSliceMut::from_slice(self.log_len, self.as_mut())
501 }
502
503 #[track_caller]
509 pub fn set(&mut self, index: usize, value: P::Scalar) {
510 assert!(
511 index < self.len(),
512 "precondition: index {index} must be less than len {}",
513 self.len()
514 );
515
516 unsafe { set_packed_slice_unchecked(&mut self.words, index, value) };
519 }
520
521 #[inline]
526 pub fn iter_packed_mut(&mut self) -> slice::IterMut<'_, P> {
527 self.as_mut().iter_mut()
528 }
529
530 #[track_caller]
541 pub fn into_split_half(self) -> SplitMut<P, Data> {
542 assert!(self.log_len > 0, "precondition: cannot split a buffer of length 1");
543
544 SplitMut::new(self.log_len - 1, self.words)
547 }
548
549 #[track_caller]
557 pub fn split_half_mut(&mut self) -> SplitMut<P, &'_ mut [P]> {
558 self.as_mut_view().into_split_half()
559 }
560}
561
562impl<P: PackedField, Data: BufferData<P>> FieldBuffer<P, Data> {
563 pub fn truncate(&mut self, new_log_len: usize) {
570 if new_log_len >= self.log_len {
571 return;
572 }
573 self.log_len = new_log_len;
574
575 if new_log_len < P::LOG_WIDTH {
578 for i in 1 << new_log_len..P::WIDTH {
579 self.words[0].set(i, <P::Scalar as Field>::ZERO);
580 }
581 }
582
583 self.words
584 .truncate(1 << new_log_len.saturating_sub(P::LOG_WIDTH));
585 }
586}
587
588impl<P: PackedField, Data: Deref<Target = [P]>> AsRef<[P]> for FieldBuffer<P, Data> {
589 #[inline]
590 fn as_ref(&self) -> &[P] {
591 &self.words[..1 << self.log_len.saturating_sub(P::LOG_WIDTH)]
592 }
593}
594
595impl<P: PackedField, Data: DerefMut<Target = [P]>> AsMut<[P]> for FieldBuffer<P, Data> {
596 #[inline]
597 fn as_mut(&mut self) -> &mut [P] {
598 &mut self.words[..1 << self.log_len.saturating_sub(P::LOG_WIDTH)]
599 }
600}
601
602impl<P: PackedField> FromIterator<P::Scalar> for FieldBuffer<P> {
603 #[track_caller]
611 fn from_iter<I: IntoIterator<Item = P::Scalar>>(iter: I) -> Self {
612 let mut iter = iter.into_iter();
613 let mut words = Vec::with_capacity(iter.size_hint().0.div_ceil(P::WIDTH));
615
616 let mut len = 0usize;
618 loop {
619 let mut filled = 0usize;
623 let word = P::from_scalars(iter.by_ref().take(P::WIDTH).inspect(|_| filled += 1));
624
625 if filled == 0 {
627 break;
628 }
629 words.push(word);
630 len += filled;
631
632 if filled < P::WIDTH {
635 break;
636 }
637 }
638
639 let log_len =
640 strict_log_2(len).expect("precondition: element count must be a power of two");
641
642 Self { log_len, words }
643 }
644}
645
646fn repeat_words<P: PackedField>(head: &[P], tail: &mut [MaybeUninit<P>], run: usize) {
661 debug_assert!(head.len().is_power_of_two());
662 debug_assert!(run.is_power_of_two() && run <= head.len());
663 debug_assert_eq!(tail.len() % head.len(), 0);
664
665 tail.par_chunks_mut(run).enumerate().for_each(|(i, dst)| {
666 let source = (i * run) & (head.len() - 1);
669 dst.write_copy_of_slice(&head[source..source + dst.len()]);
670 });
671}
672
673#[derive(Debug)]
677pub struct SplitMut<P: PackedField, Data: DerefMut<Target = [P]>> {
678 log_len: usize,
680 singles: Option<[P; 2]>,
682 data: Data,
684}
685
686impl<P: PackedField, Data: DerefMut<Target = [P]>> SplitMut<P, Data> {
687 fn new(log_len: usize, data: Data) -> Self {
689 let singles = (log_len < P::LOG_WIDTH).then(|| {
692 let (lo_half, hi_half) = data[0].interleave(P::default(), log_len);
693 [lo_half, hi_half]
694 });
695
696 Self {
697 log_len,
698 singles,
699 data,
700 }
701 }
702
703 pub fn halves(&mut self) -> (FieldSliceMut<'_, P>, FieldSliceMut<'_, P>) {
708 match &mut self.singles {
709 Some([lo_half, hi_half]) => (
710 FieldBuffer {
711 log_len: self.log_len,
712 words: slice::from_mut(lo_half),
713 },
714 FieldBuffer {
715 log_len: self.log_len,
716 words: slice::from_mut(hi_half),
717 },
718 ),
719 None => {
720 let half_len = 1 << (self.log_len - P::LOG_WIDTH);
721 let (lo_half, hi_half) = self.data.split_at_mut(half_len);
722 (
723 FieldBuffer {
724 log_len: self.log_len,
725 words: lo_half,
726 },
727 FieldBuffer {
728 log_len: self.log_len,
729 words: hi_half,
730 },
731 )
732 }
733 }
734 }
735}
736
737impl<P: PackedField, Data: DerefMut<Target = [P]>> Drop for SplitMut<P, Data> {
738 fn drop(&mut self) {
739 if let Some([lo_half, hi_half]) = self.singles {
741 (self.data[0], _) = lo_half.interleave(hi_half, self.log_len);
742 }
743 }
744}
745
746#[cfg(test)]
747mod tests {
748 use binius_compute::{BufferPool, GlobalAllocator};
749 use binius_field::packed::get_packed_slice;
750 use binius_utils::rayon::task_size::min_len_for_bytes;
751 use proptest::prelude::*;
752 use rand::{SeedableRng, rngs::StdRng};
753
754 use super::*;
755 use crate::test_utils::{B128, Packed128b, random_field_buffer};
756
757 type P = Packed128b;
758 type F = B128;
759
760 fn check_alloc_constructors<A: Allocator>(alloc: &A) {
764 let scalars: Vec<F> = (0..16).map(F::new).collect();
769 let src = FieldBuffer::<P>::from_values(&scalars);
770
771 let cloned: FieldVec<P, A> = FieldBuffer::from_view_in(alloc, src.as_view());
773 assert_eq!(cloned.log_len(), 4);
774 assert_eq!(cloned.as_view(), src.as_view());
775
776 let small = FieldBuffer::<P>::new(
787 1,
788 vec![P::from_scalars([
789 scalars[0],
790 scalars[1],
791 F::new(0xdead),
792 F::new(0xbeef),
793 ])],
794 );
795 let cloned_small: FieldVec<P, A> = FieldBuffer::from_view_in(alloc, small.as_view());
796 assert_eq!(cloned_small.log_len(), 1);
797 assert_eq!(cloned_small.as_view(), small.as_view());
798
799 let mut zeros: FieldVec<P, A> = FieldBuffer::zeros_in(alloc, 5);
801 assert_eq!(zeros.log_len(), 5);
802 assert!(zeros.iter_scalars().all(|scalar| scalar == F::ZERO));
803
804 zeros.set(31, F::new(7));
806 assert_eq!(zeros.get(31), F::new(7));
807
808 let zeros_small: FieldVec<P, A> = FieldBuffer::zeros_in(alloc, 1);
810 assert_eq!(zeros_small.as_ref().len(), 1);
811 assert!(zeros_small.iter_scalars().all(|scalar| scalar == F::ZERO));
812
813 let src_vec: FieldVec<P, A> = FieldBuffer::from_view_in(alloc, src.as_view());
821 let extended = src_vec.zero_extend_in(alloc, 5);
822 assert_eq!(extended.log_len(), 5);
823 for i in 0..16 {
824 assert_eq!(extended.get(i), F::new(i as u128));
825 }
826 assert!((16..32).all(|i| extended.get(i) == F::ZERO));
827
828 let same: FieldVec<P, A> = FieldBuffer::from_view_in(alloc, src.as_view());
830 let same = same.zero_extend_in(alloc, 4);
831 assert_eq!(same.log_len(), 4);
832 assert_eq!(same.as_view(), src.as_view());
833
834 let small_vec: FieldVec<P, A> = FieldBuffer::from_view_in(alloc, small.as_view());
841 let widened = small_vec.zero_extend_in(alloc, 3);
842 assert_eq!(widened.log_len(), 3);
843 assert_eq!(widened.get(0), F::new(0));
844 assert_eq!(widened.get(1), F::new(1));
845 assert!((2..8).all(|i| widened.get(i) == F::ZERO));
846
847 let reserved: FieldVec<P, A> =
849 FieldBuffer::from_view_with_capacity_in(alloc, src.as_view(), 6);
850 assert_eq!(reserved.log_len(), 4);
851 assert_eq!(reserved.as_view(), src.as_view());
852
853 let mut repeated = reserved;
855 repeated.repeat_extend(6);
856 assert_eq!(repeated.log_len(), 6);
857 assert!((0..64).all(|i| repeated.get(i) == F::new((i % 16) as u128)));
858
859 let mut cycled: FieldVec<P, A> =
864 FieldBuffer::from_view_with_capacity_in(alloc, small.as_view(), 3);
865 cycled.repeat_extend(3);
866 assert_eq!(cycled.log_len(), 3);
867 assert!((0..8).all(|i| cycled.get(i) == F::new((i % 2) as u128)));
868 }
869
870 fn check_repeat_words(log_head: usize, log_copies: usize) {
872 let head: Vec<P> = (0..1 << log_head)
873 .map(|i| P::broadcast(F::new(i)))
874 .collect();
875
876 for log_run in 0..=log_head {
879 let mut tail = vec![MaybeUninit::uninit(); head.len() * ((1 << log_copies) - 1)];
880 repeat_words(&head, &mut tail, 1 << log_run);
881
882 for (i, word) in tail.iter().enumerate() {
883 let word = unsafe { word.assume_init() };
885 assert_eq!(word, head[i % head.len()], "log_run={log_run} i={i}");
886 }
887 }
888 }
889
890 #[test]
891 fn repeat_words_tiles_the_head_at_every_run_width() {
892 for log_head in 0..5 {
894 for log_copies in 0..4 {
895 check_repeat_words(log_head, log_copies);
896 }
897 }
898 }
899
900 fn check_repeat_extend(log_src: usize, log_dst: usize) {
902 let mut rng = StdRng::seed_from_u64(0);
903 let src = random_field_buffer::<P>(&mut rng, log_src);
904
905 let mut buffer: FieldVec<P, GlobalAllocator> =
906 FieldBuffer::from_view_with_capacity_in(&GlobalAllocator, src.as_view(), log_dst);
907 buffer.repeat_extend(log_dst);
908
909 assert_eq!(buffer.log_len(), log_dst);
910 for i in 0..1 << log_dst {
911 let expected = src.get(i % (1 << log_src));
912 assert_eq!(buffer.get(i), expected, "log_src={log_src} log_dst={log_dst} i={i}");
913 }
914 }
915
916 #[test]
917 fn repeat_extend_repeats_the_live_scalars() {
918 for log_src in 0..5 {
921 for log_dst in log_src..7 {
922 check_repeat_extend(log_src, log_dst);
923 }
924 }
925 }
926
927 #[test]
928 #[should_panic(expected = "precondition: log_len must be at least the buffer's own log_len")]
929 fn repeat_extend_rejects_shrinking() {
930 let mut buffer: FieldVec<P, GlobalAllocator> = FieldBuffer::from_view_with_capacity_in(
931 &GlobalAllocator,
932 FieldBuffer::<P>::zeros(4).as_view(),
933 5,
934 );
935 buffer.repeat_extend(3);
936 }
937
938 #[test]
939 #[should_panic(expected = "precondition: the store must have room reserved")]
940 fn repeat_extend_rejects_a_store_without_room() {
941 let mut buffer: FieldVec<P, GlobalAllocator> = FieldBuffer::from_view_with_capacity_in(
942 &GlobalAllocator,
943 FieldBuffer::<P>::zeros(4).as_view(),
944 4,
945 );
946 buffer.repeat_extend(5);
947 }
948
949 #[test]
950 fn a_copy_reproduces_every_word_on_both_sides_of_the_task_floor() {
951 let floor = min_len_for_bytes::<P>();
956 for words in [floor, 2 * floor] {
957 let log_len = words.ilog2() as usize + P::LOG_WIDTH;
958 let src = random_field_buffer::<P>(&mut StdRng::seed_from_u64(0), log_len);
959 let copy: FieldVec<P, GlobalAllocator> =
960 FieldBuffer::from_view_in(&GlobalAllocator, src.as_view());
961 assert_eq!(copy.log_len(), log_len);
962 assert_eq!(copy.as_ref(), src.as_ref(), "words={words}");
963 }
964 }
965
966 #[test]
967 #[should_panic(expected = "precondition: log_capacity must be at least src.log_len()")]
968 fn from_view_with_capacity_rejects_a_capacity_below_the_source() {
969 let src = FieldBuffer::<P>::zeros(4);
970 let _: FieldVec<P, GlobalAllocator> =
971 FieldBuffer::from_view_with_capacity_in(&GlobalAllocator, src.as_view(), 3);
972 }
973
974 #[test]
975 fn zeros() {
976 let buffer = FieldBuffer::<P>::zeros(6); assert_eq!(buffer.log_len(), 6);
980 assert_eq!(buffer.len(), 64);
981
982 for i in 0..64 {
984 assert_eq!(buffer.get(i), F::ZERO);
985 }
986
987 let buffer = FieldBuffer::<P>::zeros(1); assert_eq!(buffer.log_len(), 1);
990 assert_eq!(buffer.len(), 2);
991
992 for i in 0..2 {
994 assert_eq!(buffer.get(i), F::ZERO);
995 }
996 }
997
998 #[test]
999 fn alloc_constructors_global() {
1000 check_alloc_constructors(&GlobalAllocator);
1002 }
1003
1004 #[test]
1005 fn alloc_constructors_pooled() {
1006 let pool = BufferPool::new();
1008 check_alloc_constructors(&&pool);
1009 }
1010
1011 #[test]
1012 fn from_values_below_packing_width() {
1013 let values = vec![F::new(1), F::new(2)]; let buffer = FieldBuffer::<P>::from_values(&values);
1018
1019 assert_eq!(buffer.log_len(), 1); assert_eq!(buffer.len(), 2);
1021
1022 assert_eq!(buffer.get(0), F::new(1));
1024 assert_eq!(buffer.get(1), F::new(2));
1025 }
1026
1027 #[test]
1028 fn from_values_above_packing_width() {
1029 let values: Vec<F> = (0..16).map(F::new).collect(); let buffer = FieldBuffer::<P>::from_values(&values);
1034
1035 assert_eq!(buffer.log_len(), 4); assert_eq!(buffer.len(), 16);
1037
1038 for i in 0..16 {
1040 assert_eq!(buffer.get(i), F::new(i as u128));
1041 }
1042 }
1043
1044 #[test]
1045 #[should_panic(expected = "power of two")]
1046 fn from_values_non_power_of_two() {
1047 let values: Vec<F> = (0..7).map(F::new).collect(); let _ = FieldBuffer::<P>::from_values(&values);
1049 }
1050
1051 #[test]
1052 #[should_panic(expected = "power of two")]
1053 fn from_values_empty() {
1054 let values: Vec<F> = vec![];
1055 let _ = FieldBuffer::<P>::from_values(&values);
1056 }
1057
1058 #[test]
1059 fn new_below_packing_width() {
1060 let mut packed_values = vec![P::default()];
1065 let mut buffer = FieldBuffer::new(1, packed_values.as_mut_slice());
1066
1067 assert_eq!(buffer.log_len(), 1);
1068 assert_eq!(buffer.len(), 2);
1069
1070 buffer.set(0, F::new(10));
1072 buffer.set(1, F::new(20));
1073 assert_eq!(buffer.get(0), F::new(10));
1074 assert_eq!(buffer.get(1), F::new(20));
1075 }
1076
1077 #[test]
1078 fn new_above_packing_width() {
1079 let mut packed_values = vec![P::default(); 4];
1084 let mut buffer = FieldBuffer::new(4, packed_values.as_mut_slice());
1085
1086 assert_eq!(buffer.log_len(), 4);
1087 assert_eq!(buffer.len(), 16);
1088
1089 for i in 0..16 {
1091 buffer.set(i, F::new(i as u128 * 10));
1092 }
1093 for i in 0..16 {
1094 assert_eq!(buffer.get(i), F::new(i as u128 * 10));
1095 }
1096 }
1097
1098 #[test]
1099 #[should_panic(expected = "precondition")]
1100 fn new_wrong_packed_length() {
1101 let packed_values = vec![P::default(); 3]; let _ = FieldBuffer::new(4, packed_values.as_slice());
1103 }
1104
1105 #[test]
1106 fn get_set() {
1107 let mut buffer = FieldBuffer::<P>::zeros(3); for i in 0..8 {
1111 buffer.set(i, F::new(i as u128));
1112 }
1113
1114 for i in 0..8 {
1116 assert_eq!(buffer.get(i), F::new(i as u128));
1117 }
1118 }
1119
1120 #[test]
1121 #[should_panic(expected = "precondition")]
1122 fn get_out_of_bounds() {
1123 let buffer = FieldBuffer::<P>::zeros(3); let _ = buffer.get(8);
1125 }
1126
1127 #[test]
1128 #[should_panic(expected = "precondition")]
1129 fn set_out_of_bounds() {
1130 let mut buffer = FieldBuffer::<P>::zeros(3); buffer.set(8, F::new(0));
1132 }
1133
1134 #[test]
1135 fn borrowed_views() {
1136 let mut buffer = FieldBuffer::<P>::zeros(3);
1137
1138 let slice_ref = buffer.as_view();
1140 assert_eq!(slice_ref.len(), buffer.len());
1141 assert_eq!(slice_ref.log_len(), buffer.log_len());
1142 assert_eq!(slice_ref.as_ref().len(), 1 << slice_ref.log_len().saturating_sub(P::LOG_WIDTH));
1143
1144 let mut slice_mut = buffer.as_mut_view();
1146 slice_mut.set(0, F::new(123));
1147 assert_eq!(slice_mut.as_mut().len(), 1 << slice_mut.log_len().saturating_sub(P::LOG_WIDTH));
1148 assert_eq!(buffer.get(0), F::new(123));
1149 }
1150
1151 #[test]
1152 fn iter_scalars() {
1153 let values = vec![F::new(10), F::new(20)]; let buffer = FieldBuffer::<P>::from_values(&values);
1157
1158 let collected: Vec<F> = buffer.iter_scalars().collect();
1159 assert_eq!(collected, values);
1160
1161 for (i, &val) in collected.iter().enumerate() {
1163 assert_eq!(val, buffer.get(i));
1164 }
1165
1166 let values = vec![F::new(1), F::new(2), F::new(3), F::new(4)]; let buffer = FieldBuffer::<P>::from_values(&values);
1169
1170 let collected: Vec<F> = buffer.iter_scalars().collect();
1171 assert_eq!(collected, values);
1172
1173 let values: Vec<F> = (0..16).map(F::new).collect(); let buffer = FieldBuffer::<P>::from_values(&values);
1176
1177 let collected: Vec<F> = buffer.iter_scalars().collect();
1178 assert_eq!(collected, values);
1179
1180 for (i, &val) in collected.iter().enumerate() {
1182 assert_eq!(val, buffer.get(i));
1183 }
1184
1185 let values = vec![F::new(42)];
1187 let buffer = FieldBuffer::<P>::from_values(&values);
1188
1189 let collected: Vec<F> = buffer.iter_scalars().collect();
1190 assert_eq!(collected, values);
1191
1192 let values: Vec<F> = (0..256).map(F::new).collect();
1194 let buffer = FieldBuffer::<P>::from_values(&values);
1195
1196 let collected: Vec<F> = buffer.iter_scalars().collect();
1197 assert_eq!(collected, values);
1198
1199 let values: Vec<F> = (0..8).map(F::new).collect();
1201 let buffer = FieldBuffer::<P>::from_values(&values);
1202
1203 let iter1 = buffer.iter_scalars();
1204 let iter2 = iter1.clone();
1205
1206 let collected1: Vec<F> = iter1.collect();
1207 let collected2: Vec<F> = iter2.collect();
1208 assert_eq!(collected1, collected2);
1209 assert_eq!(collected1, values);
1210 }
1211
1212 #[test]
1213 fn from_iter_below_packing_width() {
1214 let buffer: FieldBuffer<P> = std::iter::once(F::new(9)).collect();
1216 assert_eq!(buffer.log_len(), 0);
1217 assert_eq!(buffer.len(), 1);
1218 assert_eq!(buffer.get(0), F::new(9));
1219
1220 let data = buffer.into_inner();
1222 assert_eq!(data.len(), 1);
1223 assert!((1..P::WIDTH).all(|lane| get_packed_slice(&data[..], lane) == F::ZERO));
1224 }
1225
1226 #[test]
1227 #[should_panic(expected = "power of two")]
1228 fn from_iter_non_power_of_two() {
1229 let _: FieldBuffer<P> = (0..7).map(F::new).collect();
1231 }
1232
1233 #[test]
1234 #[should_panic(expected = "power of two")]
1235 fn from_iter_empty() {
1236 let _: FieldBuffer<P> = std::iter::empty::<F>().collect();
1238 }
1239
1240 #[test]
1241 fn iter_packed_covers_the_live_words() {
1242 let buffer = FieldBuffer::<P>::scalar_with_capacity(F::new(5), 5);
1244 let live: Vec<P> = buffer.iter_packed().copied().collect();
1245 assert_eq!(live.len(), 1);
1246 assert_eq!(get_packed_slice(&live[..], 0), F::new(5));
1247
1248 let values: Vec<F> = (0..16).map(F::new).collect();
1250 let buffer = FieldBuffer::<P>::from_values(&values);
1251 let words: Vec<P> = buffer.iter_packed().copied().collect();
1252 assert_eq!(words.len(), 4);
1253 assert_eq!(P::iter_slice(&words).collect::<Vec<_>>(), values);
1254
1255 let mut truncated = FieldBuffer::<P>::from_values(&values);
1257 truncated.truncate(1);
1258 assert_eq!(truncated.iter_packed().count(), 1);
1259 }
1260
1261 #[test]
1262 fn iter_packed_mut_writes_the_live_words() {
1263 let mut buffer = FieldBuffer::<P>::zeros(3);
1265 assert_eq!(buffer.iter_packed_mut().count(), 2);
1266 for word in buffer.iter_packed_mut() {
1267 *word = P::broadcast(F::new(3));
1268 }
1269 assert!(buffer.iter_scalars().all(|scalar| scalar == F::new(3)));
1270
1271 let mut small = FieldBuffer::<P>::zeros(1);
1273 assert_eq!(small.iter_packed_mut().count(), 1);
1274 for word in small.iter_packed_mut() {
1275 *word = P::broadcast(F::new(7));
1276 }
1277 assert_eq!(small.iter_scalars().collect::<Vec<_>>(), vec![F::new(7); 2]);
1279 }
1280
1281 #[test]
1282 fn truncate_vec_backing() {
1283 let make = || FieldBuffer::<P>::from_values(&(0..16).map(F::new).collect::<Vec<_>>());
1285
1286 let mut buffer = make();
1288 buffer.truncate(3); assert_eq!(buffer.log_len(), 3);
1290 assert_eq!(buffer.len(), 8);
1291 for i in 0..8 {
1292 assert_eq!(buffer.get(i), F::new(i as u128));
1293 }
1294 assert_eq!(buffer.into_inner().len(), 2);
1295
1296 let mut buffer = make();
1298 buffer.truncate(1); assert_eq!(buffer.len(), 2);
1300 assert_eq!(buffer.get(0), F::new(0));
1301 assert_eq!(buffer.get(1), F::new(1));
1302 let data = buffer.into_inner();
1303 assert_eq!(data.len(), 1);
1304 assert_eq!(get_packed_slice(&data[..], 2), F::new(0));
1305 assert_eq!(get_packed_slice(&data[..], 3), F::new(0));
1306
1307 let mut buffer = FieldBuffer::<P>::from_values(&(0..4).map(F::new).collect::<Vec<_>>());
1309 buffer.truncate(5);
1310 assert_eq!(buffer.log_len(), 2);
1311 assert_eq!(buffer.into_inner().len(), 1);
1312 }
1313
1314 #[test]
1315 fn truncate_slice_backing() {
1316 let mut storage = vec![P::default(); 4]; let mut buffer = FieldSliceMut::from_slice(4, storage.as_mut_slice());
1319 for i in 0..16 {
1320 buffer.set(i, F::new(i as u128));
1321 }
1322
1323 buffer.truncate(1); assert_eq!(buffer.len(), 2);
1325 assert_eq!(buffer.get(0), F::new(0));
1326 assert_eq!(buffer.get(1), F::new(1));
1327
1328 let data = buffer.into_inner();
1329 assert_eq!(data.len(), 1);
1330 assert_eq!(get_packed_slice(&data[..], 2), F::new(0));
1331 assert_eq!(get_packed_slice(&data[..], 3), F::new(0));
1332 }
1333
1334 #[test]
1335 fn split_half() {
1336 let values: Vec<F> = (0..16).map(F::new).collect();
1338 let buffer = FieldBuffer::<P>::from_values(&values);
1339
1340 let (first, second) = buffer.split_half();
1341 assert_eq!(first.len(), 8);
1342 assert_eq!(second.len(), 8);
1343
1344 for i in 0..8 {
1346 assert_eq!(first.get(i), F::new(i as u128));
1347 assert_eq!(second.get(i), F::new((i + 8) as u128));
1348 }
1349
1350 let values: Vec<F> = (0..4).map(F::new).collect();
1353 let buffer = FieldBuffer::<P>::from_values(&values);
1354
1355 let (first, second) = buffer.split_half();
1356 assert_eq!(first.len(), 2);
1357 assert_eq!(second.len(), 2);
1358
1359 match &first.words {
1361 FieldSliceData::Single(_) => {}
1362 _ => panic!("Expected Single variant for first half"),
1363 }
1364 match &second.words {
1365 FieldSliceData::Single(_) => {}
1366 _ => panic!("Expected Single variant for second half"),
1367 }
1368
1369 assert_eq!(first.get(0), F::new(0));
1371 assert_eq!(first.get(1), F::new(1));
1372 assert_eq!(second.get(0), F::new(2));
1373 assert_eq!(second.get(1), F::new(3));
1374
1375 let values: Vec<F> = vec![F::new(10), F::new(20)];
1377 let buffer = FieldBuffer::<P>::from_values(&values);
1378
1379 let (first, second) = buffer.split_half();
1380 assert_eq!(first.len(), 1);
1381 assert_eq!(second.len(), 1);
1382
1383 match &first.words {
1385 FieldSliceData::Single(_) => {}
1386 _ => panic!("Expected Single variant for first half"),
1387 }
1388 match &second.words {
1389 FieldSliceData::Single(_) => {}
1390 _ => panic!("Expected Single variant for second half"),
1391 }
1392
1393 assert_eq!(first.get(0), F::new(10));
1394 assert_eq!(second.get(0), F::new(20));
1395 }
1396
1397 #[test]
1398 #[should_panic(expected = "precondition")]
1399 fn split_half_size_one() {
1400 let values = vec![F::new(42)];
1401 let buffer = FieldBuffer::<P>::from_values(&values);
1402 let _ = buffer.split_half();
1403 }
1404
1405 #[test]
1406 fn split_half_mut_no_closure() {
1407 let mut buffer = FieldBuffer::<P>::zeros(4); for i in 0..16 {
1412 buffer.set(i, F::new(i as u128));
1413 }
1414
1415 {
1416 let mut split = buffer.split_half_mut();
1417 let (mut first, mut second) = split.halves();
1418
1419 assert_eq!(first.len(), 8);
1420 assert_eq!(second.len(), 8);
1421
1422 for i in 0..8 {
1424 first.set(i, F::new((i * 10) as u128));
1425 second.set(i, F::new((i * 20) as u128));
1426 }
1427 }
1429
1430 for i in 0..8 {
1432 assert_eq!(buffer.get(i), F::new((i * 10) as u128));
1433 assert_eq!(buffer.get(i + 8), F::new((i * 20) as u128));
1434 }
1435
1436 let mut buffer = FieldBuffer::<P>::zeros(2); for i in 0..4 {
1442 buffer.set(i, F::new(i as u128));
1443 }
1444
1445 {
1446 let mut split = buffer.split_half_mut();
1447 let (mut first, mut second) = split.halves();
1448
1449 assert_eq!(first.len(), 2);
1450 assert_eq!(second.len(), 2);
1451
1452 first.set(0, F::new(100));
1454 first.set(1, F::new(101));
1455 second.set(0, F::new(200));
1456 second.set(1, F::new(201));
1457 }
1459
1460 assert_eq!(buffer.get(0), F::new(100));
1462 assert_eq!(buffer.get(1), F::new(101));
1463 assert_eq!(buffer.get(2), F::new(200));
1464 assert_eq!(buffer.get(3), F::new(201));
1465
1466 let mut buffer = FieldBuffer::<P>::zeros(1); buffer.set(0, F::new(10));
1470 buffer.set(1, F::new(20));
1471
1472 {
1473 let mut split = buffer.split_half_mut();
1474 let (mut first, mut second) = split.halves();
1475
1476 assert_eq!(first.len(), 1);
1477 assert_eq!(second.len(), 1);
1478
1479 first.set(0, F::new(30));
1481 second.set(0, F::new(40));
1482 }
1484
1485 assert_eq!(buffer.get(0), F::new(30));
1487 assert_eq!(buffer.get(1), F::new(40));
1488 }
1489
1490 #[test]
1491 #[should_panic(expected = "precondition")]
1492 fn split_half_mut_size_one() {
1493 let mut buffer = FieldBuffer::<P>::zeros(0); let _ = buffer.split_half_mut();
1495 }
1496
1497 proptest! {
1498 #[test]
1499 fn unequal_length_buffers_are_never_equal(
1500 log_len_a in 0usize..=6,
1501 log_len_b in 0usize..=6,
1502 fill in any::<u128>(),
1503 ) {
1504 let value = F::new(fill);
1506 let buf_a = FieldBuffer::<P>::from_values(&vec![value; 1 << log_len_a]);
1507 let buf_b = FieldBuffer::<P>::from_values(&vec![value; 1 << log_len_b]);
1508
1509 if log_len_a == log_len_b {
1512 prop_assert_eq!(buf_a, buf_b);
1513 } else {
1514 prop_assert_ne!(buf_a, buf_b);
1515 }
1516 }
1517
1518 #[test]
1519 fn from_iter_matches_from_values(log_len in 0usize..=6) {
1520 let values: Vec<F> = (0..1u128 << log_len).map(F::new).collect();
1522
1523 let collected: FieldBuffer<P> = values.iter().copied().collect();
1525 prop_assert_eq!(collected.log_len(), log_len);
1526 prop_assert_eq!(&collected, &FieldBuffer::<P>::from_values(&values));
1527
1528 prop_assert_eq!(&collected.iter_scalars().collect::<Vec<_>>(), &values);
1530 }
1531 }
1532}