Macro sp_std::mem::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.

Enum variants may be traversed as if they were fields. Variants themselves do not have an offset.

However, on stable only a single field name is supported, which blocks the use of enum support.

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, offset_of_nested)]

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);