use crate::errors::capacity::FixedCap;
use crate::errors::types::SizeHint;
use crate::errors::ErrorItemProvider;
#[subdef::subdef]
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[error("Collected items out of bounds ({capacity:?}): {kind}")]
pub struct CapacityError<T> {
pub capacity: SizeHint,
pub kind: [CapacityErrorKind<T>; {
#[derive(Debug, PartialEq, Eq, derive_more::Display)]
pub enum CapacityErrorKind<T> {
#[display("Iterator ({hint:?}) cannot satisfy capacity")]
Bounds {
hint: SizeHint,
},
#[display("Iterator produced ({count}), less than the minimum capacity")]
Underflow {
count: usize,
},
#[display("Iterator exceeded capacity")]
Overflow {
overflow: T,
},
}
}],
}
impl<T> CapacityError<T> {
#[must_use]
pub const fn bounds(capacity: SizeHint, hint: SizeHint) -> Self {
assert!(SizeHint::disjoint(capacity, hint), "Bounds must not overlap");
Self { capacity, kind: CapacityErrorKind::Bounds { hint } }
}
pub fn ensure_fits<I: Iterator<Item = T>>(iter: &I, capacity: SizeHint) -> Result<(), Self> {
let hint = iter.size_hint().try_into().expect("Invalid size hint");
match SizeHint::disjoint(hint, capacity) {
true => Err(Self { capacity, kind: CapacityErrorKind::Bounds { hint } }),
false => Ok(()),
}
}
#[must_use]
pub const fn overflow(capacity: SizeHint, overflow: T) -> Self {
assert!(capacity.upper().is_some(), "Capacity must have an upper bound to overflow");
Self { capacity, kind: CapacityErrorKind::Overflow { overflow } }
}
#[must_use]
pub const fn underflow(capacity: SizeHint, count: usize) -> Self {
assert!(count < capacity.lower(), "count must be less than capacity");
Self { capacity, kind: CapacityErrorKind::Underflow { count } }
}
#[must_use]
pub const fn underflow_of<C: FixedCap>(count: usize) -> Self {
Self::underflow(C::CAP, count)
}
}
impl<T> ErrorItemProvider for CapacityError<T> {
type Item = T;
fn into_item(self) -> Option<Self::Item> {
match self.kind {
CapacityErrorKind::Overflow { overflow } => Some(overflow),
_ => None,
}
}
fn item(&self) -> Option<&Self::Item> {
match &self.kind {
CapacityErrorKind::Overflow { overflow } => Some(overflow),
_ => None,
}
}
}
#[cfg(feature = "arrayvec")]
impl<T> From<arrayvec::CapacityError<T>> for CapacityError<T> {
fn from(err: arrayvec::CapacityError<T>) -> Self {
Self::overflow(SizeHint::ZERO, err.element())
}
}