Derive Macro repr_offset::ReprOffset

source ·
#[derive(ReprOffset)]
{
    // Attributes available to this derive:
    #[roff]
}
Available on crate feature derive only.
Expand description

The ReprOffset derive macro defines associated constants with the offset of every field, and implements the GetFieldOffset trait,

The ReprOffset derive is from the repr_offset_derive crate, and is re-exported by this crate when the “derive” feature is enabled (it’s disabled by default).

Adding the “derive” feature to the Cargo.toml file:

repr_offset = { version = "0.2", features = ["derive"] }

Generated items

By default, this derive macro generates:

  • FieldOffset inherent associated constants, with the same privacy as the field, named OFFSET_<field_name> (where <field_name> is the name of the field uppercased).

  • Impls of the GetFieldOffset trait for each field.

  • An impl of the ImplsGetFieldOffset marker trait.

Valid Representation Attributes

These are the valid representation attributes:

  • #[repr(C)]

  • #[repr(transparent)]: This is treated the same as #[repr(C)].

  • #[repr(C, align(1000))]

  • #[repr(C, packed)]

  • #[repr(C, packed(1000))]

One of those must be used,otherwise the derive macro will error.

Container Attributes

#[roff(usize_offsets)]

Changes the generated offset associated constants from FieldOffset to usize.

Example:

use repr_offset::{
    ReprOffset,
    off,
    Aligned, FieldOffset,
};

 

#[repr(C)]
#[derive(ReprOffset)]
#[roff(usize_offsets)]
struct Foo{
    x: u8,
    y: u64,
    z: String,
}

let _: usize = Foo::OFFSET_X;
let _: usize = Foo::OFFSET_Y;
let _: usize = Foo::OFFSET_Z;

// You can still get the `FieldOffset` of fields using the `GetFieldOffset` impls for `Foo`,
// in this case through the `off` macro.
let _: FieldOffset<Foo, u8, Aligned> = off!(x);
let _: FieldOffset<Foo, u64, Aligned> = off!(y);
let _: FieldOffset<Foo, String, Aligned> = off!(z);

#[roff(bound = "T: Foo")]

This attribute adds a constraint to the generated impl block that defines the field offset constants.

Examples:

  • #[roff(bound = "T: 'a")]

  • #[roff(bound = "U: Foo")]

#[roff(impl_GetFieldOffset = true)]

Chooses whether GetFieldOffset is implemented for all the fields or none of them, if true then GetFieldOffset is implemented for all the fields, if false then GetFieldOffset is implemented for none of the fields.

Field attributes

#[roff(offset = "fooo")]

Changes the name of the generated offset for the field.

Example:

use repr_offset::{
    ReprOffset,
    off,
    Aligned, FieldOffset,
};

#[repr(C)]
#[derive(ReprOffset)]
struct Foo{
    x: u8,
    y: u64,
    #[roff(offset = "this_is_lowercase")]
    z: String,
}

let _: FieldOffset<Foo, u8, Aligned> = Foo::OFFSET_X;
let _: FieldOffset<Foo, u64, Aligned> = Foo::OFFSET_Y;
let _: FieldOffset<Foo, String, Aligned> = Foo::this_is_lowercase;

// The `off` macro can still access the offset for the `z` field with its original name.
let _: FieldOffset<Foo, u8, Aligned> = off!(x);
let _: FieldOffset<Foo, u64, Aligned> = off!(y);
let _: FieldOffset<Foo, String, Aligned> = off!(z);

Container or Field attributes

#[roff(offset_prefix = "FOO" )]

Changes the prefix of the name of the generated offset(s) for the field(s).

When used on the type, it uses this as the default prefix of all the offset constants for the fields.

When used on a field, it overrides the prefix of the name of the offset constant for the field.

Example:

use repr_offset::{
    ReprOffset,
    off,
    FieldOffset, Unaligned,
};

#[repr(C, packed)]
#[derive(ReprOffset)]
#[roff(offset_prefix = "OFF_")]
struct Foo{
    x: u8,
    y: u64,
    // This overrides the `offset_prefix` attribute above.
    #[roff(offset_prefix = "OOO_")]
    z: String,
}

let _: FieldOffset<Foo, u8, Unaligned> = Foo::OFF_X;
let _: FieldOffset<Foo, u64, Unaligned> = Foo::OFF_Y;
let _: FieldOffset<Foo, String, Unaligned> = Foo::OOO_Z;

// The `off` macro gets the `FieldOffset` using the `GetFieldOffset` impls for `Foo`.
let _: FieldOffset<Foo, u8, Unaligned> = off!(x);
let _: FieldOffset<Foo, u64, Unaligned> = off!(y);
let _: FieldOffset<Foo, String, Unaligned> = off!(z);

Examples

Out parameters

This example demonstrates how you can write each field individually to an out parameter (a way that complex values can be returned in the C language).

use repr_offset::{
    ReprOffset,
    off,
    FieldOffset, ROExtRawMutOps, Unaligned,
};

use std::ffi::{CStr, CString};
use std::os::raw::c_char;

fn main(){
    let mut results = Vec::<Fields>::with_capacity(3);

    unsafe{
        let ptr = results.as_mut_ptr();
        assert_eq!( write_fields(10, 2, ptr.offset(0)), ErrorCode::Ok );
        assert_eq!( write_fields(22, 3, ptr.offset(1)), ErrorCode::Ok );
        assert_eq!( write_fields(1, 0, ptr.offset(2)), ErrorCode::DivisionByZero );
        results.set_len(2);

        let cstr_as_str = |ptr| CStr::from_ptr(ptr).to_str().unwrap();

        assert_eq!( results[0].divided, 5 );
        assert_eq!( cstr_as_str(results[0].string), "5" );

        assert_eq!( results[1].divided, 7 );
        assert_eq!( cstr_as_str(results[1].string), "7" );
    }
}

#[no_mangle]
pub unsafe extern fn write_fields(left: u32, right: u32, out: *mut Fields) -> ErrorCode {
    let divided = match left.checked_div(right) {
        Some(x) => x,
        None => return ErrorCode::DivisionByZero,
    };

    let written_string= CString::new(divided.to_string())
        .expect("There shouldn't be a nul byte in the string returned by `u32::to_string`")
        .into_raw();

    unsafe{
        Fields::OFFSET_DIVIDED.write(out, divided);

        // Another way to write to a field,
        // using the `ROExtRawMutOps` extension trait, and `off` macro.
        out.f_write(off!(string), written_string);
    }

    ErrorCode::Ok
}

#[no_mangle]
pub unsafe extern fn cstring_free(ptr: *mut c_char) {
    drop(CString::from_raw(ptr));
}

#[repr(C)]
#[derive(Debug, ReprOffset)]
pub struct Fields{
    divided: u32,
    string: *mut c_char,
}

impl Drop for Fields {
    fn drop(&mut self) {
        unsafe{ cstring_free(self.string); }
    }
}

#[derive(Debug, PartialEq)]
#[repr(u8)]
pub enum ErrorCode{
    Ok,
    DivisionByZero,
}