vtable add support for field offset in the vtable

This commit is contained in:
Olivier Goffart 2020-05-16 23:47:30 +02:00
parent 751a3fbe59
commit 5a9cbaae66
7 changed files with 100 additions and 46 deletions

View file

@ -11,4 +11,4 @@ syn = { version = "1.0", features = ["full"] }
quote = "1.0"
proc-macro2 = "1.0"
vtable-macro = { path="./macro" }
const-field-offset = { path="../const-field-offset" }

View file

@ -344,7 +344,6 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
});
vtable_ctor.push(quote!(#ident: {
#[allow(unused_parens)]
#sig_extern {
// This is safe since the self must be a instance of our type
#[allow(unused)]
@ -364,7 +363,6 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
}
} else {
// associated constant
let ty = &field.ty;
let generated_trait_assoc_const =
generated_trait_assoc_const.get_or_insert_with(|| ItemTrait {
@ -373,17 +371,79 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
items: vec![],
..generated_trait.clone()
});
let const_type = if let Some(o) = field
.attrs
.iter()
.position(|a| a.path.get_ident().map(|a| a == "offset").unwrap_or(false))
{
let a = field.attrs.remove(o);
let member_type = match parse2::<Type>(a.tokens) {
Err(e) => return e.to_compile_error().into(),
Ok(ty) => ty,
};
match &field.ty {
Type::Path(p) if p.path.get_ident().map(|i| i == "usize").unwrap_or(false) => {}
ty @ _ => {
return Error::new(
ty.span(),
"The type of an #[offset] member in the vtable must be 'usize'",
)
.to_compile_error()
.into()
}
}
// add `: Sized` to the trait in case it does not have it
if generated_trait_assoc_const.supertraits.is_empty() {
generated_trait_assoc_const.colon_token = Some(Default::default());
generated_trait_assoc_const.supertraits.push(parse2(quote!(Sized)).unwrap());
}
let offset_type =
parse2::<Type>(quote!(vtable::FieldOffset<Self, #member_type>)).unwrap();
vtable_ctor.push(quote!(#ident: T::#ident.get_byte_offset(),));
let vis = &field.vis;
generated_to_fn_trait.push(
parse2(quote! {
#vis fn #ident(&self) -> &#member_type {
unsafe {
&*(self.ptr.as_ptr().add(self.vtable.as_ref().#ident) as *const #member_type)
}
}
})
.unwrap(),
);
let ident_mut = quote::format_ident!("{}_mut", ident);
generated_to_fn_trait.push(
parse2(quote! {
#vis fn #ident_mut(&mut self) -> &mut #member_type {
unsafe {
&mut *(self.ptr.as_ptr().add(self.vtable.as_ref().#ident) as *mut #member_type)
}
}
})
.unwrap(),
);
offset_type
} else {
vtable_ctor.push(quote!(#ident: T::#ident,));
field.ty.clone()
};
generated_trait_assoc_const.items.push(TraitItem::Const(TraitItemConst {
attrs: field.attrs.clone(),
const_token: Default::default(),
ident: ident.clone(),
colon_token: Default::default(),
ty: ty.clone(),
ty: const_type,
default: None,
semi_token: Default::default(),
}));
vtable_ctor.push(quote!(#ident: T::#ident,));
};
}
@ -400,6 +460,7 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
#[macro_use]
/// This private module is generated by the `vtable` macro
mod #module_name {
#![allow(unused_parens)]
#[allow(unused)]
use super::*;
use ::vtable::*;

View file

@ -1,3 +1,4 @@
pub use const_field_offset::FieldOffset;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut, Drop};
use core::ptr::NonNull;

View file

@ -10,25 +10,28 @@ struct HelloVTable {
drop: fn(VRefMut<'_, HelloVTable>),
CONSTANT: usize,
#[offset(u32)]
SOME_OFFSET: usize,
}
#[derive(Debug)]
struct SomeStruct(u32);
#[derive(Debug, const_field_offset::FieldOffsets)]
#[repr(C)]
struct SomeStruct {
x: u32,
}
impl Hello for SomeStruct {
fn foo(&self, xx: u32) -> u32 {
println!("calling foo {} + {}", self.0, xx);
self.0 + xx
self.x + xx
}
fn foo_mut(&mut self, xx: u32) -> u32 {
println!("calling foo_mut {} + {}", self.0, xx);
self.0 += xx;
self.0
self.x += xx;
self.x
}
fn construct(init: u32) -> Self {
println!("calling Construct {}", init);
Self(init)
Self { x: init }
}
fn assoc() -> isize {
@ -37,6 +40,8 @@ impl Hello for SomeStruct {
}
impl HelloConsts for SomeStruct {
const CONSTANT: usize = 88;
const SOME_OFFSET: const_field_offset::FieldOffset<SomeStruct, u32> =
SomeStruct::field_offsets().x;
}
HelloVTable_static!(SomeStruct);
@ -53,11 +58,12 @@ fn test() {
assert_eq!(bx.foo(2), 97);
assert_eq!(bx.get_vtable().CONSTANT, 88);
let bx2 = VBox::<HelloVTable>::new(SomeStruct(23));
let bx2 = VBox::<HelloVTable>::new(SomeStruct { x: 23 });
assert_eq!(bx2.foo(3), 26);
assert_eq!(bx2.get_vtable().CONSTANT, 88);
assert_eq!(*bx2.SOME_OFFSET(), 23);
let mut hello = SomeStruct(44);
let mut hello = SomeStruct { x: 44 };
{
let xref = VRef::<HelloVTable>::new(&hello);
assert_eq!(xref.foo(0), 44);
@ -65,7 +71,9 @@ fn test() {
{
let mut xref = VRefMut::<HelloVTable>::new(&mut hello);
assert_eq!(xref.foo_mut(2), 46);
assert_eq!(*xref.SOME_OFFSET(), 46);
*xref.SOME_OFFSET_mut() = 3;
let xref2 = xref.borrow();
assert_eq!(xref2.foo(1), 47);
assert_eq!(xref2.foo(1), 4);
}
}

View file

@ -74,7 +74,8 @@ pub struct ItemVTable {
/// offset in bytes fromthe *const ItemImpl.
/// isize::MAX means None
#[allow(non_upper_case_globals)]
pub cached_rendering_data_offset: isize,
#[offset(CachedRenderingData)]
pub cached_rendering_data_offset: usize,
/// Return a rendering info
pub rendering_info: extern "C" fn(VRef<'_, ItemVTable>) -> RenderingInfo,
@ -112,27 +113,6 @@ pub type MouseEvent = ();
/* -- Safe wrappers*/
/*trait Item {
fn geometry(&self) -> ();
fn cached_rendering_data(&self) -> &CachedRenderingData;
fn cached_rendering_data_mut(&mut self) -> &mut CachedRenderingData;
fn rendering_info(&self) -> CachedRenderingData;
}*/
pub fn cached_rendering_data(item: VRef<'_, ItemVTable>) -> &CachedRenderingData {
unsafe {
&*(item.as_ptr().offset(item.get_vtable().cached_rendering_data_offset)
as *const CachedRenderingData)
}
}
pub fn cached_rendering_data_mut(item: VRefMut<'_, ItemVTable>) -> &mut CachedRenderingData {
unsafe {
&mut *(item.as_ptr().offset(item.get_vtable().cached_rendering_data_offset)
as *mut CachedRenderingData)
}
}
/// Visit each items recursively
///
/// The state parametter returned by the visitor is passed to each children.

View file

@ -32,8 +32,10 @@ impl Item for Rectangle {
}
impl ItemConsts for Rectangle {
const cached_rendering_data_offset: isize =
Rectangle::field_offsets().cached_rendering_data.get_byte_offset() as isize;
const cached_rendering_data_offset: const_field_offset::FieldOffset<
Rectangle,
CachedRenderingData,
> = Rectangle::field_offsets().cached_rendering_data;
}
// FIXME: remove (or use the libc one)
@ -79,8 +81,10 @@ impl Item for Image {
}
impl ItemConsts for Image {
const cached_rendering_data_offset: isize =
Image::field_offsets().cached_rendering_data.get_byte_offset() as isize;
const cached_rendering_data_offset: const_field_offset::FieldOffset<
Image,
CachedRenderingData,
> = Image::field_offsets().cached_rendering_data;
}
#[no_mangle]

View file

@ -12,7 +12,7 @@ pub(crate) fn update_item_rendering_data<Backend: GraphicsBackend>(
println!("Caching ... {:?}", item_rendering_info);
let rendering_data = super::abi::datastructures::cached_rendering_data_mut(item.borrow_mut());
let rendering_data = item.cached_rendering_data_offset_mut();
match item_rendering_info {
RenderingInfo::Rectangle(_x, _y, width, height, color) => {
@ -85,7 +85,7 @@ pub(crate) fn render_component_items<Backend: GraphicsBackend>(
_ => {}
}
let cached_rendering_data = super::abi::datastructures::cached_rendering_data(item);
let cached_rendering_data = item.cached_rendering_data_offset();
if cached_rendering_data.cache_ok {
println!(
"Rendering... {:?} from cache {}",