node: Document and test `BoundedVec`
Borrow documentation from Rusts standard library to document BoundedVec's functions, and add documentation tests where appropriate. And make it's deref trait return a slice instead of a Vec, which is more common in rust. Signed-off-by: Slack Coder <slackcoder@server.ky>
This commit is contained in:
parent
fe60305455
commit
86beae2ebb
|
|
@ -6,40 +6,53 @@ pub enum Error {
|
|||
InvalidSize { expected: usize, actual: usize },
|
||||
}
|
||||
|
||||
/// A vector with an upper limit on its size using type level constants.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct BoundedVec<T, const N: usize> {
|
||||
v: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T, const N: usize> BoundedVec<T, N> {
|
||||
/// Create a new empty `BoundedVec<T,N>`.
|
||||
pub fn new() -> Self {
|
||||
BoundedVec { v: Vec::new() }
|
||||
}
|
||||
|
||||
/// Create a new `BoundedVec<T,N>` which takes upto the first N values of its argument, taking
|
||||
/// ownership.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use radicle_node::bounded;
|
||||
///
|
||||
/// let mut vec = vec![1, 2, 3];
|
||||
/// let bounded = bounded::BoundedVec::<_, 2>::truncate(vec);
|
||||
/// assert_eq!(bounded.len(), 2);
|
||||
/// ```
|
||||
pub fn truncate(mut v: Vec<T>) -> Self {
|
||||
v.truncate(N);
|
||||
BoundedVec { v }
|
||||
}
|
||||
|
||||
pub fn max() -> usize {
|
||||
N
|
||||
}
|
||||
|
||||
pub fn push(&mut self, item: T) -> Result<(), Error> {
|
||||
if self.len() >= N {
|
||||
return Err(Error::InvalidSize {
|
||||
expected: N,
|
||||
actual: N + 1,
|
||||
});
|
||||
}
|
||||
self.v.push(item);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unbound(self) -> Vec<T> {
|
||||
self.v
|
||||
}
|
||||
|
||||
/// Like [`Vec::with_capacity`] but returns an error if the allocation size exceeds the limit.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use radicle_node::bounded;
|
||||
///
|
||||
/// let vec = bounded::BoundedVec::<i32, 11>::with_capacity(10).unwrap();
|
||||
///
|
||||
/// // The vector contains no items, even though it has capacity for more
|
||||
/// assert_eq!(vec.len(), 0);
|
||||
/// assert!(vec.capacity() >= 10);
|
||||
///
|
||||
/// // A vector with a capacity over its limit will result in error.
|
||||
/// let vec_res = bounded::BoundedVec::<i32, 10>::with_capacity(11);
|
||||
/// assert!(vec_res.is_err());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn with_capacity(capacity: usize) -> Result<Self, Error> {
|
||||
if capacity > N {
|
||||
return Err(Error::InvalidSize {
|
||||
|
|
@ -51,13 +64,83 @@ impl<T, const N: usize> BoundedVec<T, N> {
|
|||
v: Vec::with_capacity(capacity),
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the maximum number of elements BoundedVec can contain.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use radicle_node::bounded;
|
||||
///
|
||||
/// type Inventory = bounded::BoundedVec<(), 10>;
|
||||
/// assert_eq!(Inventory::max(), 10);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn max() -> usize {
|
||||
N
|
||||
}
|
||||
|
||||
/// Extracts a slice containing the entire bounded vector.
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
self.v.as_slice()
|
||||
}
|
||||
|
||||
/// Returns the number of elements the bounded vector can hold without reallocating.
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.v.capacity()
|
||||
}
|
||||
|
||||
/// Like [`Vec::push`] but returns an error if the limit is exceeded.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use radicle_node::bounded;
|
||||
///
|
||||
/// let mut vec: bounded::BoundedVec<_,3> = vec![1, 2].try_into().unwrap();
|
||||
/// vec.push(3).expect("within limit");
|
||||
/// assert_eq!(vec, vec![1, 2, 3].try_into().unwrap());
|
||||
///
|
||||
/// // ...but this will exceed its limit, returning an error.
|
||||
/// vec.push(4).expect_err("limit exceeded");
|
||||
/// assert_eq!(vec.len(), 3);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn push(&mut self, item: T) -> Result<(), Error> {
|
||||
if self.len() >= N {
|
||||
return Err(Error::InvalidSize {
|
||||
expected: N,
|
||||
actual: N + 1,
|
||||
});
|
||||
}
|
||||
self.v.push(item);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the underlying vector without an upper limit.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use radicle_node::bounded;
|
||||
///
|
||||
/// let mut bounded: bounded::BoundedVec<_,3> = vec![1, 2, 3].try_into().unwrap();
|
||||
/// let mut vec = bounded.unbound();
|
||||
///
|
||||
/// vec.push(4);
|
||||
/// assert_eq!(vec.len(), 4);
|
||||
/// ```
|
||||
pub fn unbound(self) -> Vec<T> {
|
||||
self.v
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const N: usize> ops::Deref for BoundedVec<T, N> {
|
||||
type Target = Vec<T>;
|
||||
type Target = [T];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.v
|
||||
self.v.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue