#![warn(
missing_debug_implementations,
missing_docs,
rust_2018_idioms,
unreachable_pub
)]
#![deny(rustdoc::broken_intra_doc_links)]
#![forbid(unsafe_code)]
use std::{
cmp,
convert::{TryFrom, TryInto},
fmt,
ops::{Deref, DerefMut, Index, IndexMut},
slice::{Iter as SliceIter, IterMut as SliceIterMut, SliceIndex},
vec::IntoIter,
};
pub trait NotEmpty: sealed::Sealed {}
mod sealed {
pub trait Sealed {}
}
macro_rules! impl_for_arrays {
($($size:literal),+) => {
$(
impl<T> sealed::Sealed for MinSizedVec<T, $size> {}
impl<T> NotEmpty for MinSizedVec<T, $size> {}
)*
};
}
impl_for_arrays!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 32, 64, 128);
pub type NonEmptyVec<T> = MinSizedVec<T, 1>;
#[derive(Clone, Eq, Ord, Hash)]
pub struct MinSizedVec<T, const N: usize>(Vec<T>);
impl<T, const MINIMUM_SIZE: usize> MinSizedVec<T, MINIMUM_SIZE> {
pub const MINIMUM_SIZE: usize = MINIMUM_SIZE;
pub fn new(value: Vec<T>) -> Result<MinSizedVec<T, MINIMUM_SIZE>, Vec<T>> {
Self::try_from(value)
}
pub fn from_iterator<I>(iterator: I) -> Result<MinSizedVec<T, MINIMUM_SIZE>, Vec<T>>
where
I: IntoIterator<Item = T>,
{
let vec: Vec<T> = iterator.into_iter().collect();
if vec.len() >= MINIMUM_SIZE {
Ok(Self(vec))
} else {
Err(vec)
}
}
#[must_use]
pub fn into_inner(self) -> Vec<T> {
self.0
}
pub fn push(&mut self, value: T) {
self.0.push(value);
}
pub fn pop(&mut self) -> Option<T> {
if self.len() > MINIMUM_SIZE {
self.0.pop()
} else {
None
}
}
pub fn clear_to_minimum(&mut self) {
self.truncate(MINIMUM_SIZE);
}
pub fn truncate(&mut self, len: usize) {
let len = cmp::max(len, MINIMUM_SIZE);
self.0.truncate(len);
}
pub fn extend_from_slice(&mut self, other: &[T])
where
T: Clone,
{
self.0.extend_from_slice(other);
}
pub fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
pub fn reserve_exact(&mut self, additional: usize) {
self.0.reserve_exact(additional);
}
pub fn resize(&mut self, new_len: usize, value: T)
where
T: Clone,
{
self.0.resize(cmp::max(new_len, MINIMUM_SIZE), value);
}
pub fn resize_with<F>(&mut self, new_len: usize, f: F)
where
F: FnMut() -> T,
{
self.0.resize_with(cmp::max(new_len, MINIMUM_SIZE), f);
}
pub fn insert(&mut self, index: usize, element: T) {
self.0.insert(index, element);
}
#[track_caller]
pub fn remove(&mut self, index: usize) -> T {
if index >= self.len() {
panic!(
"index {} out of bounds for MinSizedVec of length {}",
index,
self.len()
);
}
if self.len() == MINIMUM_SIZE {
panic!(
"removing element at index {} would underflow minimum size of {}",
index, MINIMUM_SIZE
);
}
self.0.remove(index)
}
#[track_caller]
pub fn swap_remove(&mut self, index: usize) -> T {
if index >= self.len() {
panic!(
"index {} out of bounds for MinSizedVec of length {}",
index,
self.len()
);
}
if self.len() == MINIMUM_SIZE {
panic!(
"removing element at index {} would underflow minimum size of {}",
index, MINIMUM_SIZE
);
}
self.0.swap_remove(index)
}
pub fn capped_retain<F>(&mut self, mut f: F)
where
F: FnMut(&T) -> bool,
{
let mut allowed_to_remove = self.len() - MINIMUM_SIZE;
if allowed_to_remove == 0 {
return;
}
self.0.retain(|e| {
let remove = allowed_to_remove != 0 && !f(e);
if remove {
allowed_to_remove -= 1;
}
!remove
});
}
pub fn try_retain<F>(mut self, f: F) -> Result<Self, Vec<T>>
where
F: FnMut(&T) -> bool,
{
self.0.retain(f);
if self.0.len() >= MINIMUM_SIZE {
Ok(self)
} else {
Err(self.0)
}
}
pub fn change_minimum_size<const NEW: usize>(self) -> Result<MinSizedVec<T, NEW>, Self> {
if self.len() >= NEW {
Ok(MinSizedVec(self.0))
} else {
Err(self)
}
}
pub fn capacity(&self) -> usize {
self.0.capacity()
}
fn as_slice(&self) -> &[T] {
self
}
pub fn guaranteed_head(&self) -> &[T; MINIMUM_SIZE] {
self.0[..MINIMUM_SIZE].try_into().unwrap()
}
pub fn guaranteed_tail(&self) -> &[T; MINIMUM_SIZE] {
self.0[(self.len() - MINIMUM_SIZE)..].try_into().unwrap()
}
}
impl<T, const MINIMUM_SIZE: usize> MinSizedVec<T, MINIMUM_SIZE>
where
MinSizedVec<T, MINIMUM_SIZE>: NotEmpty,
{
pub fn first_mut(&mut self) -> &mut T {
self.0.first_mut().unwrap()
}
pub fn last_mut(&mut self) -> &mut T {
self.0.last_mut().unwrap()
}
pub fn first(&self) -> &T {
self.0.first().unwrap()
}
pub fn last(&self) -> &T {
self.0.last().unwrap()
}
}
impl<T, const N: usize> fmt::Debug for MinSizedVec<T, N>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T, const N: usize> Default for MinSizedVec<T, N>
where
T: Default,
{
fn default() -> Self {
let mut vec = Vec::new();
vec.resize_with(N, T::default);
Self(vec)
}
}
impl<T, const N: usize> Deref for MinSizedVec<T, N> {
type Target = [T];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T, const N: usize> DerefMut for MinSizedVec<T, N> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T, I, const N: usize> Index<I> for MinSizedVec<T, N>
where
I: SliceIndex<[T]>,
{
type Output = <I as SliceIndex<[T]>>::Output;
fn index(&self, index: I) -> &Self::Output {
self.0.index(index)
}
}
impl<T, I, const N: usize> IndexMut<I> for MinSizedVec<T, N>
where
I: SliceIndex<[T]>,
{
fn index_mut(&mut self, index: I) -> &mut Self::Output {
self.0.index_mut(index)
}
}
impl<T, U, const A: usize, const B: usize> PartialEq<MinSizedVec<U, B>> for MinSizedVec<T, A>
where
T: PartialEq<U>,
{
fn eq(&self, other: &MinSizedVec<U, B>) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<T, U, const N: usize> PartialEq<[U]> for MinSizedVec<T, N>
where
T: PartialEq<U>,
{
fn eq(&self, other: &[U]) -> bool {
self.as_slice() == other
}
}
impl<'a, T, U, const N: usize> PartialEq<&'a [U]> for MinSizedVec<T, N>
where
T: PartialEq<U>,
{
fn eq(&self, other: &&'a [U]) -> bool {
self.as_slice() == *other
}
}
impl<T, U, const A: usize, const B: usize> PartialEq<[U; B]> for MinSizedVec<T, A>
where
T: PartialEq<U>,
{
fn eq(&self, other: &[U; B]) -> bool {
self.as_slice() == other
}
}
impl<'a, T, U, const A: usize, const B: usize> PartialEq<&'a [U; B]> for MinSizedVec<T, A>
where
T: PartialEq<U>,
{
fn eq(&self, other: &&'a [U; B]) -> bool {
self.as_slice() == *other
}
}
impl<T, const A: usize, const B: usize> PartialOrd<MinSizedVec<T, B>> for MinSizedVec<T, A>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &MinSizedVec<T, B>) -> Option<cmp::Ordering> {
self.as_slice().partial_cmp(other)
}
}
impl<T, const N: usize> AsRef<[T]> for MinSizedVec<T, N> {
fn as_ref(&self) -> &[T] {
self
}
}
impl<T, const N: usize> AsMut<[T]> for MinSizedVec<T, N> {
fn as_mut(&mut self) -> &mut [T] {
self
}
}
impl<T, const N: usize> IntoIterator for MinSizedVec<T, N> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a, T, const N: usize> IntoIterator for &'a MinSizedVec<T, N> {
type Item = &'a T;
type IntoIter = SliceIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T, const N: usize> IntoIterator for &'a mut MinSizedVec<T, N> {
type Item = &'a mut T;
type IntoIter = SliceIterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<T, const N: usize> Extend<T> for MinSizedVec<T, N> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
self.0.extend(iter);
}
}
impl<T, const N: usize> From<[T; N]> for MinSizedVec<T, N> {
fn from(val: [T; N]) -> Self {
let mut vec = Vec::new();
vec.extend(val);
MinSizedVec(vec)
}
}
impl<T, const N: usize> TryFrom<Vec<T>> for MinSizedVec<T, N> {
type Error = Vec<T>;
fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
if value.len() >= N {
Ok(Self(value))
} else {
Err(value)
}
}
}
#[cfg(feature = "arbitrary")]
impl<'a, T, const N: usize> arbitrary::Arbitrary<'a> for MinSizedVec<T, N>
where
T: arbitrary::Arbitrary<'a>,
{
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let start = u.arbitrary::<[T; N]>()?;
let mut out = MinSizedVec::from(start);
let additional = u.arbitrary_len::<T>()?;
for _ in 0..additional {
out.push(u.arbitrary()?);
}
Ok(out)
}
fn size_hint(depth: usize) -> (usize, Option<usize>) {
arbitrary::size_hint::recursion_guard(depth, |depth| {
arbitrary::size_hint::and(
<[T; N] as arbitrary::Arbitrary>::size_hint(depth),
<Vec<T> as arbitrary::Arbitrary>::size_hint(depth),
)
})
}
}
#[cfg(any(feature = "serde", test))]
mod serde_impl {
use super::*;
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
impl<T, const N: usize> Serialize for MinSizedVec<T, N>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_seq(self)
}
}
impl<'de, T, const N: usize> Deserialize<'de> for MinSizedVec<T, N>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let v = <Vec<T>>::deserialize(deserializer)?;
if v.len() >= N {
Ok(Self(v))
} else {
Err(<D::Error>::custom(format!(
"expected at least {} elements, found only {}",
N,
v.len()
)))
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serde_serialize() {
let serialized = serde_json::to_string(&MinSizedVec::from([1, 2, 3])).unwrap();
assert_eq!(serialized, "[1,2,3]");
}
#[test]
fn serde_deserialize() {
let v = serde_json::from_str::<MinSizedVec<i32, 3>>("[1,2,3]").unwrap();
assert_eq!(v, &[1, 2, 3]);
let v = serde_json::from_str::<MinSizedVec<i32, 3>>("[1,2]");
assert!(v.is_err());
}
}