pub unsafe trait VarULE: 'static {
fn validate_byte_slice(_bytes: &[u8]) -> Result<(), ZeroVecError>;
unsafe fn from_byte_slice_unchecked(bytes: &[u8]) -> &Self;
fn parse_byte_slice(bytes: &[u8]) -> Result<&Self, ZeroVecError> { ... }
fn as_byte_slice(&self) -> &[u8]ⓘNotable traits for &'_ [u8]impl<'_> Read for &'_ [u8]impl<'_> Write for &'_ mut [u8]
{ ... }
fn to_boxed(&self) -> Box<Self>ⓘNotable traits for Box<R, Global>impl<R> Read for Box<R, Global> where
R: Read + ?Sized, impl<W> Write for Box<W, Global> where
W: Write + ?Sized, impl<I, A> Iterator for Box<I, A> where
I: Iterator + ?Sized,
A: Allocator, type Item = <I as Iterator>::Item;impl<F, A> Future for Box<F, A> where
F: Future + Unpin + ?Sized,
A: Allocator + 'static, type Output = <F as Future>::Output;
{ ... }
}
Expand description
Variable-width, byte-aligned data that can be cast to and from a little-endian byte slice.
If you need to implement this trait, consider using #[make_varule]
or
#[derive(VarULE)]
instead.
This trait is mostly for unsized types like str
and [T]
. It can be implemented on sized types;
however, it is much more preferable to use ULE
for that purpose. The custom
module contains
additional documentation on how this type can be implemented on custom types.
If deserialization with VarZeroVec
is desired is recommended to implement Deserialize
for
Box<T>
(serde does not do this automatically for unsized T
).
For convenience it is typically desired to implement EncodeAsVarULE
and ZeroFrom
on some stack type to convert to and from the ULE type efficiently when necessary.
Safety
Safety checklist for VarULE
:
- The type must not include any uninitialized or padding bytes.
- The type must have an alignment of 1 byte.
- The impl of
VarULE::validate_byte_slice()
must return an error if the given byte slice would not represent a valid slice of this type. - The impl of
VarULE::validate_byte_slice()
must return an error if the given byte slice cannot be used in its entirety. - The impl of
VarULE::from_byte_slice_unchecked()
must produce a reference to the same underlying data assuming that the given bytes previously passed validation. - All other methods must be left with their default impl, or else implemented according to their respective safety guidelines.
- Acknowledge the following note about the equality invariant.
If the ULE type is a struct only containing other ULE/VarULE types (or other types which satisfy invariants 1 and 2,
like [u8; N]
), invariants 1 and 2 can be achieved via #[repr(packed)]
or #[repr(transparent)]
.
Equality invariant
A non-safety invariant is that if Self
implements PartialEq
, the it must be logically
equivalent to byte equality on Self::as_byte_slice()
.
It may be necessary to introduce a “canonical form” of the ULE if logical equality does not
equal byte equality. In such a case, Self::validate_byte_slice()
should return an error
for any values that are not in canonical form. For example, the decimal strings “1.23e4” and
“12.3e3” are logically equal, but not byte-for-byte equal, so we could define a canonical form
where only a single digit is allowed before .
.
Failure to follow this invariant will cause surprising behavior in PartialEq
, which may
result in unpredictable operations on ZeroVec
, VarZeroVec
, and ZeroMap
.
Required Methods
fn validate_byte_slice(_bytes: &[u8]) -> Result<(), ZeroVecError>
fn validate_byte_slice(_bytes: &[u8]) -> Result<(), ZeroVecError>
Validates a byte slice, &[u8]
.
If Self
is not well-defined for all possible bit values, the bytes should be validated.
If the bytes can be transmuted, in their entirety, to a valid &Self
, then Ok
should
be returned; otherwise, Self::Error
should be returned.
Takes a byte slice, &[u8]
, and return it as &Self
with the same lifetime, assuming
that this byte slice has previously been run through Self::parse_byte_slice()
with
success.
Safety
Callers
Callers of this method must take care to ensure that bytes
was previously passed through
Self::validate_byte_slice()
with success (and was not changed since then).
Implementors
Implementations of this method may call unsafe functions to cast the pointer to the correct type, assuming the “Callers” invariant above.
Safety checklist:
- This method must return the same result as
Self::parse_byte_slice()
. - This method must return a slice to the same region of memory as the argument.
Provided Methods
fn parse_byte_slice(bytes: &[u8]) -> Result<&Self, ZeroVecError>
fn parse_byte_slice(bytes: &[u8]) -> Result<&Self, ZeroVecError>
Parses a byte slice, &[u8]
, and return it as &Self
with the same lifetime.
If Self
is not well-defined for all possible bit values, the bytes should be validated,
and an error should be returned in the same cases as Self::validate_byte_slice()
.
The default implementation executes Self::validate_byte_slice()
followed by
Self::from_byte_slice_unchecked
.
Note: The following equality should hold: size_of_val(result) == size_of_val(bytes)
,
where result
is the successful return value of the method. This means that the return
value spans the entire byte slice.
Given &Self
, returns a &[u8]
with the same lifetime.
The default implementation performs a pointer cast to the same region of memory.
Safety
Implementations of this method should call potentially unsafe functions to cast the pointer to the correct type.
fn to_boxed(&self) -> Box<Self>ⓘNotable traits for Box<R, Global>impl<R> Read for Box<R, Global> where
R: Read + ?Sized, impl<W> Write for Box<W, Global> where
W: Write + ?Sized, impl<I, A> Iterator for Box<I, A> where
I: Iterator + ?Sized,
A: Allocator, type Item = <I as Iterator>::Item;impl<F, A> Future for Box<F, A> where
F: Future + Unpin + ?Sized,
A: Allocator + 'static, type Output = <F as Future>::Output;
fn to_boxed(&self) -> Box<Self>ⓘNotable traits for Box<R, Global>impl<R> Read for Box<R, Global> where
R: Read + ?Sized, impl<W> Write for Box<W, Global> where
W: Write + ?Sized, impl<I, A> Iterator for Box<I, A> where
I: Iterator + ?Sized,
A: Allocator, type Item = <I as Iterator>::Item;impl<F, A> Future for Box<F, A> where
F: Future + Unpin + ?Sized,
A: Allocator + 'static, type Output = <F as Future>::Output;
R: Read + ?Sized, impl<W> Write for Box<W, Global> where
W: Write + ?Sized, impl<I, A> Iterator for Box<I, A> where
I: Iterator + ?Sized,
A: Allocator, type Item = <I as Iterator>::Item;impl<F, A> Future for Box<F, A> where
F: Future + Unpin + ?Sized,
A: Allocator + 'static, type Output = <F as Future>::Output;
Allocate on the heap as a Box<T>
Implementations on Foreign Types
sourceimpl VarULE for str
impl VarULE for str
sourceunsafe fn from_byte_slice_unchecked(bytes: &[u8]) -> &Self
unsafe fn from_byte_slice_unchecked(bytes: &[u8]) -> &Self
Invariant: must be safe to call when called on a slice that previously
succeeded with parse_byte_slice
fn validate_byte_slice(bytes: &[u8]) -> Result<(), ZeroVecError>
fn parse_byte_slice(bytes: &[u8]) -> Result<&Self, ZeroVecError>
sourceimpl<T> VarULE for [T] where
T: ULE,
impl<T> VarULE for [T] where
T: ULE,
Note: VarULE is well-defined for all [T]
where T: ULE
, but ZeroSlice
is more ergonomic
when T
is a low-level ULE type. For example:
// OK: [u8] is a useful type
let _: VarZeroVec<[u8]> = unimplemented!();
// Technically works, but [u32::ULE] is not very useful
let _: VarZeroVec<[<u32 as AsULE>::ULE]> = unimplemented!();
// Better: ZeroSlice<u32>
let _: VarZeroVec<ZeroSlice<u32>> = unimplemented!();