mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 22:54:36 +00:00
vtable add support for field offset in the vtable
This commit is contained in:
parent
751a3fbe59
commit
5a9cbaae66
7 changed files with 100 additions and 46 deletions
|
@ -11,4 +11,4 @@ syn = { version = "1.0", features = ["full"] }
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = "1.0"
|
||||||
vtable-macro = { path="./macro" }
|
vtable-macro = { path="./macro" }
|
||||||
|
const-field-offset = { path="../const-field-offset" }
|
||||||
|
|
|
@ -344,7 +344,6 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
});
|
});
|
||||||
|
|
||||||
vtable_ctor.push(quote!(#ident: {
|
vtable_ctor.push(quote!(#ident: {
|
||||||
#[allow(unused_parens)]
|
|
||||||
#sig_extern {
|
#sig_extern {
|
||||||
// This is safe since the self must be a instance of our type
|
// This is safe since the self must be a instance of our type
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -364,7 +363,6 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// associated constant
|
// associated constant
|
||||||
let ty = &field.ty;
|
|
||||||
|
|
||||||
let generated_trait_assoc_const =
|
let generated_trait_assoc_const =
|
||||||
generated_trait_assoc_const.get_or_insert_with(|| ItemTrait {
|
generated_trait_assoc_const.get_or_insert_with(|| ItemTrait {
|
||||||
|
@ -373,17 +371,79 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
items: vec![],
|
items: vec![],
|
||||||
..generated_trait.clone()
|
..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 {
|
generated_trait_assoc_const.items.push(TraitItem::Const(TraitItemConst {
|
||||||
attrs: field.attrs.clone(),
|
attrs: field.attrs.clone(),
|
||||||
const_token: Default::default(),
|
const_token: Default::default(),
|
||||||
ident: ident.clone(),
|
ident: ident.clone(),
|
||||||
colon_token: Default::default(),
|
colon_token: Default::default(),
|
||||||
ty: ty.clone(),
|
ty: const_type,
|
||||||
default: None,
|
default: None,
|
||||||
semi_token: Default::default(),
|
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]
|
#[macro_use]
|
||||||
/// This private module is generated by the `vtable` macro
|
/// This private module is generated by the `vtable` macro
|
||||||
mod #module_name {
|
mod #module_name {
|
||||||
|
#![allow(unused_parens)]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use super::*;
|
use super::*;
|
||||||
use ::vtable::*;
|
use ::vtable::*;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub use const_field_offset::FieldOffset;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::ops::{Deref, DerefMut, Drop};
|
use core::ops::{Deref, DerefMut, Drop};
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
|
|
@ -10,25 +10,28 @@ struct HelloVTable {
|
||||||
drop: fn(VRefMut<'_, HelloVTable>),
|
drop: fn(VRefMut<'_, HelloVTable>),
|
||||||
|
|
||||||
CONSTANT: usize,
|
CONSTANT: usize,
|
||||||
|
|
||||||
|
#[offset(u32)]
|
||||||
|
SOME_OFFSET: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, const_field_offset::FieldOffsets)]
|
||||||
struct SomeStruct(u32);
|
#[repr(C)]
|
||||||
|
struct SomeStruct {
|
||||||
|
x: u32,
|
||||||
|
}
|
||||||
impl Hello for SomeStruct {
|
impl Hello for SomeStruct {
|
||||||
fn foo(&self, xx: u32) -> u32 {
|
fn foo(&self, xx: u32) -> u32 {
|
||||||
println!("calling foo {} + {}", self.0, xx);
|
self.x + xx
|
||||||
self.0 + xx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo_mut(&mut self, xx: u32) -> u32 {
|
fn foo_mut(&mut self, xx: u32) -> u32 {
|
||||||
println!("calling foo_mut {} + {}", self.0, xx);
|
self.x += xx;
|
||||||
self.0 += xx;
|
self.x
|
||||||
self.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct(init: u32) -> Self {
|
fn construct(init: u32) -> Self {
|
||||||
println!("calling Construct {}", init);
|
Self { x: init }
|
||||||
Self(init)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assoc() -> isize {
|
fn assoc() -> isize {
|
||||||
|
@ -37,6 +40,8 @@ impl Hello for SomeStruct {
|
||||||
}
|
}
|
||||||
impl HelloConsts for SomeStruct {
|
impl HelloConsts for SomeStruct {
|
||||||
const CONSTANT: usize = 88;
|
const CONSTANT: usize = 88;
|
||||||
|
const SOME_OFFSET: const_field_offset::FieldOffset<SomeStruct, u32> =
|
||||||
|
SomeStruct::field_offsets().x;
|
||||||
}
|
}
|
||||||
|
|
||||||
HelloVTable_static!(SomeStruct);
|
HelloVTable_static!(SomeStruct);
|
||||||
|
@ -53,11 +58,12 @@ fn test() {
|
||||||
assert_eq!(bx.foo(2), 97);
|
assert_eq!(bx.foo(2), 97);
|
||||||
assert_eq!(bx.get_vtable().CONSTANT, 88);
|
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.foo(3), 26);
|
||||||
assert_eq!(bx2.get_vtable().CONSTANT, 88);
|
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);
|
let xref = VRef::<HelloVTable>::new(&hello);
|
||||||
assert_eq!(xref.foo(0), 44);
|
assert_eq!(xref.foo(0), 44);
|
||||||
|
@ -65,7 +71,9 @@ fn test() {
|
||||||
{
|
{
|
||||||
let mut xref = VRefMut::<HelloVTable>::new(&mut hello);
|
let mut xref = VRefMut::<HelloVTable>::new(&mut hello);
|
||||||
assert_eq!(xref.foo_mut(2), 46);
|
assert_eq!(xref.foo_mut(2), 46);
|
||||||
|
assert_eq!(*xref.SOME_OFFSET(), 46);
|
||||||
|
*xref.SOME_OFFSET_mut() = 3;
|
||||||
let xref2 = xref.borrow();
|
let xref2 = xref.borrow();
|
||||||
assert_eq!(xref2.foo(1), 47);
|
assert_eq!(xref2.foo(1), 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,8 @@ pub struct ItemVTable {
|
||||||
/// offset in bytes fromthe *const ItemImpl.
|
/// offset in bytes fromthe *const ItemImpl.
|
||||||
/// isize::MAX means None
|
/// isize::MAX means None
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
pub cached_rendering_data_offset: isize,
|
#[offset(CachedRenderingData)]
|
||||||
|
pub cached_rendering_data_offset: usize,
|
||||||
|
|
||||||
/// Return a rendering info
|
/// Return a rendering info
|
||||||
pub rendering_info: extern "C" fn(VRef<'_, ItemVTable>) -> RenderingInfo,
|
pub rendering_info: extern "C" fn(VRef<'_, ItemVTable>) -> RenderingInfo,
|
||||||
|
@ -112,27 +113,6 @@ pub type MouseEvent = ();
|
||||||
|
|
||||||
/* -- Safe wrappers*/
|
/* -- 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
|
/// Visit each items recursively
|
||||||
///
|
///
|
||||||
/// The state parametter returned by the visitor is passed to each children.
|
/// The state parametter returned by the visitor is passed to each children.
|
||||||
|
|
|
@ -32,8 +32,10 @@ impl Item for Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemConsts for Rectangle {
|
impl ItemConsts for Rectangle {
|
||||||
const cached_rendering_data_offset: isize =
|
const cached_rendering_data_offset: const_field_offset::FieldOffset<
|
||||||
Rectangle::field_offsets().cached_rendering_data.get_byte_offset() as isize;
|
Rectangle,
|
||||||
|
CachedRenderingData,
|
||||||
|
> = Rectangle::field_offsets().cached_rendering_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: remove (or use the libc one)
|
// FIXME: remove (or use the libc one)
|
||||||
|
@ -79,8 +81,10 @@ impl Item for Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemConsts for Image {
|
impl ItemConsts for Image {
|
||||||
const cached_rendering_data_offset: isize =
|
const cached_rendering_data_offset: const_field_offset::FieldOffset<
|
||||||
Image::field_offsets().cached_rendering_data.get_byte_offset() as isize;
|
Image,
|
||||||
|
CachedRenderingData,
|
||||||
|
> = Image::field_offsets().cached_rendering_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub(crate) fn update_item_rendering_data<Backend: GraphicsBackend>(
|
||||||
|
|
||||||
println!("Caching ... {:?}", item_rendering_info);
|
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 {
|
match item_rendering_info {
|
||||||
RenderingInfo::Rectangle(_x, _y, width, height, color) => {
|
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 {
|
if cached_rendering_data.cache_ok {
|
||||||
println!(
|
println!(
|
||||||
"Rendering... {:?} from cache {}",
|
"Rendering... {:?} from cache {}",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue