#![allow(clippy::let_unit_value)]
use core::fmt;
use std::{
collections::TryReserveError,
fmt::Debug,
ops::{Bound, Deref, DerefMut, RangeBounds, RangeInclusive},
usize,
};
use thiserror::Error;
#[derive(Error, Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Error {
#[error("Vector len outside LOW and UPP bounds")]
OutOfBoundsVec,
}
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct BoundedVec<T, const LOW: usize, const UPP: usize>(Vec<T>);
impl<T, const LOW: usize, const UPP: usize> BoundedVec<T, LOW, UPP> {
#[doc(hidden)]
pub const VALID_L_U_TEST: () = assert!(LOW <= UPP);
#[doc(hidden)]
pub const BOUNDS: RangeInclusive<usize> = LOW..=UPP;
#[inline]
pub unsafe fn from_raw_parts(
ptr: *mut T,
length: usize,
capacity: usize,
) -> Result<Self, Error> {
let _ = Self::VALID_L_U_TEST;
if !Self::BOUNDS.contains(&length) {
return Err(Error::OutOfBoundsVec);
}
Ok(Self(Vec::from_raw_parts(ptr, length, capacity)))
}
#[inline]
pub fn as_vec(&self) -> &Vec<T> {
&self.0
}
#[inline]
pub fn to_vec(self) -> Vec<T> {
self.0
}
#[inline]
pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<T> {
&mut self.0
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.0.reserve(additional)
}
#[inline]
pub fn capacity(&self) -> usize {
self.0.capacity()
}
#[inline]
pub fn reserve_exact(&mut self, additional: usize) {
self.0.reserve_exact(additional)
}
#[inline]
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
self.0.try_reserve(additional)
}
#[inline]
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
self.0.try_reserve_exact(additional)
}
#[inline]
pub fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit()
}
#[inline]
pub fn shrink_to(&mut self, min_capacity: usize) {
self.0.shrink_to(min_capacity);
}
#[inline]
pub fn into_boxed_slice(self) -> Box<[T]> {
self.0.into_boxed_slice()
}
#[inline]
pub fn truncate(&mut self, length: usize) -> Result<(), Error> {
if length < LOW {
return Err(Error::OutOfBoundsVec);
}
self.0.truncate(length);
Ok(())
}
#[inline]
pub fn as_slice(&self) -> &[T] {
self.0.as_slice()
}
#[inline]
pub fn as_ptr(&self) -> *const T {
self.0.as_ptr()
}
#[inline]
pub fn as_mut_slice(&mut self) -> &[T] {
self.0.as_mut_slice()
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
self.0.as_mut_ptr()
}
#[inline]
pub unsafe fn set_len(&mut self, new_len: usize) -> Result<(), Error> {
self.0.set_len(new_len);
Ok(())
}
#[inline]
pub fn swap_remove(&mut self, index: usize) -> Result<T, Error> {
if self.len() <= LOW {
return Err(Error::OutOfBoundsVec);
}
Ok(self.0.swap_remove(index))
}
#[inline]
pub fn insert(&mut self, index: usize, element: T) -> Result<(), Error> {
if self.len() >= UPP {
return Err(Error::OutOfBoundsVec);
}
self.0.insert(index, element);
Ok(())
}
#[inline]
pub fn remove(&mut self, index: usize) -> Result<T, Error> {
if self.len() <= LOW {
return Err(Error::OutOfBoundsVec);
}
Ok(self.0.remove(index))
}
#[inline]
pub fn retain<F>(mut self, f: F) -> Result<Self, Error>
where
F: FnMut(&T) -> bool,
{
self.0.retain(f);
if self.len() < LOW {
return Err(Error::OutOfBoundsVec);
}
Ok(self)
}
#[inline]
pub fn retain_mut<F>(mut self, f: F) -> Result<Self, Error>
where
F: FnMut(&mut T) -> bool,
{
self.0.retain_mut(f);
if self.len() < LOW {
return Err(Error::OutOfBoundsVec);
}
Ok(self)
}
#[inline]
pub fn dedup_by_key<F, K>(mut self, key: F) -> Result<Self, Error>
where
F: FnMut(&mut T) -> K,
K: PartialEq,
{
self.0.dedup_by_key(key);
if self.len() < LOW {
return Err(Error::OutOfBoundsVec);
}
Ok(self)
}
#[inline]
pub fn dedup_by<F>(mut self, same_bucket: F) -> Result<Self, Error>
where
F: FnMut(&mut T, &mut T) -> bool,
{
self.0.dedup_by(same_bucket);
if self.len() < LOW {
return Err(Error::OutOfBoundsVec);
}
Ok(self)
}
#[inline]
pub fn push(&mut self, value: T) -> Result<(), Error> {
if self.len() >= UPP {
return Err(Error::OutOfBoundsVec);
}
self.0.push(value);
Ok(())
}
#[inline]
pub fn pop(&mut self) -> Result<T, Error> {
if self.len() <= LOW {
return Err(Error::OutOfBoundsVec);
}
Ok(self.0.pop().expect("Checked before"))
}
#[inline]
pub fn append(&mut self, vec: &mut Vec<T>) -> Result<(), Error> {
if self.len() + vec.len() > UPP {
return Err(Error::OutOfBoundsVec);
}
self.0.append(vec);
Ok(())
}
#[inline]
pub fn len(&self) -> usize {
if LOW == UPP {
LOW
} else {
self.0.len()
}
}
#[inline]
pub fn is_empty(&self) -> bool {
if UPP == 0 {
true
} else {
self.0.is_empty()
}
}
#[inline]
pub fn split_off(&mut self, at: usize) -> Result<Vec<T>, Error> {
if at < LOW {
return Err(Error::OutOfBoundsVec);
}
Ok(self.0.split_off(at))
}
#[inline]
pub fn resize_with<F>(&mut self, new_len: usize, f: F) -> Result<(), Error>
where
F: FnMut() -> T,
{
if !Self::BOUNDS.contains(&new_len) {
return Err(Error::OutOfBoundsVec);
}
self.0.resize_with(new_len, f);
Ok(())
}
}
impl<T: Clone, const LOW: usize, const UPP: usize> BoundedVec<T, LOW, UPP> {
#[doc(hidden)]
#[inline]
pub fn from_elem(elem: T, n: usize) -> Result<Self, Error> {
if !Self::BOUNDS.contains(&n) {
return Err(Error::OutOfBoundsVec);
}
Ok(Self(vec![elem; n]))
}
#[inline]
pub fn resize(&mut self, new_len: usize, value: T) -> Result<(), Error> {
if !Self::BOUNDS.contains(&new_len) {
return Err(Error::OutOfBoundsVec);
}
self.0.resize(new_len, value);
Ok(())
}
#[inline]
pub fn extend_from_slice(&mut self, other: &[T]) -> Result<(), Error> {
if self.len() + other.len() > UPP {
return Err(Error::OutOfBoundsVec);
}
self.0.extend_from_slice(other);
Ok(())
}
pub fn extend_from_within<R>(&mut self, src: R) -> Result<(), Error>
where
R: RangeBounds<usize>,
{
let start = match src.start_bound() {
Bound::Unbounded => 0,
Bound::Excluded(v) => v + 1,
Bound::Included(v) => *v,
};
let end = match src.end_bound() {
Bound::Unbounded => self.len(),
Bound::Excluded(v) => *v,
Bound::Included(v) => v + 1,
};
if start > end {
panic!("slice index starts at {start} but ends at {end}")
}
let new_len = end - start + self.len();
if new_len > UPP {
return Err(Error::OutOfBoundsVec);
}
self.0.extend_from_within(src);
if !Self::BOUNDS.contains(&self.len()) {
panic!(
"The length of array({}) is outside LOW and UPP bounds",
self.len()
)
}
Ok(())
}
}
impl<T: Clone, const UPP: usize> BoundedVec<T, 0, UPP> {
#[inline]
pub const fn new() -> Self {
let _ = Self::VALID_L_U_TEST;
Self(Vec::new())
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
let _ = Self::VALID_L_U_TEST;
Self(Vec::with_capacity(capacity))
}
#[inline]
pub fn clear(&mut self) {
self.0.clear()
}
}
impl<T, const LOW: usize, const UPP: usize> TryFrom<Vec<T>> for BoundedVec<T, LOW, UPP> {
type Error = Error;
fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
let _ = Self::VALID_L_U_TEST;
if !Self::BOUNDS.contains(&value.len()) {
return Err(Error::OutOfBoundsVec);
}
Ok(Self(value))
}
}
impl<T, const LOW: usize, const UPP: usize> TryFrom<Box<[T]>> for BoundedVec<T, LOW, UPP> {
type Error = Error;
fn try_from(value: Box<[T]>) -> Result<Self, Self::Error> {
let _ = Self::VALID_L_U_TEST;
if !Self::BOUNDS.contains(&value.len()) {
return Err(Error::OutOfBoundsVec);
}
Ok(Self(value.into()))
}
}
impl<T, const LOW: usize, const UPP: usize> From<BoundedVec<T, LOW, UPP>> for Vec<T> {
fn from(value: BoundedVec<T, LOW, UPP>) -> Self {
let _ = BoundedVec::<T, LOW, UPP>::VALID_L_U_TEST;
value.0
}
}
impl<T, const LOW: usize, const UPP: usize, const N: usize> TryFrom<[T; N]>
for BoundedVec<T, LOW, UPP>
{
type Error = Error;
fn try_from(value: [T; N]) -> Result<Self, Self::Error> {
let _ = Self::VALID_L_U_TEST;
if !Self::BOUNDS.contains(&N) {
return Err(Error::OutOfBoundsVec);
}
Ok(Self(value.into()))
}
}
impl<T, const LOW: usize, const UPP: usize> AsRef<Vec<T>> for BoundedVec<T, LOW, UPP> {
fn as_ref(&self) -> &Vec<T> {
&self.0
}
}
impl<T, const LOW: usize, const UPP: usize> Deref for BoundedVec<T, LOW, UPP> {
type Target = [T];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T, const LOW: usize, const UPP: usize> DerefMut for BoundedVec<T, LOW, UPP> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T: Debug, const LOW: usize, const UPP: usize> Debug for BoundedVec<T, LOW, UPP> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt::Debug::fmt(&*self.0, f)
}
}
#[cfg(test)]
mod tests {
use crate::bvec;
use super::*;
const fn err<T>() -> Result<T, Error> {
Err(Error::OutOfBoundsVec)
}
#[test]
fn format() {
let bvec: BoundedVec<_, 0, 10> = bvec![1, 2, 3].unwrap();
assert_eq!("[1, 2, 3]", format!("{:?}", bvec));
}
#[test]
fn format_hash() {
let bvec: BoundedVec<_, 0, 10> = bvec![1, 2, 3].unwrap();
assert_eq!("[\n 1,\n 2,\n 3,\n]", format!("{:#?}", bvec));
}
#[test]
fn try_from_array() {
let bounded_vec = BoundedVec::<_, 2, 3>::try_from([1, 2, 3]).unwrap();
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec());
let bounded_vec = BoundedVec::<_, 1, 2>::try_from([1, 2, 3]);
assert_eq!(err(), bounded_vec);
}
#[test]
fn try_from_box_array() {
let bounded_vec =
BoundedVec::<_, 2, 3>::try_from(vec![1, 2, 3].into_boxed_slice()).unwrap();
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec());
let bounded_vec = BoundedVec::<_, 1, 2>::try_from(vec![1, 2, 3].into_boxed_slice());
assert_eq!(err(), bounded_vec);
}
#[test]
fn try_from_vec() {
let bounded_vec = BoundedVec::<_, 2, 3>::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec());
let bounded_vec = BoundedVec::<_, 1, 2>::try_from(vec![1, 2, 3]);
assert_eq!(err(), bounded_vec);
}
#[test]
fn new() {
assert_eq!(Vec::<()>::new(), BoundedVec::<(), 0, 0>::new().to_vec());
}
#[test]
fn with_capacity() {
assert_eq!(
BoundedVec::<(), 0, 0>::new(),
BoundedVec::<(), 0, 0>::with_capacity(0)
);
}
#[test]
fn truncate() {
let mut bounded_vec: BoundedVec<i32, 2, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
bounded_vec.truncate(2).unwrap();
assert_eq!(vec![1, 2], bounded_vec.to_vec());
let mut bounded_vec: BoundedVec<i32, 2, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(err(), bounded_vec.truncate(1));
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec())
}
#[test]
fn swap_remove() {
let mut bounded_vec: BoundedVec<i32, 2, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(Ok(1), bounded_vec.swap_remove(0));
assert_eq!(vec![3, 2], bounded_vec.to_vec());
let mut bounded_vec: BoundedVec<i32, 3, 4> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(err(), bounded_vec.swap_remove(0));
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec());
}
#[test]
fn insert() {
let mut bounded_vec: BoundedVec<i32, 3, 4> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
bounded_vec.insert(2, 20).unwrap();
assert_eq!(vec![1, 2, 20, 3], bounded_vec.to_vec());
let mut bounded_vec: BoundedVec<i32, 2, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(err(), bounded_vec.insert(3, 4));
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec());
}
#[test]
fn remove() {
let mut bounded_vec: BoundedVec<i32, 2, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(Ok(2), bounded_vec.remove(1));
assert_eq!(vec![1, 3], bounded_vec.to_vec());
let mut bounded_vec: BoundedVec<i32, 3, 4> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(err(), bounded_vec.remove(1));
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec());
}
#[test]
fn retain() {
let bounded_vec: BoundedVec<i32, 1, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
let bounded_vec = bounded_vec.retain(|x| *x == 3).unwrap();
assert_eq!(vec![3], bounded_vec.to_vec());
let bounded_vec: BoundedVec<i32, 2, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(err(), bounded_vec.retain(|x| *x == 2));
}
#[test]
fn retain_mut() {
let bounded_vec: BoundedVec<i32, 1, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
let bounded_vec = bounded_vec
.retain_mut(|x| {
*x *= 2;
*x == 6
})
.unwrap();
assert_eq!(vec![6], bounded_vec.to_vec());
let bounded_vec: BoundedVec<i32, 2, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(
err(),
bounded_vec.retain_mut(|x| {
*x *= 2;
*x == 6
})
)
}
#[test]
fn dedup_by_key() {
let bounded_vec: BoundedVec<_, 2, 3> = BoundedVec::try_from(vec![1, 1, 2]).unwrap();
let bounded_vec = bounded_vec.dedup_by_key(|x| *x).unwrap();
assert_eq!(vec![1, 2], bounded_vec.to_vec());
let bounded_vec: BoundedVec<_, 3, 4> = BoundedVec::try_from(vec![1, 1, 2]).unwrap();
assert_eq!(err(), bounded_vec.dedup_by_key(|x| *x));
}
#[test]
fn dedup_by() {
let bounded_vec: BoundedVec<_, 2, 3> = BoundedVec::try_from(vec![1, 1, 2]).unwrap();
let bounded_vec = bounded_vec.dedup_by(|x, y| x == y).unwrap();
assert_eq!(vec![1, 2], bounded_vec.to_vec());
let bounded_vec: BoundedVec<_, 3, 4> = BoundedVec::try_from(vec![1, 1, 2]).unwrap();
assert_eq!(err(), bounded_vec.dedup_by(|x, y| x == y));
}
#[test]
fn push() {
let mut bounded_vec: BoundedVec<_, 3, 4> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
bounded_vec.push(4).unwrap();
assert_eq!(vec![1, 2, 3, 4], bounded_vec.to_vec());
let mut bounded_vec: BoundedVec<_, 2, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(err(), bounded_vec.push(4));
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec());
}
#[test]
fn pop() {
let mut bounded_vec: BoundedVec<_, 2, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(3, bounded_vec.pop().unwrap());
assert_eq!(vec![1, 2], bounded_vec.to_vec());
let mut bounded_vec: BoundedVec<_, 3, 5> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(err(), bounded_vec.pop());
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec());
}
#[test]
fn append() {
let mut vec = vec![4, 5];
let mut bounded_vec: BoundedVec<_, 3, 5> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
bounded_vec.append(&mut vec).unwrap();
assert_eq!(Vec::<i32>::new(), vec);
assert_eq!(vec![1, 2, 3, 4, 5], bounded_vec.to_vec());
let mut vec = vec![4, 5];
let mut bounded_vec: BoundedVec<_, 3, 4> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(err(), bounded_vec.append(&mut vec));
assert_eq!(vec![4, 5], vec);
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec())
}
#[test]
fn clear() {
let mut bounded_vec: BoundedVec<_, 0, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
bounded_vec.clear();
assert_eq!(BoundedVec::new(), bounded_vec);
}
#[test]
fn split_off() {
let mut bounded_vec: BoundedVec<_, 2, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(vec![3], bounded_vec.split_off(2).unwrap());
assert_eq!(vec![1, 2], bounded_vec.to_vec());
let mut bounded_vec: BoundedVec<_, 3, 4> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(err(), bounded_vec.split_off(2));
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec())
}
#[test]
fn resize_with() {
let mut bounded_vec: BoundedVec<_, 3, 5> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
bounded_vec.resize_with(5, || 0).unwrap();
assert_eq!(vec![1, 2, 3, 0, 0], bounded_vec.to_vec());
let mut bounded_vec: BoundedVec<_, 1, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
bounded_vec.resize_with(1, || 0).unwrap();
assert_eq!(vec![1], bounded_vec.to_vec());
let mut bounded_vec: BoundedVec<_, 3, 4> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(err(), bounded_vec.resize_with(5, || 0));
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec());
let mut bounded_vec: BoundedVec<_, 2, 3> = BoundedVec::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(err(), bounded_vec.resize_with(1, || 0));
assert_eq!(vec![1, 2, 3], bounded_vec.to_vec());
}
#[test]
fn from_elem() {
let bounded_vec: BoundedVec<_, 3, 4> = BoundedVec::from_elem(3, 4).unwrap();
assert_eq!(vec![3, 3, 3, 3], bounded_vec.to_vec());
let bounded_vec = BoundedVec::<_, 2, 3>::from_elem(3, 4);
assert_eq!(err(), bounded_vec)
}
#[test]
pub fn resize() {
let mut bounded_vec = BoundedVec::<_, 1, 3>::try_from(vec![1, 2, 3]).unwrap();
bounded_vec.resize(1, 2).unwrap();
assert_eq!(&vec![1], bounded_vec.as_vec());
bounded_vec.resize(3, 2).unwrap();
assert_eq!(&vec![1, 2, 2], bounded_vec.as_vec());
assert_eq!(err(), bounded_vec.resize(4, 2));
assert_eq!(vec![1, 2, 2], bounded_vec.to_vec());
}
#[test]
pub fn extend_from_slice() {
let mut bounded_vec = BoundedVec::<_, 3, 5>::try_from(vec![1, 2, 3]).unwrap();
bounded_vec.extend_from_slice(&[4, 5]).unwrap();
assert_eq!(&vec![1, 2, 3, 4, 5], bounded_vec.as_vec());
assert_eq!(err(), bounded_vec.extend_from_slice(&[6]));
assert_eq!(&vec![1, 2, 3, 4, 5], bounded_vec.as_vec());
}
#[test]
pub fn extend_from_within() {
let mut bounded_vec = BoundedVec::<_, 3, 5>::try_from(vec![1, 2, 3]).unwrap();
bounded_vec.extend_from_within(1..).unwrap();
assert_eq!(&vec![1, 2, 3, 2, 3], bounded_vec.as_vec());
bounded_vec.extend_from_within(4..4).unwrap();
assert_eq!(&vec![1, 2, 3, 2, 3], bounded_vec.as_vec());
assert_eq!(err(), bounded_vec.extend_from_within(4..=4));
assert_eq!(&vec![1, 2, 3, 2, 3], bounded_vec.as_vec())
}
}