Some improvement in ConstFieldOffset trait

This commit is contained in:
Olivier Goffart 2020-06-25 18:23:08 +02:00
parent 812b08b50c
commit 40f4265071
3 changed files with 73 additions and 58 deletions

View file

@ -32,6 +32,22 @@ assert_eq!(FOO, 4);
// const FOO : usize = memofsets::offsetof!(Foo, field_2); // const FOO : usize = memofsets::offsetof!(Foo, field_2);
``` ```
In addition, the macro laso create a module `{ClassName}_field_offsets` which contains
zero-sized type that implement the `const_field_offset::ConstFieldOffset` trait
```rust
use const_field_offset::{FieldOffsets, FieldOffset, ConstFieldOffset};
#[repr(C)]
#[derive(FieldOffsets)]
struct Foo {
field_1 : u8,
field_2 : u32,
}
const FOO : FieldOffset<Foo, u32> = Foo_field_offsets::field_2::OFFSET;
assert_eq!(FOO.get_byte_offset(), 4);
```
## limitations ## limitations
Only work with named #[repr(C)] structures. Only work with named #[repr(C)] structures.
@ -152,21 +168,6 @@ pub fn const_field_offset(input: TokenStream) -> TokenStream {
Visibility::Inherited => quote!(pub(super)), Visibility::Inherited => quote!(pub(super)),
}); });
/*let mut offset = quote!(0);
let mut offsets = vec![];
for ty in &types {
let len_rounded_up = quote! {
let len = #offset;
let align = ::core::mem::align_of::<#ty>();
let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
};
offsets.push(quote! { { #len_rounded_up len_rounded_up } });
offset = quote!({
#len_rounded_up
len_rounded_up + ::core::mem::size_of::<#ty>();
});
}*/
let doc = format!( let doc = format!(
"Helper struct containing the offsets of the fields of the struct `{}`", "Helper struct containing the offsets of the fields of the struct `{}`",
struct_name struct_name
@ -232,7 +233,9 @@ pub fn const_field_offset(input: TokenStream) -> TokenStream {
)* )*
} }
#( #(
impl #crate_::ConstFieldOffset<#struct_name, #types> for #module_name::#fields { impl #crate_::ConstFieldOffset for #module_name::#fields {
type Container = #struct_name;
type Field = #types;
type PinFlag = #pin_flag; type PinFlag = #pin_flag;
const OFFSET : #crate_::FieldOffset<#struct_name, #types, Self::PinFlag> const OFFSET : #crate_::FieldOffset<#struct_name, #types, Self::PinFlag>
= #struct_name::field_offsets().#fields; = #struct_name::field_offsets().#fields;
@ -242,13 +245,14 @@ pub fn const_field_offset(input: TokenStream) -> TokenStream {
#struct_name::field_offsets().#fields #struct_name::field_offsets().#fields
} }
} }
/*impl<Other : #crate_::ConstFieldOffset<#types, >> ::core::ops::Add<Other> for #module_name::#fields { impl<Other> ::core::ops::Add<Other> for #module_name::#fields
where Other : #crate_::ConstFieldOffset<Container = #types>
{
type Output = #crate_::ConstFieldOffsetSum<Self, Other>; type Output = #crate_::ConstFieldOffsetSum<Self, Other>;
#[inline]
fn add(self, other: Other) -> Self::Output { fn add(self, other: Other) -> Self::Output {
#crate_::ConstFieldOffsetSum::new(self, other) #crate_::ConstFieldOffsetSum(self, other)
}
} }
}*/
)* )*
}; };

View file

