Struct ZeroVec
struct ZeroVec<'a, T> { ... }
where
T: AsULE
A zero-copy, byte-aligned vector for fixed-width types.
ZeroVec<T> is designed as a drop-in replacement for Vec<T> in situations where it is
desirable to borrow data from an unaligned byte slice, such as zero-copy deserialization.
T must implement AsULE, which is auto-implemented for a number of built-in types,
including all fixed-width multibyte integers. For variable-width types like str,
see VarZeroVec. zerovec::make_ule may
be used to automatically implement AsULE for a type and generate the underlying ULE type.
Typically, the zero-copy equivalent of a Vec<T> will simply be ZeroVec<'a, T>.
Most of the methods on ZeroVec<'a, T> come from its Deref implementation to ZeroSlice<T>.
For creating zero-copy vectors of fixed-size types, see VarZeroVec.
ZeroVec<T> behaves much like Cow, where it can be constructed from
owned data (and then mutated!) but can also borrow from some buffer.
Example
use ZeroVec;
// The little-endian bytes correspond to the numbers on the following line.
let nums: & = &;
// The owned version will allocate
let data = Data ;
let bincode_bytes =
serialize.expect;
// Will deserialize without allocations
let deserialized: Data = deserialize
.expect;
// This deserializes without allocation!
assert!;
assert_eq!;
assert_eq!;
How it Works
ZeroVec<T> represents a slice of T as a slice of T::ULE. The difference between T and
T::ULE is that T::ULE must be encoded in little-endian with 1-byte alignment. When accessing
items from ZeroVec<T>, we fetch the T::ULE, convert it on the fly to T, and return T by
value.
Benchmarks can be found in the project repository, with some results found in the crate-level documentation.
See the design doc for more details.
Implementations
impl<'a> ZeroVec<'a, u8>
fn try_into_parsed<T: AsULE>(self: Self) -> Result<ZeroVec<'a, T>, UleError>Converts a
ZeroVec<u8>into aZeroVec<T>, retaining the current ownership model.Note that the length of the ZeroVec may change.
Examples
Convert a borrowed
ZeroVec:use ZeroVec; let bytes: & = &; let zv_bytes = new_borrowed; let zerovec: = zv_bytes.try_into_parsed.expect; assert!; assert_eq!;Convert an owned
ZeroVec:use ZeroVec; let bytes: = vec!; let zv_bytes = new_owned; let zerovec: = zv_bytes.try_into_parsed.expect; assert!; assert_eq!;
impl<'a, T> ZeroVec<'a, T>
fn alloc_from_slice(other: &[T]) -> SelfCreates a
ZeroVec<T>from a&[T]by allocating memory.This function results in an
Ownedinstance ofZeroVec<T>.Example
use ZeroVec; // The little-endian bytes correspond to the numbers on the following line. let bytes: & = &; let nums: & = &; let zerovec = alloc_from_slice; assert!; assert_eq!;fn to_vec(self: &Self) -> Vec<T>Creates a
Vec<T>from aZeroVec<T>.Example
use ZeroVec; let nums: & = &; let vec: = alloc_from_slice.to_vec; assert_eq!;
impl<'a, T> ZeroVec<'a, T>
fn try_from_slice(slice: &'a [T]) -> Option<Self>Attempts to create a
ZeroVec<'a, T>from a&'a [T]by borrowing the argument.If this is not possible, such as on a big-endian platform,
Noneis returned.Example
use ZeroVec; // The little-endian bytes correspond to the numbers on the following line. let bytes: & = &; let nums: & = &; if let Some = try_from_slicefn from_slice_or_alloc(slice: &'a [T]) -> SelfCreates a
ZeroVec<'a, T>from a&'a [T], either by borrowing the argument or by allocating a new vector.This is a cheap operation on little-endian platforms, falling back to a more expensive operation on big-endian platforms.
Example
use ZeroVec; // The little-endian bytes correspond to the numbers on the following line. let bytes: & = &; let nums: & = &; let zerovec = from_slice_or_alloc; // Note: zerovec could be either borrowed or owned. assert_eq!;
impl<'a, T> ZeroVec<'a, T>
fn for_each_mut<impl FnMut(&mut T): FnMut(&mut T)>(self: &mut Self, f: impl FnMut(&mut T))Mutates each element according to a given function, meant to be a more convenient version of calling
.iter_mut()with [ZeroVec::with_mut()] which serves fewer use cases.This will convert the ZeroVec into an owned ZeroVec if not already the case.
Example
use ZeroVec; let bytes: & = &; let mut zerovec: = parse_bytes.expect; zerovec.for_each_mut; assert_eq!; assert!;fn try_for_each_mut<E, impl FnMut(&mut T) -> Result<(), E>: FnMut(&mut T) -> Result<(), E>>(self: &mut Self, f: impl FnMut(&mut T) -> Result<(), E>) -> Result<(), E>Same as [
ZeroVec::for_each_mut()], but bubbles up errors.Example
use ZeroVec; let bytes: & = &; let mut zerovec: = parse_bytes.expect; zerovec.try_for_each_mut?; assert_eq!; assert!; # Ok::fn into_owned(self: Self) -> ZeroVec<'static, T>Converts a borrowed ZeroVec to an owned ZeroVec. No-op if already owned.
Example
use ZeroVec; let bytes: & = &; let zerovec: = parse_bytes.expect; assert!; let owned = zerovec.into_owned; assert!;fn with_mut<R, impl FnOnce(&mut alloc::vec::Vec<T::ULE>) -> R: FnOnce(&mut alloc::vec::Vec<<T as >::ULE>) -> R>(self: &mut Self, f: impl FnOnce(&mut Vec<<T as >::ULE>) -> R) -> RAllows the ZeroVec to be mutated by converting it to an owned variant, and producing a mutable vector of ULEs. If you only need a mutable slice, consider using [
Self::to_mut_slice()] instead.Example
# use crateAsULE; use ZeroVec; let bytes: & = &; let mut zerovec: = parse_bytes.expect; assert!; zerovec.with_mut; assert!;fn to_mut_slice(self: &mut Self) -> &mut [<T as >::ULE]Allows the ZeroVec to be mutated by converting it to an owned variant (if necessary) and returning a slice to its backing buffer. [
Self::with_mut()] allows for mutation of the vector itself.Example
# use crateAsULE; use ZeroVec; let bytes: & = &; let mut zerovec: = parse_bytes.expect; assert!; zerovec.to_mut_slice = 5u16.to_unaligned; assert!;fn clear(self: &mut Self)Remove all elements from this ZeroVec and reset it to an empty borrowed state.
fn take_first(self: &mut Self) -> Option<T>Removes the first element of the ZeroVec. The ZeroVec remains in the same borrowed or owned state.
Examples
# use crateAsULE; use ZeroVec; let bytes: & = &; let mut zerovec: = parse_bytes.expect; assert!; let first = zerovec.take_first.unwrap; assert_eq!; assert!; let mut zerovec = zerovec.into_owned; assert!; let first = zerovec.take_first.unwrap; assert_eq!; assert!;fn take_last(self: &mut Self) -> Option<T>Removes the last element of the ZeroVec. The ZeroVec remains in the same borrowed or owned state.
Examples
# use crateAsULE; use ZeroVec; let bytes: & = &; let mut zerovec: = parse_bytes.expect; assert!; let last = zerovec.take_last.unwrap; assert_eq!; assert!; let mut zerovec = zerovec.into_owned; assert!; let last = zerovec.take_last.unwrap; assert_eq!; assert!;fn into_cow(self: Self) -> Cow<'a, [<T as >::ULE]>Converts the type into a
Cow<'a, [T::ULE]>, which is the logical equivalent of this type's internal representation
impl<'a, T: AsULE> ZeroVec<'a, T>
const fn new() -> SelfCreates a new, borrowed, empty
ZeroVec<T>.Examples
use ZeroVec; let zv: = new; assert!;const fn const_len(self: &Self) -> usizeSame as
ZeroSlice::len, which is available throughDerefand notconst.fn new_owned(vec: Vec<<T as >::ULE>) -> SelfCreates a new owned
ZeroVecusing an existing allocated backing bufferIf you have a slice of
&[T]s, prefer using [Self::alloc_from_slice()].const fn new_borrowed(slice: &'a [<T as >::ULE]) -> SelfCreates a new borrowed
ZeroVecusing an existing backing bufferfn with_capacity(capacity: usize) -> SelfCreates a new, owned, empty
ZeroVec<T>, with a certain capacity pre-allocated.fn parse_bytes(bytes: &'a [u8]) -> Result<Self, UleError>Parses a
&[u8]buffer into aZeroVec<T>.This function is infallible for built-in integer types, but fallible for other types, such as
char. For more information, seeULE::parse_bytes_to_slice.The bytes within the byte buffer must remain constant for the life of the ZeroVec.
Endianness
The byte buffer must be encoded in little-endian, even if running in a big-endian environment. This ensures a consistent representation of data across platforms.
Example
use ZeroVec; let bytes: & = &; let zerovec: = parse_bytes.expect; assert!; assert_eq!;unsafe const fn from_bytes_unchecked(bytes: &'a [u8]) -> SelfUses a
&[u8]buffer as aZeroVec<T>without any verification.Safety
bytesneed to be an output from [ZeroSlice::as_bytes()].fn into_bytes(self: Self) -> ZeroVec<'a, u8>Converts a
ZeroVec<T>into aZeroVec<u8>, retaining the current ownership model.Note that the length of the ZeroVec may change.
Examples
Convert a borrowed
ZeroVec:use ZeroVec; let bytes: & = &; let zerovec: = parse_bytes.expect; let zv_bytes = zerovec.into_bytes; assert!; assert_eq!;Convert an owned
ZeroVec:use ZeroVec; let nums: & = &; let zerovec = alloc_from_slice; let zv_bytes = zerovec.into_bytes; assert!; assert_eq!;const fn as_slice(self: &Self) -> &ZeroSlice<T>Returns this
ZeroVecas aZeroSlice.To get a reference with a longer lifetime from a borrowed
ZeroVec, useZeroVec::as_maybe_borrowed.fn cast<P>(self: Self) -> ZeroVec<'a, P> where P: AsULE<ULE = <T as >::ULE>Casts a
ZeroVec<T>to a compatibleZeroVec<P>.TandPare compatible if they have the sameULErepresentation.If the
ULEs ofTandPare different types but have the same size, use [Self::try_into_converted()].Examples
use ZeroVec; let bytes: & = &; let zerovec_u16: = parse_bytes.expect; assert_eq!; let zerovec_i16: = zerovec_u16.cast; assert_eq!;fn try_into_converted<P: AsULE>(self: Self) -> Result<ZeroVec<'a, P>, UleError>Converts a
ZeroVec<T>into aZeroVec<P>, retaining the current ownership model.If
TandPhave the exact sameULE, use [Self::cast()].Panics
Panics if
T::ULEandP::ULEare not the same size.Examples
Convert a borrowed
ZeroVec:use ZeroVec; let bytes: & = &; let zv_char: = parse_bytes.expect; let zv_u8_3: = zv_char.try_into_converted.expect; assert!; assert_eq!;Convert an owned
ZeroVec:use ZeroVec; let chars: & = &; let zv_char = alloc_from_slice; let zv_u8_3: = zv_char.try_into_converted.expect; assert!; assert_eq!;If the types are not the same size, we refuse to convert:
use zerovec::ZeroVec; let bytes: &[u8] = &[0x7F, 0xF3, 0x01, 0x49, 0xF6, 0x01]; let zv_char: ZeroVec<char> = ZeroVec::parse_bytes(bytes).expect("valid code points"); // Panics! core::mem::size_of::<char::ULE> != core::mem::size_of::<u16::ULE> zv_char.try_into_converted::<u16>();Instead, convert to bytes and then parse:
use ZeroVec; let bytes: & = &; let zv_char: = parse_bytes.expect; let zv_u16: = zv_char.into_bytes.try_into_parsed.expect; assert!; assert_eq!;fn is_owned(self: &Self) -> boolCheck if this type is fully owned
fn as_maybe_borrowed(self: &Self) -> Option<&'a ZeroSlice<T>>If this is a borrowed
ZeroVec, return it as a slice that covers its lifetime parameter.To infallibly get a
ZeroSlicewith a shorter lifetime, useZeroVec::as_slice.fn owned_capacity(self: &Self) -> Option<NonZeroUsize>If the ZeroVec is owned, returns the capacity of the vector.
Otherwise, if the ZeroVec is borrowed, returns
None.Examples
use ZeroVec; let mut zv = new_borrowed; assert!; assert_eq!; // Convert to owned without appending anything zv.with_mut; assert!; assert_eq!; // Double the size by appending zv.with_mut; assert!; assert_eq!;
impl<'a, 'b, T> PartialEq for ZeroVec<'a, T>
fn eq(self: &Self, other: &ZeroVec<'b, T>) -> bool
impl<'a, T> Freeze for ZeroVec<'a, T>
impl<'a, T> MutableZeroVecLike for ZeroVec<'a, T>
fn zvl_insert(self: &mut Self, index: usize, value: &T)fn zvl_remove(self: &mut Self, index: usize) -> Tfn zvl_replace(self: &mut Self, index: usize, value: &T) -> Tfn zvl_push(self: &mut Self, value: &T)fn zvl_with_capacity(cap: usize) -> Selffn zvl_clear(self: &mut Self)fn zvl_reserve(self: &mut Self, addl: usize)fn owned_as_t(o: &<Self as >::OwnedType) -> &Tfn zvl_from_borrowed(b: &'a ZeroSlice<T>) -> Selffn zvl_as_borrowed_inner(self: &Self) -> Option<&'a ZeroSlice<T>>fn zvl_permute(self: &mut Self, permutation: &mut [usize])
impl<'a, T> PartialEq for ZeroVec<'a, T>
fn eq(self: &Self, other: &ZeroSlice<T>) -> bool
impl<'a, T> RefUnwindSafe for ZeroVec<'a, T>
impl<'a, T> Unpin for ZeroVec<'a, T>
impl<'a, T> UnsafeUnpin for ZeroVec<'a, T>
impl<'a, T> UnwindSafe for ZeroVec<'a, T>
impl<'a, T> ZeroVecLike for ZeroVec<'a, T>
fn zvl_new_borrowed() -> &'static <Self as >::SliceVariantfn zvl_binary_search(self: &Self, k: &T) -> Result<usize, usize> where T: Ordfn zvl_binary_search_in_range(self: &Self, k: &T, range: Range<usize>) -> Option<Result<usize, usize>> where T: Ordfn zvl_binary_search_by<impl FnMut(&T) -> Ordering: FnMut(&T) -> Ordering>(self: &Self, predicate: impl FnMut(&T) -> Ordering) -> Result<usize, usize>fn zvl_binary_search_in_range_by<impl FnMut(&T) -> Ordering: FnMut(&T) -> Ordering>(self: &Self, predicate: impl FnMut(&T) -> Ordering, range: Range<usize>) -> Option<Result<usize, usize>>fn zvl_get(self: &Self, index: usize) -> Option<&<T as >::ULE>fn zvl_len(self: &Self) -> usizefn zvl_as_borrowed(self: &Self) -> &ZeroSlice<T>fn zvl_get_as_t<R, impl FnOnce(&T) -> R: FnOnce(&T) -> R>(g: &<Self as >::GetType, f: impl FnOnce(&T) -> R) -> R
impl<'a, T: 'static + AsULE> Yokeable for ZeroVec<'static, T>
fn transform(self: &'a Self) -> &'a <Self as >::Outputfn transform_owned(self: Self) -> <Self as >::Outputunsafe fn make(from: <Self as >::Output) -> Selffn transform_mut<F>(self: &'a mut Self, f: F) where F: 'static + for<'b> FnOnce(&'b mut <Self as >::Output)
impl<'a, T: AsULE + Ord> Ord for ZeroVec<'a, T>
fn cmp(self: &Self, other: &Self) -> Ordering
impl<'a, T: AsULE + PartialOrd> PartialOrd for ZeroVec<'a, T>
fn partial_cmp(self: &Self, other: &Self) -> Option<Ordering>
impl<'a, T: AsULE> AsRef for ZeroVec<'a, T>
fn as_ref(self: &Self) -> &ZeroSlice<T>
impl<'a, T: AsULE> AsRef for ZeroVec<'a, T>
fn as_ref(self: &Self) -> &[<T as >::ULE]
impl<'a, T: AsULE> Clone for ZeroVec<'a, T>
fn clone(self: &Self) -> Self
impl<'a, T: AsULE> Default for ZeroVec<'a, T>
fn default() -> Self
impl<'a, T: AsULE> Deref for ZeroVec<'a, T>
fn deref(self: &Self) -> &<Self as >::Target
impl<'a, T: AsULE> From for ZeroVec<'a, T>
fn from(other: Vec<<T as >::ULE>) -> Self
impl<'a, T: AsULE> From for ZeroVec<'a, T>
fn from(other: &'a [<T as >::ULE]) -> Self
impl<'a, T: AsULE> Send for ZeroVec<'a, T>
impl<'a, T: AsULE> Sync for ZeroVec<'a, T>
impl<'zf, T> ZeroFrom for ZeroVec<'zf, T>
fn zero_from(other: &'zf ZeroSlice<T>) -> Self
impl<'zf, T> ZeroFrom for ZeroVec<'zf, T>
fn zero_from(other: &'zf ZeroVec<'_, T>) -> Self
impl<P, T> Receiver for ZeroVec<'a, T>
impl<T> Any for ZeroVec<'a, T>
fn type_id(self: &Self) -> TypeId
impl<T> Borrow for ZeroVec<'a, T>
fn borrow(self: &Self) -> &T
impl<T> BorrowMut for ZeroVec<'a, T>
fn borrow_mut(self: &mut Self) -> &mut T
impl<T> CloneToUninit for ZeroVec<'a, T>
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8)
impl<T> Debug for ZeroVec<'_, T>
fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result
impl<T> EncodeAsVarULE for ZeroVec<'_, T>
fn encode_var_ule_as_slices<R, impl FnOnce(&[&[u8]]) -> R: FnOnce(&[&[u8]]) -> R>(self: &Self, _: impl FnOnce(&[&[u8]]) -> R) -> Rfn encode_var_ule_len(self: &Self) -> usizefn encode_var_ule_write(self: &Self, dst: &mut [u8])
impl<T> Eq for ZeroVec<'_, T>
impl<T> ErasedDestructor for ZeroVec<'a, T>
impl<T> From for ZeroVec<'a, T>
fn from(t: T) -> TReturns the argument unchanged.
impl<T> PartialEq for ZeroVec<'_, T>
fn eq(self: &Self, other: &&[T]) -> bool
impl<T> ToOwned for ZeroVec<'a, T>
fn to_owned(self: &Self) -> Tfn clone_into(self: &Self, target: &mut T)
impl<T, N: usize> PartialEq for ZeroVec<'_, T>
fn eq(self: &Self, other: &[T; N]) -> bool
impl<T, U> Into for ZeroVec<'a, T>
fn into(self: Self) -> UCalls
U::from(self).That is, this conversion is whatever the implementation of
[From]<T> for Uchooses to do.
impl<T, U> TryFrom for ZeroVec<'a, T>
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
impl<T, U> TryInto for ZeroVec<'a, T>
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>
impl<T: AsULE> FromIterator for ZeroVec<'_, T>
fn from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = T>Creates an owned
ZeroVecfrom an iterator of values.