Struct VarZeroVec

struct VarZeroVec<'a, T: ?Sized, F = Index16>(_)

A zero-copy, byte-aligned vector for variable-width types.

VarZeroVec<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, and where T's data is variable-length (e.g. String)

T must implement VarULE, which is already implemented for str and [u8]. For storing more complicated series of elements, it is implemented on ZeroSlice<T> as well as VarZeroSlice<T> for nesting. zerovec::make_varule may be used to generate a dynamically-sized VarULE type and conversions to and from a custom type.

For example, here are some owned types and their zero-copy equivalents:

Most of the methods on VarZeroVec<'a, T> come from its Deref implementation to VarZeroSlice<T>.

For creating zero-copy vectors of fixed-size types, see ZeroVec.

VarZeroVec<T> behaves much like Cow, where it can be constructed from owned data (and then mutated!) but can also borrow from some buffer.

The F type parameter is a VarZeroVecFormat (see its docs for more details), which can be used to select the precise format of the backing buffer with various size and performance tradeoffs. It defaults to Index16.

Bytes and Equality

Two VarZeroVecs are equal if and only if their bytes are equal, as described in the trait VarULE. However, we do not guarantee stability of byte equality or serialization format across major SemVer releases.

To compare a [Vec<T>] to a [VarZeroVec<T>], it is generally recommended to use Iterator::eq, since it is somewhat expensive at runtime to convert from a [Vec<T>] to a [VarZeroVec<T>] or vice-versa.

Prior to zerovec reaching 1.0, the precise byte representation of VarZeroVec is still under consideration, with different options along the space-time spectrum. See #1410.

Example

use zerovec::VarZeroVec;

// The little-endian bytes correspond to the list of strings.
let strings = vec!["w", "ω", "", "𑄃"];

#[derive(serde::Serialize, serde::Deserialize)]
struct Data<'a> {
    #[serde(borrow)]
    strings: VarZeroVec<'a, str>,
}

let data = Data {
    strings: VarZeroVec::from(&strings),
};

let bincode_bytes =
    bincode::serialize(&data).expect("Serialization should be successful");

// Will deserialize without allocations
let deserialized: Data = bincode::deserialize(&bincode_bytes)
    .expect("Deserialization should be successful");

assert_eq!(deserialized.strings.get(2), Some(""));
assert_eq!(deserialized.strings, &*strings);

Here's another example with ZeroSlice<T> (similar to [T]):

use zerovec::VarZeroVec;
use zerovec::ZeroSlice;

// The structured list correspond to the list of integers.
let numbers: &[&[u32]] = &[
    &[12, 25, 38],
    &[39179, 100],
    &[42, 55555],
    &[12345, 54321, 9],
];

#[derive(serde::Serialize, serde::Deserialize)]
struct Data<'a> {
    #[serde(borrow)]
    vecs: VarZeroVec<'a, ZeroSlice<u32>>,
}

let data = Data {
    vecs: VarZeroVec::from(numbers),
};

let bincode_bytes =
    bincode::serialize(&data).expect("Serialization should be successful");

let deserialized: Data = bincode::deserialize(&bincode_bytes)
    .expect("Deserialization should be successful");

assert_eq!(deserialized.vecs[0].get(1).unwrap(), 25);
assert_eq!(deserialized.vecs[1], *numbers[1]);

VarZeroVecs can be nested infinitely via a similar mechanism, see the docs of VarZeroSlice for more information.

How it Works

VarZeroVec<T>, when used with non-human-readable serializers (like bincode), will serialize to a specially formatted list of bytes. The format is:

The format is tweakable by setting the F parameter, by default it uses u16 indices and lengths but other VarZeroVecFormat types can set other sizes.

Each element in the indices array points to the ending index of its corresponding data part in the data list. The starting index can be calculated from the ending index of the next element (or 0 for the first element). The last ending index, not stored in the array, is the length of the data segment.

See the design doc for more details.

Implementations

impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVec<'a, T, F>

const fn new() -> Self

Creates a new, empty VarZeroVec<T>.

Examples

use zerovec::VarZeroVec;

