no_std_compat::mem

Macro offset_of

1.77.0 · Source
pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) {
    ...
}
Expand description

Expands to the offset in bytes of a field from the beginning of the given type.

Structs, enums, unions and tuples are supported.

Nested field accesses may be used, but not array indexes.

If the nightly-only feature offset_of_enum is enabled, variants may be traversed as if they were fields. Variants themselves do not have an offset.

Visibility is respected - all types and fields must be visible to the call site:

mod nested {
    #[repr(C)]
    pub struct Struct {
        private: u8,
    }
}

// assert_eq!(mem::offset_of!(nested::Struct, private), 0);
// ^^^ error[E0616]: field `private` of struct `Struct` is private

Only Sized fields are supported, but the container may be unsized:

#[repr(C)]
pub struct Struct {
    a: u8,
    b: [u8],
}

assert_eq!(mem::offset_of!(Struct, a), 0); // OK
// assert_eq!(mem::offset_of!(Struct, b), 1);
// ^^^ error[E0277]: doesn't have a size known at compile-time

Note that type layout is, in general, subject to change and platform-specific. If layout stability is required, consider using an explicit repr attribute.

Rust guarantees that the offset of a given field within a given type will not change over the lifetime of the program. However, two different compilations of the same program may result in different layouts. Also, even within a single program execution, no guarantees are made about types which are similar but not identical, e.g.:

struct Wrapper<T, U>(T, U);

type A = Wrapper<u8, u8>;
type B = Wrapper<u8, i8>;

// Not necessarily identical even though `u8` and `i8` have the same layout!
// assert_eq!(mem::offset_of!(A, 1), mem::offset_of!(B, 1));

#[repr(transparent)]
struct U8(u8);

type C = Wrapper<u8, U8>;

// Not necessarily identical even though `u8` and `U8` have the same layout!
// assert_eq!(mem::offset_of!(A, 1), mem::offset_of!(C, 1));

struct Empty<T>(core::marker::PhantomData<T>);

// Not necessarily identical even though `PhantomData` always has the same layout!
// assert_eq!(mem::offset_of!(Empty<u8>, 0), mem::offset_of!(Empty<i8>, 0));

§Examples

#![feature(offset_of_enum)]

use std::mem;
#[repr(C)]
struct FieldStruct {
    first: u8,
    second: u16,
    third: u8
}

assert_eq!(mem::offset_of!(FieldStruct, first), 0);
assert_eq!(mem::offset_of!(FieldStruct, second), 2);
assert_eq!(mem::offset_of!(FieldStruct, third), 4);

#[repr(C)]
struct NestedA {
    b: NestedB
}

#[repr(C)]
struct NestedB(u8);

assert_eq!(mem::offset_of!(NestedA, b.0), 0);

#[repr(u8)]
enum Enum {
    A(u8, u16),
    B { one: u8, two: u16 },
}

assert_eq!(mem::offset_of!(Enum, A.0), 1);
assert_eq!(mem::offset_of!(Enum, B.two), 2);

assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0);