Skip to main content

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}