radicle_node/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_node::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_node::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_node::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_node::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_node::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_node::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}