Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
node: Document and test `BoundedVec`
Slack Coder committed 3 years ago
commit 86beae2ebb25810b8005d9a111c45bd2113ab948
parent fe60305455ad490ed3f1978e5e4db8fb4b78e8c8
1 file changed +97 -14
modified radicle-node/src/bounded.rs
@@ -6,25 +6,107 @@ 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 }
    }

+
    /// 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 {
+
                expected: N,
+
                actual: capacity,
+
            });
+
        }
+
        Ok(Self {
+
            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 {
@@ -36,28 +118,29 @@ impl<T, const N: usize> BoundedVec<T, N> {
        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
    }
-

-
    pub fn with_capacity(capacity: usize) -> Result<Self, Error> {
-
        if capacity > N {
-
            return Err(Error::InvalidSize {
-
                expected: N,
-
                actual: capacity,
-
            });
-
        }
-
        Ok(Self {
-
            v: Vec::with_capacity(capacity),
-
        })
-
    }
}

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()
    }
}