pub unsafe trait ULE{
// Required method
fn validate_bytes(bytes: &[u8]) -> Result<(), UleError>;
// Provided methods
fn parse_bytes_to_slice(bytes: &[u8]) -> Result<&[Self], UleError> { ... }
unsafe fn slice_from_bytes_unchecked(bytes: &[u8]) -> &[Self] { ... }
fn slice_as_bytes(slice: &[Self]) -> &[u8] ⓘ { ... }
}
Expand description
Fixed-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_ule]
or
#[derive(ULE)]
instead.
Types that are not fixed-width can implement VarULE
instead.
“ULE” stands for “Unaligned little-endian”
§Safety
Safety checklist for ULE
:
- The type must not include any uninitialized or padding bytes.
- The type must have an alignment of 1 byte.
- The impl of
ULE::validate_bytes()
must return an error if the given byte slice would not represent a valid slice of this type. - The impl of
ULE::validate_bytes()
must return an error if the given byte slice cannot be used in its entirety (if its length is not a multiple ofsize_of::<Self>()
). - 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 types (or other types which satisfy invariants 1 and 2,
like [u8; N]
), invariants 1 and 2 can be achieved via #[repr(C, 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::slice_as_bytes()
.
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_bytes()
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§
sourcefn validate_bytes(bytes: &[u8]) -> Result<(), UleError>
fn validate_bytes(bytes: &[u8]) -> Result<(), UleError>
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 slice of Self
, then Ok
should be returned; otherwise, Err
should be returned.
Provided Methods§
sourcefn parse_bytes_to_slice(bytes: &[u8]) -> Result<&[Self], UleError>
fn parse_bytes_to_slice(bytes: &[u8]) -> Result<&[Self], UleError>
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_bytes()
.
The default implementation executes Self::validate_bytes()
followed by
Self::slice_from_bytes_unchecked
.
Note: The following equality should hold: bytes.len() % size_of::<Self>() == 0
. This
means that the returned slice can span the entire byte slice.
sourceunsafe fn slice_from_bytes_unchecked(bytes: &[u8]) -> &[Self]
unsafe fn slice_from_bytes_unchecked(bytes: &[u8]) -> &[Self]
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_bytes_to_slice()
with
success.
The default implementation performs a pointer cast to the same region of memory.
§Safety
§Callers
Callers of this method must take care to ensure that bytes
was previously passed through
Self::validate_bytes()
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.
Keep in mind that &[Self]
and &[u8]
may have different lengths.
Safety checklist:
- This method must return the same result as
Self::parse_bytes_to_slice()
. - This method must return a slice to the same region of memory as the argument.
sourcefn slice_as_bytes(slice: &[Self]) -> &[u8] ⓘ
fn slice_as_bytes(slice: &[Self]) -> &[u8] ⓘ
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.
Keep in mind that &[Self]
and &[u8]
may have different lengths.
Object Safety§
Implementations on Foreign Types§
Implementors§
impl ULE for CharULE
impl<A: ULE, B: ULE> ULE for Tuple2ULE<A, B>
impl<A: ULE, B: ULE, C: ULE> ULE for Tuple3ULE<A, B, C>
impl<A: ULE, B: ULE, C: ULE, D: ULE> ULE for Tuple4ULE<A, B, C, D>
impl<A: ULE, B: ULE, C: ULE, D: ULE, E: ULE> ULE for Tuple5ULE<A, B, C, D, E>
impl<A: ULE, B: ULE, C: ULE, D: ULE, E: ULE, F: ULE> ULE for Tuple6ULE<A, B, C, D, E, F>
impl<U: NicheBytes<N> + ULE, const N: usize> ULE for NichedOptionULE<U, N>
Safety for ULE trait
- NichedOptionULE does not have any padding bytes due to
#[repr(C)]
on a struct containing only ULE fields. NichedOptionULE either contains NICHE_BIT_PATTERN or valid U byte sequences. In both cases the data is initialized. - NichedOptionULE is aligned to 1 byte due to
#[repr(C, packed)]
on a struct containing only ULE fields. - validate_bytes impl returns an error if invalid bytes are encountered.
- validate_bytes impl returns an error there are extra bytes.
- The other ULE methods are left to their default impl.
- NichedOptionULE equality is based on ULE equality of the subfield, assuming that NicheBytes has been implemented correctly (this is a correctness but not a safety guarantee).
impl<U: ULE> ULE for OptionULE<U>
zeroed or valid-T byte sequences to fill it)