[−][src]Module gvariant::aligned_bytes
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.
alloc_aligned
is provided to make it easy and safe to create aligned
buffers. Example reading data from file into aligned buffer:
let mut buf = alloc_aligned::<A8>(4096); let len = file.read(buf.as_mut())?; let aligned_data = &buf[..len];
I've not yet implemented it, but it may become necessary to create an
equivalent to Vec<u8>
but for aligned memory. We'll see how we get on.
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
A1 | 1-byte alignment e.g. no alignment |
A2 | 2-byte alignment |
A4 | 4-byte alignment |
A8 | 8-byte alignment |
AlignedOffset | Represents a usize that is some multiple of |
AlignedSlice | A byte array, but with a compile-time guaranteed minimum alignment |
Misaligned | Error returned by |
Traits
AlignedTo | This is a promise that the type is aligned as described by A. |
Alignment | |
AsAligned | Allows narrowing the alignment of a |
AsAlignedMut | Allows narrowing the alignment of a |
TryAsAligned | Allows widening the alignment by performing fallible runtime checks. |
TryAsAlignedMut | Allows widening the alignment by performing fallible runtime checks. |
Functions
align_offset | Construct an |
alloc_aligned | Allocate a new boxed |
copy_to_align | Aligns the given data to the alignment as given by the type parameter A. |
empty_aligned | Get a static reference to an empty |
read_to_slice | Read the contents of the |