#assert #offset #sizeof #layout

macro assert_layout

Assert struct layouts, including field sizes and offsets

1 unstable release

Uses new Rust 2024

0.0.1 Apr 3, 2025

#10 in #sizeof

Download history 132/week @ 2025-04-01 16/week @ 2025-04-08

148 downloads per month
Used in cuisiner

MIT/Apache

30KB
635 lines

assert_layout

Assert struct layouts, including field sizes and offsets.

assert_layout provides a single proc-macro which will perform compile-time assertions for certain qualities of a struct. In addition to field size and offset, it's also possible to provide concrete types for generics and assert that the layout still holds.

Overview

Struct containers can use the size assertion to assert the size of the struct.

use assert_layout::assert_layout;

#[assert_layout(size = 1)]
#[repr(packed)]
struct MyStruct {
    field: u8,
}

Similarly, each field can use the size and offset assertions.

use assert_layout::assert_layout;

#[assert_layout(size = 5)]
#[repr(packed)]
struct MyStruct {
    #[assert_layout(offset = 0, size = 1)]
    field: u8,

    #[assert_layout(offset = 2, size = 4)]
    another_field: f32,
}

Generics

If the struct contains generics, concrete types can be provided for assertions using generics. For instance, the following assertion would expand with T = u32.

use assert_layout::assert_layout;

#[assert_layout(size = 4, generics = "u32")]
#[repr(packed)]
struct MyStruct<T> {
    #[assert_layout(offset = 0, size = 4)]
    field: T,
}

Multiple generic parameters can by provided with commas between them, in addition to consts (in the same manner as MyStruct<...>).

use assert_layout::assert_layout;

#[assert_layout(size = 64, generics = "8, f64")]
#[repr(packed)]
struct MyStruct<const N: usize, T> {
    #[assert_layout(offset = 0, size = 64)]
    field: [T; N],
}

The generics attribute can be provided multiple times in order to assert different combinations of generics.

use assert_layout::assert_layout;

#[assert_layout(size = 12, generics = "u32, u64", generics = "i32, i64")]
#[repr(packed)]
struct MyStruct<T, U> {
    #[assert_layout(offset = 0, size = 4)]
    field: T,

    #[assert_layout(offset = 4, size = 8)]
    another_field: U,
}

Namespaces

Sometimes generic combinations will not be compatible with each other, so namespaces can be used to isolate the assertions. A namespace is created using namespace(...), where namespace is a unique identifier for the namepsace, and the previously described assertions (generics, offset, size) are within the brackets. Everything within the namespace will be asserted in isolation.

use assert_layout::assert_layout;

#[assert_layout(little(size = 4, generics = "u32"), big(size = 8, generics = "u64"))]
#[repr(packed)]
struct MyStruct<T> {
    #[assert_layout(little(offset = 0, size = 4), big(offset = 0, size = 8))]
    field: T,
}

If there are common assertions between the namespaces (such as offset = 0 above), they can be omitted from the namespace and asserted at the top level.

use assert_layout::assert_layout;

#[assert_layout(
    generics = "u32",
    generics = "u64",
    little(size = 4, generics = "u32"),
    big(size = 8, generics = "u64")
)]
#[repr(packed)]
struct MyStruct<T> {
    #[assert_layout(offset = 0, little(size = 4), big(size = 8))]
    field: T,
}

Dependencies

~190–620KB
~15K SLoC