From 86beae2ebb25810b8005d9a111c45bd2113ab948 Mon Sep 17 00:00:00 2001 From: Slack Coder Date: Thu, 1 Dec 2022 10:27:48 -0500 Subject: [PATCH] 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 --- radicle-node/src/bounded.rs | 125 ++++++++++++++++++++++++++++++------ 1 file changed, 104 insertions(+), 21 deletions(-) diff --git a/radicle-node/src/bounded.rs b/radicle-node/src/bounded.rs index 61bc09d2..01ac79c8 100644 --- a/radicle-node/src/bounded.rs +++ b/radicle-node/src/bounded.rs @@ -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 { v: Vec, } impl BoundedVec { + /// Create a new empty `BoundedVec`. pub fn new() -> Self { BoundedVec { v: Vec::new() } } + /// Create a new `BoundedVec` 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) -> 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 { - 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::::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::::with_capacity(11); + /// assert!(vec_res.is_err()); + /// ``` + #[inline] pub fn with_capacity(capacity: usize) -> Result { if capacity > N { return Err(Error::InvalidSize { @@ -51,13 +64,83 @@ impl BoundedVec { 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 { + self.v + } } impl ops::Deref for BoundedVec { - type Target = Vec; + type Target = [T]; fn deref(&self) -> &Self::Target { - &self.v + self.v.as_slice() } }