Module gvariant::aligned_bytes
source · [−]Expand description
Byte slices with statically guaranteed alignment
The gvariant crates operates by reinterpreting byte buffers as a Rust type. For these casts to be valid the alignment of the underlying data must be sufficient for the target type. We don’t perform any of our own allocations, relying on data passed from the user, as a result proper alignment of byte buffers is the responsibility of the user.
This library defines a type AlignedSlice<A>
which
represents an aligned byte buffer aligned to the alignment given by A
. A
may be:
As a type parameter the alignment is known statically at compile time. This allows eliding runtime checks.
You can convert AlignedSlice
s to lower alignments infallibly and for
free (using AsAligned::as_aligned
and AsAlignedMut::as_aligned_mut
).
Going in the opposite direction and coming from a plain &[u8]
slice
requires runtime checks (TryAsAligned::try_as_aligned
and
TryAsAlignedMut::try_as_aligned_mut
) and may require copying the data
(copy_to_align
).
The AsAligned
trait is provided to make accepting any data of the
appropriate alignment convenient. For example: use a &impl AsAligned<A2>
parameter to accept any data with 2B or greater alignment.
AlignedBuf
is provided to make it easy and safe to create aligned
buffers. Example reading data from file into aligned buffer:
let mut buf = vec![];
let len = file.read(buf.as_mut())?;
let mut buf : AlignedBuf = buf.into();
Efficiency of statically known alignment
Every GVariant container type has alignment >= any of its children. This means that if a byte slice is aligned for the parent it will still be aligned when we access the children, so we only need to check the alignment once when constructing the buffer rather than on every access.
For example: The structure (nu)
(or (i16, u32)
in rust terms) has
alignment 4: So we create an AlignedSlice<A4>
containing the complete 8B
structure. The alignment is checked at run-time when we create the slice.
The i16
is extracted with data[..2]
, which still has type
AlignedSlice<A4>
. The conversion to AlignedSlice<A2>
as required by the
i16
’s doesn’t require any runtime checks.
Serialisation alignment vs. platform alignment requirements
Note: there are two related, but subtly different concepts of alignment at use in this library:
- The GVariant serialisation format has a concept of alignment of data types which informs where padding should be placed and affects the size of fixed size structures.
- There are the alignment requirements of the types we’re casting to that
Rust and the underlying platform requires of us when we cast. These are
the values that
std::mem::align_of<>()
returns.
These alignments are usually the same, but in some circumstances can differ.
For example: I believe that on 32-bit x86 align_of<u64>() == 4
- while of
course the serialisation format doesn’t depend on the platform in use. This
library assumes (and asserts in code) that the former alignment is always >=
the latter.
Structs
1-byte alignment e.g. no alignment
2-byte alignment
4-byte alignment
8-byte alignment
A buffer where the pointed to data is guaranteed to have 8B alignment. The length of the data needn’t be a multiple of 8.
Represents a usize that is some multiple of Alignment::ALIGNMENT
.
A byte array, but tagged with GVariant alignment
Error returned by TryAsAligned::try_as_aligned
and
TryAsAlignedMut::try_as_aligned_mut
when the passed in slice isn’t
appropriately aligned.
Traits
This is a promise that the type is aligned as described by A.
Allows narrowing the alignment of a &AlignedSlice
Allows narrowing the alignment of a &mut AlignedSlice
Allows widening the alignment by performing fallible runtime checks.
Allows widening the alignment by performing fallible runtime checks.
Functions
Construct an AlignedOffset
by rounding-up idx
until it’s a multiple of
A::ALIGNMENT
.
Aligns the given data to the alignment as given by the type parameter A.
Get a static reference to an empty AlignedSlice
with the given
alignment.