[][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:

  • A1 - 1B aligned aka unaligned
  • A2 - 2B aligned
  • A4 - 4B aligned
  • A8 - 8B aligned

As a type parameter the alignment is known statically at compile time. This allows eliding runtime checks.

You can convert AlignedSlices 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:

  1. 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.
  2. 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 Alignment::ALIGNMENT.

AlignedSlice

A byte array, but with a compile-time guaranteed minimum alignment

Misaligned

Error returned by TryAsAligned::try_as_aligned and TryAsAlignedMut::try_as_aligned_mut when the passed in slice isn't appropriately aligned.

Traits

AlignedTo

This is a promise that the type is aligned as described by A.

Alignment

A trait for our alignment structs A1, A2, A4 and A8.

AsAligned

Allows narrowing the alignment of a &AlignedSlice

AsAlignedMut

Allows narrowing the alignment of a &mut AlignedSlice

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 AlignedOffset by rounding-up idx until it's a multiple of A::ALIGNMENT.

alloc_aligned

Allocate a new boxed AlignedSlice.

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 AlignedSlice with the given alignment.

read_to_slice

Read the contents of the Read into an AlignedSlice