//! This module includes variable-length data types that are const-constructible for single //! values and overflow to the heap. //! //! # Why? //! //! This module is far from the first stack-or-heap vector in the Rust ecosystem. It was created //! with the following value proposition: //! //! 1. Enable safe const construction of stack collections. //! 2. Avoid stack size penalties common with stack-or-heap collections. //! //! As of this writing, `heapless` and `tinyvec` don't support const construction except //! for empty vectors, and `smallvec` supports it on unstable. //! //! Additionally, [`ShortBoxSlice`] has a smaller stack size than any of these: //! //! ```ignore //! use core::mem::size_of; //! //! // NonZeroU64 has a niche that this module utilizes //! use core::num::NonZeroU64; //! //! // ShortBoxSlice is the same size as `Box<[]>` for small or nichey values //! assert_eq!(16, size_of::<shortvec::ShortBoxSlice::<NonZeroU64>>()); //! //! // Note: SmallVec supports pushing and therefore has a capacity field //! assert_eq!(24, size_of::<smallvec::SmallVec::<[NonZeroU64; 1]>>()); //! //! // Note: heapless doesn't support spilling to the heap //! assert_eq!(16, size_of::<heapless::Vec::<NonZeroU64, 1>>()); //! //! // Note: TinyVec only supports types that implement `Default` //! assert_eq!(24, size_of::<tinyvec::TinyVec::<[u64; 1]>>()); //! ``` //! //! The module is `no_std` with `alloc`.
mod litemap;
#[cfg(feature = "alloc")] use alloc::boxed::Box; #[cfg(feature = "alloc")] use alloc::vec; #[cfg(feature = "alloc")] use alloc::vec::Vec; use core::ops::Deref; use core::ops::DerefMut;
/// A boxed slice that supports no-allocation, constant values if length 0 or 1. /// Using ZeroOne(Option<T>) saves 8 bytes in ShortBoxSlice via niche optimization. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub(crate) enum ShortBoxSliceInner<T> {
ZeroOne(Option<T>), #[cfg(feature = "alloc")]
Multi(Box<[T]>), #[cfg(not(feature = "alloc"))]
Two([T; 2]),
}
impl<T> Default for ShortBoxSliceInner<T> { fn default() -> Self { use ShortBoxSliceInner::*;
ZeroOne(None)
}
}
/// A boxed slice that supports no-allocation, constant values if length 0 or 1. /// /// Supports mutation but always reallocs when mutated. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub(crate) struct ShortBoxSlice<T>(ShortBoxSliceInner<T>);
impl<T> ShortBoxSlice<T> { /// Creates a new, empty [`ShortBoxSlice`]. #[inline] pubconstfn new() -> Self { use ShortBoxSliceInner::*; Self(ZeroOne(None))
}
/// Creates a new [`ShortBoxSlice`] containing a single element. #[inline] pubconstfn new_single(item: T) -> Self { use ShortBoxSliceInner::*; Self(ZeroOne(Some(item)))
}
/// Pushes an element onto this [`ShortBoxSlice`]. /// /// Reallocs if more than 1 item is already in the collection. #[cfg(feature = "alloc")] pubfn push(&mutself, item: T) { use ShortBoxSliceInner::*; self.0 = match core::mem::replace(&mutself.0, ZeroOne(None)) {
ZeroOne(None) => ZeroOne(Some(item)),
ZeroOne(Some(prev_item)) => Multi(vec![prev_item, item].into_boxed_slice()),
Multi(items) => { letmut items = items.into_vec();
items.push(item);
Multi(items.into_boxed_slice())
}
};
}
/// Gets a single element from the [`ShortBoxSlice`]. /// /// Returns `None` if empty or more than one element. #[inline] pubconstfn single(&self) -> Option<&T> { use ShortBoxSliceInner::*; matchself.0 {
ZeroOne(Some(ref v)) => Some(v),
_ => None,
}
}
/// Destruct into a single element of the [`ShortBoxSlice`]. /// /// Returns `None` if empty or more than one element. pubfn into_single(self) -> Option<T> { use ShortBoxSliceInner::*; matchself.0 {
ZeroOne(Some(v)) => Some(v),
_ => None,
}
}
/// Returns the number of elements in the collection. #[inline] pubfn len(&self) -> usize { use ShortBoxSliceInner::*; matchself.0 {
ZeroOne(None) => 0,
ZeroOne(_) => 1, #[cfg(feature = "alloc")]
Multi(ref v) => v.len(), #[cfg(not(feature = "alloc"))]
Two(_) => 2,
}
}
/// Returns whether the collection is empty. #[inline] pubconstfn is_empty(&self) -> bool { use ShortBoxSliceInner::*;
matches!(self.0, ZeroOne(None))
}
/// Inserts an element at the specified index into the collection. /// /// Reallocs if more than 1 item is already in the collection. #[cfg(feature = "alloc")] pubfn insert(&mutself, index: usize, elt: T) { use ShortBoxSliceInner::*;
assert!(
index <= self.len(), "insertion index (is {}) should be <= len (is {})",
index, self.len()
);
/// Removes the element at the specified index from the collection. /// /// Reallocs if more than 2 items are in the collection. pubfn remove(&mutself, index: usize) -> T { use ShortBoxSliceInner::*;
assert!(
index < self.len(), "removal index (is {}) should be < len (is {})",
index, self.len()
);
let (replaced, removed_item) = match core::mem::replace(&mutself.0, ZeroOne(None)) {
ZeroOne(None) => unreachable!(),
ZeroOne(Some(v)) => (ZeroOne(None), v), #[cfg(feature = "alloc")]
Multi(v) => { letmut v = v.into_vec(); let removed_item = v.remove(index); match v.len() { #[expect(clippy::unwrap_used)] // we know that the vec has exactly one element left 1 => (ZeroOne(Some(v.pop().unwrap())), removed_item), // v has at least 2 elements, create a Multi variant
_ => (Multi(v.into_boxed_slice()), removed_item),
}
} #[cfg(not(feature = "alloc"))]
Two([f, s]) => (ZeroOne(Some(f)), s),
}; self.0 = replaced;
removed_item
}
/// Removes all elements from the collection. #[inline] pubfn clear(&mutself) { use ShortBoxSliceInner::*; let _ = core::mem::replace(&mutself.0, ZeroOne(None));
}
/// Retains only the elements specified by the predicate. #[allow(dead_code)] pubfn retain<F>(&mutself, mut f: F) where
F: FnMut(&T) -> bool,
{ use ShortBoxSliceInner::*; match core::mem::take(&mutself.0) {
ZeroOne(Some(one)) if f(&one) => self.0 = ZeroOne(Some(one)),
ZeroOne(_) => self.0 = ZeroOne(None), #[cfg(feature = "alloc")]
Multi(slice) => { letmut vec = slice.into_vec();
vec.retain(f);
*self = ShortBoxSlice::from(vec)
} #[cfg(not(feature = "alloc"))]
Two([first, second]) => {
*self = match (Some(first).filter(&mut f), Some(second).filter(&<span style='color:red'>mut f)) {
(None, None) => ShortBoxSlice::new(),
(None, Some(x)) | (Some(x), None) => ShortBoxSlice::new_single(x),
(Some(f), Some(s)) => ShortBoxSlice::new_double(f, s),
}
}
};
}
}
impl<T> Deref for ShortBoxSlice<T> { type Target = [T];
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.20Bemerkung:
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.