macro_rules! unsafe_struct_field_offsets {
    (
        $( Self = $Self:ty, )?
        alignment =  $alignment:ty,
        $( usize_offsets = $usize_offsets:ident,)?
        $( impl_GetFieldOffset = $impl_gfo:ident,)?

        $(#[$impl_attr:meta])*
        impl[ $($impl_params:tt)* ] $self:ty
        $(where [ $($where:tt)* ])?
        {
            $(
                $(#[$const_attr:meta])*
                $( pub $(($($inn:tt)*))? )?
                const $offset:ident, $field_ident:tt: $field_ty:ty;
            )*
        }
    ) => { ... };
}
Expand description

Declares a sequence of associated constants with the offsets of the listed fields, and implements the GetFieldOffset trait.

Safety

Callers must ensure that:

  • The type that the offsets are for is a #[repr(C)] struct.

  • All field types are listed,in declaration order.

  • The alignment parameter is Unaligned if the struct is #[repr(C,packed)], and Aligned if it’s not.

Parameters

Self

The optional Self parameter overrides which struct the FieldOffset constants (that this outputs) are an offset inside of.

Note that passing the this parameter unconditionally causes the type not to implement GetFieldOffset.

alignment

The alignment parameter can be either Aligned or Unaligned, and describes whether the fields are aligned or potentially unaligned, changing how fields are accessed in FieldOffset methods.

usize_offsets

The optional usize_offsets parameter determines whether type of the generated constants is FieldOffset or usize.

The valid values for this parameter are:

  • (not passing this parameter): The constants are FieldOffsets.
  • false: The constants are FieldOffsets.
  • true: The constants are usizes.

impl_GetFieldOffset

The optional impl_GetFieldOffset parameter determines whether $self implements the GetFieldOffset trait, which allows getting the FieldOffset for each field using the OFF, off, PUB_OFF, and pub_off macros.

The valid values for this parameter are:

Note that passing the Self parameter unconditionally causes the type not to implement GetFieldOffset.

Examples

Syntax example

This demonstrates the macro being used with all of the syntax.

use repr_offset::{unsafe_struct_field_offsets, Aligned};

#[repr(C)]
struct Bar<T: Copy, U>(T,U)
where U: Clone;

unsafe_struct_field_offsets!{
    // Optional parameter.
    // Generic parameters from the impl block can be used here.
    Self = Bar<T, U>,

    alignment =  Aligned,

    // Optional parameter.
    usize_offsets = false,

    // Optional parameter.
    impl_GetFieldOffset = false,

    impl[T: Copy, U] Bar<T, U>
    where[ U: Clone ]
    {
        pub const OFFSET_0, 0: T;
        pub const OFFSET_1, 1: U;
    }
}

Unaligned struct example

This example demonstrates how you can replace fields in a packed struct, as well as getting a raw pointer to a field, using both FieldOffset methods, and extension traits from the ext module

use repr_offset::{
    unsafe_struct_field_offsets,
    off,
    ROExtAcc, ROExtOps, Unaligned,
};

// Replacing the table field
{
    let mut bar = Bar{ mugs: 3, bottles: 5, table: "wooden".to_string() };
    
    assert_eq!( replace_table_a(&mut bar, "metallic".to_string()), "wooden".to_string());
    assert_eq!( replace_table_b(&mut bar, "granite".to_string()), "metallic".to_string());
    assert_eq!( replace_table_b(&mut bar, "carbonite".to_string()), "granite".to_string());
     
    fn replace_table_a(this: &mut Bar, replacement: String)-> String{
        Bar::OFFSET_TABLE.replace_mut(this, replacement)
    }
    
    fn replace_table_b(this: &mut Bar, replacement: String)-> String{
        this.f_replace(off!(table), replacement)
    }
}

// Getting raw pointers to fields
unsafe {
    let bar = Bar{ mugs: 3, bottles: 5, table: "wooden".to_string() };

    assert_eq!(get_mugs_ptr(&bar).read_unaligned(), 3);

    assert_eq!(get_bottles_ptr(&bar).read_unaligned(), 5);

    fn get_mugs_ptr(this: &Bar) -> *const u32 {
        Bar::OFFSET_MUGS.get_ptr(this)
    }
    
    fn get_bottles_ptr(this: &Bar) -> *const u16 {
        this.f_get_ptr(off!(bottles))
    }
}



#[repr(C,packed)]
struct Bar{
    mugs: u32,
    bottles: u16,
    table: String,
}

unsafe_struct_field_offsets!{
    alignment =  Unaligned,

    impl[] Bar {
        pub const OFFSET_MUGS, mugs: u32;
        pub const OFFSET_BOTTLES, bottles: u16;
        pub const OFFSET_TABLE, table: String;
    }
}