radicle_protocol/
bounded.rs

1use std::{
2    collections::BTreeSet,
3    ops::{self, RangeBounds},
4};
5
6#[derive(thiserror::Error, Debug)]
7pub enum Error {
8    #[error("invalid size: expected {expected}, got {actual}")]
9    InvalidSize { expected: usize, actual: usize },
10}
11
12/// A vector with an upper limit on its size using type level constants.
13#[derive(Default, Clone, PartialEq, Eq)]
14pub struct BoundedVec<T, const N: usize> {
15    v: Vec<T>,
16}
17
18impl<T, const N: usize> BoundedVec<T, N> {
19    /// Create a new empty `BoundedVec<T,N>`.
20    pub fn new() -> Self {
21        BoundedVec {
22            v: Vec::with_capacity(N),
23        }
24    }
25
26    /// Build a `BoundedVec` by consuming from the given iterator up to its limit.
27    ///
28    /// # Examples
29    ///
30    /// ```
31    /// use radicle_protocol::bounded;
32    ///
33    /// let mut iter = (0..4).into_iter();
34    /// let bounded: bounded::BoundedVec<i32,3> = bounded::BoundedVec::collect_from(&mut iter);
35    ///
36    /// assert_eq!(bounded.len(), 3);
37    /// assert_eq!(iter.count(), 1);
38    /// ```
39    pub fn collect_from<I: IntoIterator<Item = T>>(iter: I) -> Self {
40        BoundedVec {
41            v: iter.into_iter().take(N).collect(),
42        }
43    }
44
45    /// Create a new `BoundedVec<T,N>` which takes upto the first N values of its argument, taking
46    /// ownership.
47    ///
48    /// # Examples
49    ///
50    /// ```
51    /// use radicle_protocol::bounded;
52    ///
53    /// let mut vec = vec![1, 2, 3];
54    /// let bounded = bounded::BoundedVec::<_, 2>::truncate(vec);
55    /// assert_eq!(bounded.len(), 2);
56    /// ```
57    pub fn truncate(mut v: Vec<T>) -> Self {
58        v.truncate(N);
59        BoundedVec { v }
60    }
61
62    /// Like [`Vec::with_capacity`] but returns an error if the allocation size exceeds the limit.
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// use radicle_protocol::bounded;
68    ///
69    /// let vec = bounded::BoundedVec::<i32, 11>::with_capacity(10).unwrap();
70    ///
71    /// // The vector contains no items, even though it has capacity for more
72    /// assert_eq!(vec.len(), 0);
73    /// assert!(vec.capacity() >= 10);
74    ///
75    /// // A vector with a capacity over its limit will result in error.
76    /// let vec_res = bounded::BoundedVec::<i32, 10>::with_capacity(11);
77    /// assert!(vec_res.is_err());
78    /// ```
79    #[inline]
80    pub fn with_capacity(capacity: usize) -> Result<Self, Error> {
81        if capacity > N {
82            return Err(Error::InvalidSize {
83                expected: N,
84                actual: capacity,
85            });
86        }
87        Ok(Self {
88            v: Vec::with_capacity(capacity),
89        })
90    }
91
92    /// Return the maximum number of elements BoundedVec can contain.
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// use radicle_protocol::bounded;
98    ///
99    /// type Inventory = bounded::BoundedVec<(), 10>;
100    /// assert_eq!(Inventory::max(), 10);
101    /// ```
102    #[inline]
103    pub fn max() -> usize {
104        N
105    }
106
107    /// Extracts a slice containing the entire bounded vector.
108    #[inline]
109    pub fn as_slice(&self) -> &[T] {
110        self.v.as_slice()
111    }
112
113    /// Returns the number of elements the bounded vector can hold without reallocating.
114    pub fn capacity(&self) -> usize {
115        self.v.capacity()
116    }
117
118    /// Like [`Vec::push`] but returns an error if the limit is exceeded.
119    ///
120    /// # Examples
121    ///
122    /// ```
123    /// use radicle_protocol::bounded;
124    ///
125    /// let mut vec: bounded::BoundedVec<_,3> = vec![1, 2].try_into().unwrap();
126    /// vec.push(3).expect("within limit");
127    /// assert_eq!(vec, vec![1, 2, 3].try_into().unwrap());
128    ///
129    /// // ...but this will exceed its limit, returning an error.
130    /// vec.push(4).expect_err("limit exceeded");
131    /// assert_eq!(vec.len(), 3);
132    /// ```
133    #[inline]
134    pub fn push(&mut self, item: T) -> Result<(), Error> {
135        if self.len() >= N {
136            return Err(Error::InvalidSize {
137                expected: N,
138                actual: N + 1,
139            });
140        }
141        self.v.push(item);
142        Ok(())
143    }
144
145    /// Return the underlying vector without an upper limit.
146    ///
147    /// # Examples
148    ///
149    /// ```
150    /// use radicle_protocol::bounded;
151    ///
152    /// let mut bounded: bounded::BoundedVec<_,3> = vec![1, 2, 3].try_into().unwrap();
153    /// let mut vec = bounded.unbound();
154    ///
155    /// vec.push(4);
156    /// assert_eq!(vec.len(), 4);
157    /// ```
158    pub fn unbound(self) -> Vec<T> {
159        self.v
160    }
161
162    /// Calls [`std::vec::Drain`].
163    pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> std::vec::Drain<T> {
164        self.v.drain(range)
165    }
166}
167
168impl<T: Clone, const N: usize> BoundedVec<T, N> {
169    /// Like [`Vec::extend_from_slice`] but returns an error if out of bounds.
170    pub fn extend_from_slice(&mut self, slice: &[T]) -> Result<(), Error> {
171        if self.len() + slice.len() > N {
172            return Err(Error::InvalidSize {
173                expected: N,
174                actual: self.len() + slice.len(),
175            });
176        }
177        self.v.extend_from_slice(slice);
178
179        Ok(())
180    }
181}
182
183impl<T, const N: usize> ops::Deref for BoundedVec<T, N> {
184    type Target = [T];
185
186    fn deref(&self) -> &Self::Target {
187        self.v.as_slice()
188    }
189}
190
191impl<T, const N: usize> From<Option<T>> for BoundedVec<T, N> {
192    fn from(value: Option<T>) -> Self {
193        let v = match value {
194            None => vec![],
195            Some(v) => vec![v],
196        };
197        BoundedVec { v }
198    }
199}
200
201impl<T, const N: usize> TryFrom<Vec<T>> for BoundedVec<T, N> {
202    type Error = Error;
203
204    fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
205        if value.len() > N {
206            return Err(Error::InvalidSize {
207                expected: N,
208                actual: value.len(),
209            });
210        }
211        Ok(BoundedVec { v: value })
212    }
213}
214
215impl<T, const N: usize> TryFrom<BTreeSet<T>> for BoundedVec<T, N> {
216    type Error = Error;
217
218    fn try_from(value: BTreeSet<T>) -> Result<Self, Self::Error> {
219        if value.len() > N {
220            return Err(Error::InvalidSize {
221                expected: N,
222                actual: value.len(),
223            });
224        }
225        Ok(BoundedVec {
226            v: value.into_iter().collect(),
227        })
228    }
229}
230
231impl<T, const N: usize> From<BoundedVec<T, N>> for Vec<T> {
232    fn from(value: BoundedVec<T, N>) -> Self {
233        value.v
234    }
235}
236
237impl<T: std::fmt::Debug, const N: usize> std::fmt::Debug for BoundedVec<T, N> {
238    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
239        self.v.fmt(f)
240    }
241}
242
243unsafe impl<const N: usize> bytes::BufMut for BoundedVec<u8, N> {
244    fn remaining_mut(&self) -> usize {
245        N - self.v.len()
246    }
247
248    unsafe fn advance_mut(&mut self, cnt: usize) {
249        let len = {
250            let len = self.v.len();
251            let remaining = N - len;
252
253            if remaining >= cnt {
254                len + cnt
255            } else {
256                panic!("advance out of bounds: have {remaining} remaining, but advancing by {cnt}",);
257            }
258        };
259
260        debug_assert!(len <= N);
261
262        // Addition will not overflow since the sum is at most the capacity.
263        self.v.set_len(len);
264    }
265
266    fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
267        let len = self.v.len();
268
269        // If the vector is full, we double its capacity using `reserve`, but not beyond the limit.
270        if self.v.capacity() == len {
271            self.v.reserve(std::cmp::min(len, N - len));
272        }
273
274        let cap = self.v.capacity();
275
276        debug_assert!(cap <= N);
277        debug_assert!(len <= cap);
278
279        let ptr = self.v.as_mut_ptr();
280
281        // SAFETY: Since `ptr` is valid for `cap` bytes, `ptr.add(len)` must be
282        // valid for `cap - len` bytes. The subtraction will not underflow since
283        // `len <= cap`.
284        unsafe { bytes::buf::UninitSlice::from_raw_parts_mut(ptr.add(len), cap - len) }
285    }
286}
287
288#[cfg(any(test, feature = "test"))]
289impl<T, const N: usize> qcheck::Arbitrary for BoundedVec<T, N>
290where
291    T: qcheck::Arbitrary + Eq,
292{
293    fn arbitrary(g: &mut qcheck::Gen) -> Self {
294        let mut v: Vec<T> = qcheck::Arbitrary::arbitrary(g);
295        v.truncate(N);
296        v.try_into().expect("size within bounds")
297    }
298}