diff --git a/helper_crates/vtable/Cargo.toml b/helper_crates/vtable/Cargo.toml index 25fe411e4..e6143e582 100644 --- a/helper_crates/vtable/Cargo.toml +++ b/helper_crates/vtable/Cargo.toml @@ -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" } diff --git a/helper_crates/vtable/macro/macro.rs b/helper_crates/vtable/macro/macro.rs index 492b7f657..556f8872c 100644 --- a/helper_crates/vtable/macro/macro.rs +++ b/helper_crates/vtable/macro/macro.rs @@ -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::(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::(quote!(vtable::FieldOffset)).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::*; diff --git a/helper_crates/vtable/src/lib.rs b/helper_crates/vtable/src/lib.rs index 94b027169..4cc0a431b 100644 --- a/helper_crates/vtable/src/lib.rs +++ b/helper_crates/vtable/src/lib.rs @@ -1,3 +1,4 @@ +pub use const_field_offset::FieldOffset; use core::marker::PhantomData; use core::ops::{Deref, DerefMut, Drop}; use core::ptr::NonNull; diff --git a/helper_crates/vtable/tests/test_vtable.rs b/helper_crates/vtable/tests/test_vtable.rs index d66efdfaf..d0b65c78f 100644 --- a/helper_crates/vtable/tests/test_vtable.rs +++ b/helper_crates/vtable/tests/test_vtable.rs @@ -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::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::::new(SomeStruct(23)); + let bx2 = VBox::::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::::new(&hello); assert_eq!(xref.foo(0), 44); @@ -65,7 +71,9 @@ fn test() { { let mut xref = VRefMut::::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); } } diff --git a/sixtyfps_runtime/corelib/abi/datastructures.rs b/sixtyfps_runtime/corelib/abi/datastructures.rs index 9edd8a0e1..fc52850bb 100644 --- a/sixtyfps_runtime/corelib/abi/datastructures.rs +++ b/sixtyfps_runtime/corelib/abi/datastructures.rs @@ -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. diff --git a/sixtyfps_runtime/corelib/abi/primitives.rs b/sixtyfps_runtime/corelib/abi/primitives.rs index 5871805cd..879d04ab2 100644 --- a/sixtyfps_runtime/corelib/abi/primitives.rs +++ b/sixtyfps_runtime/corelib/abi/primitives.rs @@ -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] diff --git a/sixtyfps_runtime/corelib/item_rendering.rs b/sixtyfps_runtime/corelib/item_rendering.rs index 2f49d15a8..cfcee04d7 100644 --- a/sixtyfps_runtime/corelib/item_rendering.rs +++ b/sixtyfps_runtime/corelib/item_rendering.rs @@ -12,7 +12,7 @@ pub(crate) fn update_item_rendering_data( 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( _ => {} } - 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 {}",