let vzv: VarZeroVec<str> = VarZeroVec::new();
assert!(vzv.is_empty());
fn parse_bytes(slice: &'a [u8]) -> Result<Self, UleError>

Parse a VarZeroVec from a slice of the appropriate format

Slices of the right format can be obtained via [VarZeroSlice::as_bytes()].

Example

# use zerovec::VarZeroVec;

let strings = vec!["foo", "bar", "baz", "quux"];
let vec = VarZeroVec::<str>::from(&strings);

assert_eq!(&vec[0], "foo");
assert_eq!(&vec[1], "bar");
assert_eq!(&vec[2], "baz");
assert_eq!(&vec[3], "quux");
unsafe const fn from_bytes_unchecked(bytes: &'a [u8]) -> Self

Uses a &[u8] buffer as a VarZeroVec<T> without any verification.

Safety

bytes need to be an output from [VarZeroSlice::as_bytes()].

fn make_mut(self: &mut Self) -> &mut VarZeroVecOwned<T, F>

Convert this into a mutable vector of the owned T type, cloning if necessary.

Example

# use zerovec::VarZeroVec;
let strings = vec!["foo", "bar", "baz", "quux"];
let mut vec = VarZeroVec::<str>::from(&strings);

assert_eq!(vec.len(), 4);
let mutvec = vec.make_mut();
mutvec.push("lorem ipsum".into());
mutvec[2] = "dolor sit".into();
assert_eq!(&vec[0], "foo");
assert_eq!(&vec[1], "bar");
assert_eq!(&vec[2], "dolor sit");
assert_eq!(&vec[3], "quux");
assert_eq!(&vec[4], "lorem ipsum");
fn into_owned(self: Self) -> VarZeroVec<'static, T, F>

Converts a borrowed ZeroVec to an owned ZeroVec. No-op if already owned.

Example

# use zerovec::VarZeroVec;

let strings = vec!["foo", "bar", "baz", "quux"];
let vec = VarZeroVec::<str>::from(&strings);

assert_eq!(vec.len(), 4);
// has 'static lifetime
let owned = vec.into_owned();
fn as_slice(self: &Self) -> &VarZeroSlice<T, F>

Obtain this VarZeroVec as a VarZeroSlice

fn into_bytes(self: Self) -> Vec<u8>

Takes the byte vector representing the encoded data of this VarZeroVec. If borrowed, this function allocates a byte vector and copies the borrowed bytes into it.

The bytes can be passed back to [Self::parse_bytes()].

To get a reference to the bytes without moving, see [VarZeroSlice::as_bytes()].

Example

# use zerovec::VarZeroVec;

let strings = vec!["foo", "bar", "baz"];
let bytes = VarZeroVec::<str>::from(&strings).into_bytes();

let mut borrowed: VarZeroVec<str> =
    VarZeroVec::parse_bytes(&bytes).unwrap();
assert_eq!(borrowed, &*strings);
fn is_owned(self: &Self) -> bool

Return whether the VarZeroVec is operating on owned or borrowed data. [VarZeroVec::into_owned()] and [VarZeroVec::make_mut()] can be used to force it into an owned type

impl<'a, 'b, T, F> PartialEq for VarZeroVec<'a, T, F>

fn eq(self: &Self, other: &VarZeroVec<'b, T, F>) -> bool

impl<'a, T, F> Eq for VarZeroVec<'a, T, F>

impl<'a, T, F> Freeze for VarZeroVec<'a, T, F>

impl<'a, T, F> MutableZeroVecLike for VarZeroVec<'a, T, F>

fn zvl_insert(self: &mut Self, index: usize, value: &T)
fn zvl_remove(self: &mut Self, index: usize) -> Box<T>
fn zvl_replace(self: &mut Self, index: usize, value: &T) -> Box<T>
fn zvl_push(self: &mut Self, value: &T)
fn zvl_with_capacity(cap: usize) -> Self
fn zvl_clear(self: &mut Self)
fn zvl_reserve(self: &mut Self, addl: usize)
fn owned_as_t(o: &<Self as >::OwnedType) -> &T
fn zvl_from_borrowed(b: &'a VarZeroSlice<T, F>) -> Self
fn zvl_as_borrowed_inner(self: &Self) -> Option<&'a VarZeroSlice<T, F>>
fn zvl_permute(self: &mut Self, permutation: &mut [usize])

impl<'a, T, F> RefUnwindSafe for VarZeroVec<'a, T, F>

impl<'a, T, F> Send for VarZeroVec<'a, T, F>

impl<'a, T, F> Sync for VarZeroVec<'a, T, F>

impl<'a, T, F> Unpin for VarZeroVec<'a, T, F>

impl<'a, T, F> UnsafeUnpin for VarZeroVec<'a, T, F>

impl<'a, T, F> UnwindSafe for VarZeroVec<'a, T, F>

impl<'a, T, F> ZeroVecLike for VarZeroVec<'a, T, F>

fn zvl_new_borrowed() -> &'static <Self as >::SliceVariant
fn zvl_binary_search_in_range(self: &Self, k: &T, range: Range<usize>) -> Option<Result<usize, usize>>
where
    T: Ord
fn 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>
fn zvl_len(self: &Self) -> usize
fn zvl_as_borrowed(self: &Self) -> &VarZeroSlice<T, F>
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 + VarULE + ?Sized> Yokeable for VarZeroVec<'static, T>

fn transform(self: &'a Self) -> &'a <Self as >::Output
fn transform_owned(self: Self) -> <Self as >::Output
unsafe fn make(from: <Self as >::Output) -> Self
fn transform_mut<F>(self: &'a mut Self, f: F)
where
    F: 'static + for<'b> FnOnce(&'b mut <Self as >::Output)

impl<'a, T: ?Sized, F> Clone for VarZeroVec<'a, T, F>

fn clone(self: &Self) -> Self

impl<'a, T: ?Sized, F> From for VarZeroVec<'a, T, F>

fn from(other: &'a VarZeroSlice<T, F>) -> Self

impl<'a, T: ?Sized, F> From for VarZeroVec<'a, T, F>

fn from(other: VarZeroVecOwned<T, F>) -> Self

impl<'a, T: VarULE + ?Sized + Ord, F: VarZeroVecFormat> Ord for VarZeroVec<'a, T, F>

fn cmp(self: &Self, other: &Self) -> Ordering

impl<'a, T: VarULE + ?Sized + PartialOrd, F: VarZeroVecFormat> PartialOrd for VarZeroVec<'a, T, F>

fn partial_cmp(self: &Self, other: &Self) -> Option<Ordering>

impl<'zf, T, F: VarZeroVecFormat> ZeroFrom for VarZeroVec<'zf, T, F>

fn zero_from(other: &'zf VarZeroVec<'_, T, F>) -> Self

impl<'zf, T, F: VarZeroVecFormat> ZeroFrom for VarZeroVec<'zf, T, F>

fn zero_from(other: &'zf VarZeroSlice<T, F>) -> Self

impl<A, T, F> From for VarZeroVec<'static, T, F>

fn from(elements: &[A]) -> Self

impl<A, T, F> From for VarZeroVec<'static, T, F>

fn from(elements: &Vec<A>) -> Self

impl<A, T, F, N: usize> From for VarZeroVec<'static, T, F>

fn from(elements: &[A; N]) -> Self

impl<P, T> Receiver for VarZeroVec<'a, T, F>

impl<T> Any for VarZeroVec<'a, T, F>

fn type_id(self: &Self) -> TypeId

impl<T> Borrow for VarZeroVec<'a, T, F>

fn borrow(self: &Self) -> &T

impl<T> BorrowMut for VarZeroVec<'a, T, F>

fn borrow_mut(self: &mut Self) -> &mut T

impl<T> CloneToUninit for VarZeroVec<'a, T, F>

unsafe fn clone_to_uninit(self: &Self, dest: *mut u8)

impl<T> ErasedDestructor for VarZeroVec<'a, T, F>

impl<T> From for VarZeroVec<'a, T, F>

fn from(t: T) -> T

Returns the argument unchanged.

impl<T> ToOwned for VarZeroVec<'a, T, F>

fn to_owned(self: &Self) -> T
fn clone_into(self: &Self, target: &mut T)

impl<T, A, F> PartialEq for VarZeroVec<'_, T, F>

fn eq(self: &Self, other: &&[A]) -> bool

impl<T, A, F, N: usize> PartialEq for VarZeroVec<'_, T, F>

fn eq(self: &Self, other: &[A; N]) -> bool

impl<T, F> EncodeAsVarULE for VarZeroVec<'_, T, F>

fn encode_var_ule_as_slices<R, impl FnOnce(&[&[u8]]) -> R: FnOnce(&[&[u8]]) -> R>(self: &Self, _: impl FnOnce(&[&[u8]]) -> R) -> R
fn encode_var_ule_len(self: &Self) -> usize
fn encode_var_ule_write(self: &Self, dst: &mut [u8])

impl<T, F: VarZeroVecFormat> Debug for VarZeroVec<'_, T, F>

fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result

impl<T, U> Into for VarZeroVec<'a, T, F>

fn into(self: Self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

impl<T, U> TryFrom for VarZeroVec<'a, T, F>

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

impl<T, U> TryInto for VarZeroVec<'a, T, F>

fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>

impl<T: VarULE + ?Sized> Default for VarZeroVec<'_, T>

fn default() -> Self

impl<T: VarULE + ?Sized, F: VarZeroVecFormat> Deref for VarZeroVec<'_, T, F>

fn deref(self: &Self) -> &VarZeroSlice<T, F>