binius_utils/buffer.rs
1// Copyright 2026 The Binius Developers
2
3//! Traits abstracting over the buffers that back Binius' working memory.
4//!
5//! [`BufferData`] is the shrinkable-in-place surface, and [`VecLike`] is that plus growth — the
6//! subset of [`Vec`]'s API that callers rely on. Both are container vocabulary: they say what a
7//! buffer can do, not where its memory came from, so a plain [`Vec`], a borrowed `&mut [T]`, or a
8//! buffer drawn from a recycling pool can all satisfy them.
9
10use std::{mem, mem::MaybeUninit, ops::DerefMut};
11
12/// A mutable buffer of `T` that can be shrunk in place.
13///
14/// This is the backing store a `binius_math::FieldBuffer` needs in order to support
15/// `FieldBuffer::truncate`, which shrinks the store to match a smaller `log_len`.
16///
17/// This trait is the shrinkable-store capability alone, and [`VecLike`] is that plus growth.
18/// Three backings implement it:
19///
20/// - `Vec<T>` and `PoolVec` both shrink and grow, so both are [`VecLike`] as well.
21/// - `&mut [T]` only shrinks, by re-slicing, which is what slice-backed sumcheck halves need.
22pub trait BufferData<T>: DerefMut<Target = [T]> {
23 /// Shrinks the store in place to its first `len` elements.
24 ///
25 /// `len` must be at most the current length.
26 fn truncate(&mut self, len: usize);
27}
28
29impl<T> BufferData<T> for Vec<T> {
30 fn truncate(&mut self, len: usize) {
31 Vec::truncate(self, len);
32 }
33}
34
35impl<T> BufferData<T> for &mut [T] {
36 fn truncate(&mut self, len: usize) {
37 // A `&'a mut [T]` cannot be re-sliced in place through `&mut self`, so move it out and
38 // slice the owned value back in.
39 let full = mem::take(self);
40 *self = &mut full[..len];
41 }
42}
43
44/// A growable, `Vec`-like buffer.
45///
46/// Abstracts the buffer surface the prover uses: [`BufferData`] plus a subset of [`Vec`]'s API.
47/// Implemented by `Vec<T>` and `PoolVec`, with methods added as callers need them.
48/// It is not meant to mirror all of [`Vec`].
49pub trait VecLike<T>: BufferData<T> + Extend<T> {
50 /// Returns the number of elements the buffer can hold without reallocating.
51 fn capacity(&self) -> usize;
52
53 /// Appends an element to the back of the buffer.
54 fn push(&mut self, value: T);
55
56 /// Clears the buffer, removing all elements while retaining its capacity.
57 fn clear(&mut self);
58
59 /// Resizes the buffer to `new_len`, filling any new slots with `value`.
60 fn resize(&mut self, new_len: usize, value: T)
61 where
62 T: Clone;
63
64 /// Appends all elements of `other` to the back of the buffer.
65 fn extend_from_slice(&mut self, other: &[T])
66 where
67 T: Clone;
68
69 /// Returns the spare capacity of the buffer as a slice of `MaybeUninit<T>`.
70 fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>];
71
72 /// Forces the length of the buffer to `new_len`.
73 ///
74 /// # Safety
75 ///
76 /// Same contract as [`Vec::set_len`]: `new_len` must be at most [`capacity`](Self::capacity)
77 /// and the elements in `0..new_len` must be initialized.
78 unsafe fn set_len(&mut self, new_len: usize);
79}
80
81impl<T> VecLike<T> for Vec<T> {
82 fn capacity(&self) -> usize {
83 Vec::capacity(self)
84 }
85
86 fn push(&mut self, value: T) {
87 Vec::push(self, value);
88 }
89
90 fn clear(&mut self) {
91 Vec::clear(self);
92 }
93
94 fn resize(&mut self, new_len: usize, value: T)
95 where
96 T: Clone,
97 {
98 Vec::resize(self, new_len, value);
99 }
100
101 fn extend_from_slice(&mut self, other: &[T])
102 where
103 T: Clone,
104 {
105 Vec::extend_from_slice(self, other);
106 }
107
108 fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
109 Vec::spare_capacity_mut(self)
110 }
111
112 unsafe fn set_len(&mut self, new_len: usize) {
113 unsafe { Vec::set_len(self, new_len) }
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn vec_truncates_through_buffer_data() {
123 let mut buffer = vec![1u64, 2, 3, 4];
124 BufferData::truncate(&mut buffer, 2);
125 assert_eq!(&*buffer, &[1, 2]);
126 }
127
128 #[test]
129 fn slice_truncates_through_buffer_data() {
130 let mut owned = [1u64, 2, 3, 4];
131 let mut buffer: &mut [u64] = &mut owned;
132 BufferData::truncate(&mut buffer, 3);
133 assert_eq!(buffer, &[1, 2, 3]);
134 }
135
136 #[test]
137 fn vec_fills_through_vec_like() {
138 let mut buffer: Vec<u64> = Vec::with_capacity(4);
139 buffer.push(1);
140 buffer.extend_from_slice(&[2, 3]);
141 VecLike::resize(&mut buffer, 5, 0);
142 assert!(VecLike::capacity(&buffer) >= 5);
143 assert_eq!(&*buffer, &[1, 2, 3, 0, 0]);
144 }
145}