@ -414,72 +414,67 @@ mod tests {
} }
} }
pub trait ConstFieldOffset<T, U>: Copy { pub trait ConstFieldOffset: Copy {
/// The type of the container
type Container;
/// The type of the field
type Field;
/// Can be PinnedFlag or NotPinnedFlag /// Can be PinnedFlag or NotPinnedFlag
type PinFlag; type PinFlag;
const OFFSET: FieldOffset<T, U, Self::PinFlag>; const OFFSET: FieldOffset<Self::Container, Self::Field, Self::PinFlag>;
fn as_field_offset(self) -> FieldOffset<T, U, Self::PinFlag> { fn as_field_offset(self) -> FieldOffset<Self::Container, Self::Field, Self::PinFlag> {
Self::OFFSET Self::OFFSET
} }
fn get_byte_offset(self) -> usize { fn get_byte_offset(self) -> usize {
Self::OFFSET.get_byte_offset() Self::OFFSET.get_byte_offset()
} }
fn apply(self, x: &T) -> &U { fn apply(self, x: &Self::Container) -> &Self::Field {
Self::OFFSET.apply(x) Self::OFFSET.apply(x)
} }
fn apply_mut(self, x: &mut T) -> &mut U { fn apply_mut(self, x: &mut Self::Container) -> &mut Self::Field {
Self::OFFSET.apply_mut(x) Self::OFFSET.apply_mut(x)
} }
fn apply_pin<'a>(self, x: Pin<&'a T>) -> Pin<&'a U> fn apply_pin<'a>(self, x: Pin<&'a Self::Container>) -> Pin<&'a Self::Field>
where where
Self: ConstFieldOffset<T, U, PinFlag = PinnedFlag>, Self: ConstFieldOffset<PinFlag = PinnedFlag>,
{ {
Self::OFFSET.apply_pin(x) Self::OFFSET.apply_pin(x)
} }
fn apply_pin_mut<'a>(self, x: Pin<&'a mut T>) -> Pin<&'a mut U> fn apply_pin_mut<'a>(self, x: Pin<&'a mut Self::Container>) -> Pin<&'a mut Self::Field>
where where
Self: ConstFieldOffset<T, U, PinFlag = PinnedFlag>, Self: ConstFieldOffset<PinFlag = PinnedFlag>,
{ {
Self::OFFSET.apply_pin_mut(x) Self::OFFSET.apply_pin_mut(x)
} }
} }
pub struct ConstFieldOffsetSum<T, U, V, A: ConstFieldOffset<T, U>, B: ConstFieldOffset<U, V>>( #[derive(Copy, Clone)]
A, pub struct ConstFieldOffsetSum<A: ConstFieldOffset, B: ConstFieldOffset>(pub A, pub B);
B,
PhantomData<(FieldOffset<T, U>, FieldOffset<U, V>)>,
);
impl<T, U, V, A: ConstFieldOffset<T, U>, B: ConstFieldOffset<U, V>> impl<A: ConstFieldOffset, B: ConstFieldOffset> ConstFieldOffset for ConstFieldOffsetSum<A, B>
ConstFieldOffsetSum<T, U, V, A, B>
{
pub fn new(a: A, b: B) -> Self {
Self(a, b, PhantomData)
}
}
impl<T, U, V, A: ConstFieldOffset<T, U>, B: ConstFieldOffset<U, V>> Copy
for ConstFieldOffsetSum<T, U, V, A, B>
{
}
impl<T, U, V, A: ConstFieldOffset<T, U>, B: ConstFieldOffset<U, V>> Clone
for ConstFieldOffsetSum<T, U, V, A, B>
{
fn clone(&self) -> Self {
*self
}
}
impl<T, U, V, A: ConstFieldOffset<T, U>, B: ConstFieldOffset<U, V>> ConstFieldOffset<T, V>
for ConstFieldOffsetSum<T, U, V, A, B>
where where
A: ConstFieldOffset<Field = B::Container>,
(A::PinFlag, B::PinFlag): internal::CombineFlag, (A::PinFlag, B::PinFlag): internal::CombineFlag,
{ {
type Container = A::Container;
type Field = B::Field;
type PinFlag = <(A::PinFlag, B::PinFlag) as internal::CombineFlag>::Output; type PinFlag = <(A::PinFlag, B::PinFlag) as internal::CombineFlag>::Output;
const OFFSET: FieldOffset<T, V, Self::PinFlag> = const OFFSET: FieldOffset<Self::Container, Self::Field, Self::PinFlag> =
FieldOffset(A::OFFSET.get_byte_offset() + B::OFFSET.get_byte_offset(), PhantomData); FieldOffset(A::OFFSET.get_byte_offset() + B::OFFSET.get_byte_offset(), PhantomData);
} }
impl<A: ConstFieldOffset, B: ConstFieldOffset, Other> ::core::ops::Add<Other>
for ConstFieldOffsetSum<A, B>
where
Self: ConstFieldOffset,
Other: ConstFieldOffset<Container = <Self as ConstFieldOffset>::Field>,
{
type Output = ConstFieldOffsetSum<Self, Other>;
fn add(self, other: Other) -> Self::Output {
ConstFieldOffsetSum(self, other)
}
}

View file

@ -18,6 +18,12 @@ struct MyStruct2 {
v: u32, v: u32,
} }
#[derive(FieldOffsets)]
#[repr(C)]
struct MyStruct3 {
ms2: MyStruct2,
}
const XX_CONST: usize = MyStruct2::field_offsets().xx.get_byte_offset(); const XX_CONST: usize = MyStruct2::field_offsets().xx.get_byte_offset();
static D_STATIC: usize = MyStruct::field_offsets().d.get_byte_offset(); static D_STATIC: usize = MyStruct::field_offsets().d.get_byte_offset();
@ -41,6 +47,16 @@ fn test() {
assert_eq!(offset_of!(MyStruct2, xx), MyStruct2_field_offsets::xx.get_byte_offset()); assert_eq!(offset_of!(MyStruct2, xx), MyStruct2_field_offsets::xx.get_byte_offset());
assert_eq!(offset_of!(MyStruct2, v), MyStruct2_field_offsets::v.get_byte_offset()); assert_eq!(offset_of!(MyStruct2, v), MyStruct2_field_offsets::v.get_byte_offset());
assert_eq!(offset_of!(MyStruct2, k), MyStruct2_field_offsets::k.get_byte_offset()); assert_eq!(offset_of!(MyStruct2, k), MyStruct2_field_offsets::k.get_byte_offset());
assert_eq!(core::mem::size_of::<MyStruct_field_offsets::c>(), 0);
let d_in_ms2 = MyStruct2_field_offsets::xx + MyStruct_field_offsets::d;
assert_eq!(offset_of!(MyStruct2, xx) + offset_of!(MyStruct, d), d_in_ms2.get_byte_offset());
assert_eq!(core::mem::size_of_val(&d_in_ms2), 0);
let a = MyStruct3_field_offsets::ms2 + d_in_ms2;
let b = MyStruct3_field_offsets::ms2 + MyStruct2_field_offsets::xx + MyStruct_field_offsets::d;
assert_eq!(a.get_byte_offset(), b.get_byte_offset());
} }
#[derive(FieldOffsets)] #[derive(FieldOffsets)]