mirror of
https://seed.radicle.dev/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5.git
synced 2026-11-16 00:00:37 +08:00
Use the BoundedVec to limit the supported number of refs in RefAnnouncement messages. The size (235) is the maximum supported by message wire size. To reduce the complexity of the changes, BoundedVec is used again instead of using a new bounded Refs or BTreeMap. This requires defining new Decode/Encode logic for Ref's element types, and workarounds for arbitrary instances. Signed-off-by: Slack Coder <slackcoder@server.ky>
189 lines
5.0 KiB
Rust
189 lines
5.0 KiB
Rust
use std::ops;
|
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
pub enum Error {
|
|
#[error("invalid size: expected {expected}, got {actual}")]
|
|
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() }
|
|
}
|
|
|
|
/// Build a `BoundedVec` by consuming from the given iterator up to its limit.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use radicle_node::bounded;
|
|
///
|
|
/// let mut iter = (0..4).into_iter();
|
|
/// let bounded: bounded::BoundedVec<i32,3> = bounded::BoundedVec::collect_from(&mut iter);
|
|
///
|
|
/// assert_eq!(bounded.len(), 3);
|
|
/// assert_eq!(iter.count(), 1);
|
|
/// ```
|
|
pub fn collect_from<I: Iterator<Item = T>>(iter: &mut I) -> Self {
|
|
BoundedVec {
|
|
v: iter.into_iter().take(N).collect(),
|
|
}
|
|
}
|
|
|
|
/// 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 {
|
|
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 = [T];
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
self.v.as_slice()
|
|
}
|
|
}
|
|
|
|
impl<T, const N: usize> From<Option<T>> for BoundedVec<T, N> {
|
|
fn from(value: Option<T>) -> Self {
|
|
let v = match value {
|
|
None => vec![],
|
|
Some(v) => vec![v],
|
|
};
|
|
BoundedVec { v }
|
|
}
|
|
}
|
|
|
|
impl<T, const N: usize> TryFrom<Vec<T>> for BoundedVec<T, N> {
|
|
type Error = Error;
|
|
|
|
fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
|
|
if value.len() > N {
|
|
return Err(Error::InvalidSize {
|
|
expected: N,
|
|
actual: value.len(),
|
|
});
|
|
}
|
|
Ok(BoundedVec { v: value })
|
|
}
|
|
}
|