1 unstable release

0.1.0 Jul 30, 2019

#20 in #repr

MIT license

14KB
244 lines

typelayout

Documentation

This is an experiment and a work-in-progress. The implementation of the repr(C) layout algorithm has not been thoroughly tested.

An experiment in embedding layout computations in the type system. This crate encodes the layout algorithm for repr(C) structs as a type-level computation, using frunk to compute over the type structure of structs and typenum to perform the calculations. The Layout trait is implemented for types that know their own size at type-checking time. For instance:

use typelayout::{ReprC, Generic, Layout};

#[derive(Generic)]
#[repr(C)]
pub struct Struct {
  first: u8,
  second: u32,
}

unsafe impl ReprC for Struct {}

assert_eq!(4, <Struct as Layout>::ALIGN);
assert_eq!(8, <Struct as Layout>::SIZE);

Layout Invariants

The purpose of this experiment is to express type layout invariants in the typesystem to enable safe abstractions for unsafe code that relies on layout.

For instance, mem::zeroed() is only valid to call on types for which a sequence of zeroed bits is a valid instance of the type. This function is unsafe to use to initialize structures that have padding bits, since rust is free to assume that padding bits have a particular value.

This library's NoPadding trait is implemented for types in which the #[repr(packed)] layout algorithm and #[repr(C)] algorithm produce layouts of exactly the same size. Using this, we implement a FromZeros trait for structs meeting the criteria of being safe to initialize with mem::zeroed:

unsafe impl<T: Generic + ReprC> FromZeros for T
where
  T: NoPadding,
  Struct<<Self as Generic>::Repr>: FromZeros,
{}

Given this implementation, this will compile:

use typelayout::{ReprC, Generic, Layout, FromZeros};

#[derive(Generic, Default, Debug, PartialEq)]
#[repr(C)]
pub struct Struct {
  first: u8,
  second: u8,
}

unsafe impl ReprC for Struct {}

assert_eq!(<Struct as Default>::default(), <Struct as FromZeros>::zeroed());

...but this will not:

use typelayout::{ReprC, Generic, Layout, FromZeros};

#[derive(Generic, Default, Debug, PartialEq)]
#[repr(C)]
pub struct Struct {
  first: u8,
  second: u16, // padding will be inserted between `first` and `second`
}

unsafe impl ReprC for Struct {}

// `Struct` does not implement `FromZeros`, because it has a padding byte!
assert_eq!(<Struct as Default>::default(), <Struct as FromZeros>::zeroed());

Dependencies

~2.5MB
~57K SLoC