Use the vtable crate for the ItemVTable

This commit is contained in:
Olivier Goffart 2020-05-15 13:45:50 +02:00
parent 49fc23224e
commit f74cfe73cd
6 changed files with 99 additions and 113 deletions

View file

@ -390,6 +390,7 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
let result = quote!( let result = quote!(
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[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)] #[allow(unused)]
@ -448,6 +449,11 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
pub type #refmut_name<'a> = VRefMut<'a, #vtable_name>; pub type #refmut_name<'a> = VRefMut<'a, #vtable_name>;
pub type #box_name = VBox<#vtable_name>; pub type #box_name = VBox<#vtable_name>;
}
#[doc(inline)]
#[macro_use]
#vis use #module_name::*;
#[macro_export] #[macro_export]
macro_rules! #static_vtable_macro_name { macro_rules! #static_vtable_macro_name {
($ty:ty) => { ($ty:ty) => {
@ -459,11 +465,8 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
} }
} }
} }
}
#[doc(inline)]
#vis use #module_name::*;
); );
// println!("{}", result); // println!("{}", result);
result.into() result.into()
} }

View file

@ -1,7 +1,7 @@
use core::ops::{Deref, DerefMut, Drop}; use core::ops::{Deref, DerefMut, Drop};
use core::ptr::NonNull; use core::ptr::NonNull;
use core::marker::PhantomData; use core::marker::PhantomData;
pub use vtable_macro::vtable; pub use vtable_macro::*;
pub unsafe trait VTableMeta { pub unsafe trait VTableMeta {
/// that's the rust trait. (e.g: `Hello`) /// that's the rust trait. (e.g: `Hello`)
@ -189,6 +189,9 @@ impl<'a, T: ?Sized + VTableMeta> VRefMut<'a, T> {
pub fn into_ref(self) -> VRef<'a, T> { pub fn into_ref(self) -> VRef<'a, T> {
unsafe { VRef::from_inner(VRefMut::inner(&self)) } unsafe { VRef::from_inner(VRefMut::inner(&self)) }
} }
pub unsafe fn from_raw(vtable: NonNull<T::VTable>, ptr: NonNull<u8>) -> Self {
Self {inner : T::from_raw(vtable, ptr), _phantom: PhantomData }
}
pub fn get_vtable(&self) -> &T::VTable { pub fn get_vtable(&self) -> &T::VTable {
unsafe { T::get_vtable(&self.inner) } unsafe { T::get_vtable(&self.inner) }
} }

View file

@ -14,16 +14,6 @@ pub struct ComponentVTable {
pub item_tree: extern "C" fn(VRef<ComponentVTable>) -> *const ItemTreeNode, pub item_tree: extern "C" fn(VRef<ComponentVTable>) -> *const ItemTreeNode,
} }
/// From the ItemTreeNode and a ComponentImpl, you can get a pointer to the instance data
/// ItemImpl via the offset field.
pub struct ItemImpl;
// Example memory representation:
// offset| type | value
// 0 | f32 | x
// 4 | f32 | y
// ...
// 64 | CachedRenderingData | struct
#[repr(C)] #[repr(C)]
#[derive(Default)] #[derive(Default)]
pub struct CachedRenderingData { pub struct CachedRenderingData {
@ -75,24 +65,25 @@ pub enum ItemTreeNode {
/// It is supposed to be in static array /// It is supposed to be in static array
unsafe impl Sync for ItemTreeNode {} unsafe impl Sync for ItemTreeNode {}
#[vtable]
#[repr(C)] #[repr(C)]
#[derive(Default)]
pub struct ItemVTable { pub struct ItemVTable {
/// Rectangle: x/y/width/height ==> (path -> vertices/indicies(triangle)) /// Rectangle: x/y/width/height ==> (path -> vertices/indicies(triangle))
pub geometry: Option<unsafe extern "C" fn(*const ItemImpl) -> ()>, // like kurbo::Rect pub geometry: extern "C" fn(VRef<'_, ItemVTable>) -> (), // like kurbo::Rect
/// 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)]
pub cached_rendering_data_offset: isize, pub cached_rendering_data_offset: isize,
/// Return a rendering info /// Return a rendering info
pub rendering_info: Option<unsafe extern "C" fn(*const ItemImpl) -> RenderingInfo>, pub rendering_info: extern "C" fn(VRef<'_, ItemVTable>) -> RenderingInfo,
/// We would need max/min/preferred size, and all layout info /// We would need max/min/preferred size, and all layout info
pub layouting_info: Option<unsafe extern "C" fn(*const ItemImpl) -> LayoutInfo>, pub layouting_info: extern "C" fn(VRef<'_, ItemVTable>) -> LayoutInfo,
/// input event /// input event
pub input_event: Option<unsafe extern "C" fn(*const ItemImpl, MouseEvent)>, pub input_event: extern "C" fn(VRef<'_, ItemVTable>, MouseEvent),
} }
// given an ItemImpl & ItemVTable // given an ItemImpl & ItemVTable
@ -117,7 +108,7 @@ pub enum RenderingInfo {
Text(String)*/ Text(String)*/
} }
type MouseEvent = (); pub type MouseEvent = ();
/* -- Safe wrappers*/ /* -- Safe wrappers*/
@ -128,45 +119,26 @@ type MouseEvent = ();
fn rendering_info(&self) -> CachedRenderingData; fn rendering_info(&self) -> CachedRenderingData;
}*/ }*/
// To be used as &'x Item pub fn cached_rendering_data(item: VRef<'_, ItemVTable>) -> &CachedRenderingData {
pub struct Item {
vtable: NonNull<ItemVTable>,
inner: NonNull<ItemImpl>,
}
impl Item {
/// One should create only one instance of item at the time to keep the &mut invariant
pub unsafe fn new(vtable: NonNull<ItemVTable>, inner: NonNull<ItemImpl>) -> Self {
Self { vtable, inner }
}
pub fn cached_rendering_data(&self) -> &CachedRenderingData {
unsafe { unsafe {
&*((self.inner.as_ptr() as *const u8) &*(VRef::get_ptr(&item).as_ptr().offset(item.get_vtable().cached_rendering_data_offset)
.offset(self.vtable.as_ref().cached_rendering_data_offset)
as *const CachedRenderingData) as *const CachedRenderingData)
} }
} }
pub fn cached_rendering_data_mut(&mut self) -> &mut CachedRenderingData { pub fn cached_rendering_data_mut(item: VRefMut<'_, ItemVTable>) -> &mut CachedRenderingData {
unsafe { unsafe {
&mut *((self.inner.as_ptr() as *mut u8) &mut *(VRefMut::get_ptr(&item).as_ptr().offset(item.get_vtable().cached_rendering_data_offset)
.offset(self.vtable.as_ref().cached_rendering_data_offset)
as *mut CachedRenderingData) as *mut CachedRenderingData)
} }
} }
pub fn rendering_info(&self) -> Option<RenderingInfo> {
unsafe { self.vtable.as_ref().rendering_info.map(|x| x(self.inner.as_ptr())) }
}
}
/// 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.
pub fn visit_items<State>( pub fn visit_items<State>(
component: VRef<'_, ComponentVTable>, component: VRef<'_, ComponentVTable>,
mut visitor: impl FnMut(&Item, &State) -> State, mut visitor: impl FnMut(ItemRef<'_>, &State) -> State,
state: State, state: State,
) { ) {
visit_internal(component, &mut visitor, 0, &state) visit_internal(component, &mut visitor, 0, &state)
@ -174,7 +146,7 @@ pub fn visit_items<State>(
fn visit_internal<State>( fn visit_internal<State>(
component: VRef<'_, ComponentVTable>, component: VRef<'_, ComponentVTable>,
visitor: &mut impl FnMut(&Item, &State) -> State, visitor: &mut impl FnMut(ItemRef<'_>, &State) -> State,
index: isize, index: isize,
state: &State, state: &State,
) { ) {
@ -182,14 +154,14 @@ fn visit_internal<State>(
match unsafe { &*item_tree.offset(index) } { match unsafe { &*item_tree.offset(index) } {
ItemTreeNode::Item { vtable, offset, children_index, chilren_count } => { ItemTreeNode::Item { vtable, offset, children_index, chilren_count } => {
let item = unsafe { let item = unsafe {
Item::new( ItemRef::from_raw(
NonNull::new_unchecked(*vtable as *mut _), NonNull::new_unchecked(*vtable as *mut _),
NonNull::new_unchecked( NonNull::new_unchecked(
(VRef::get_ptr(&component).as_ptr()).offset(*offset) as *mut _, (VRef::get_ptr(&component).as_ptr()).offset(*offset) as *mut _
), ),
) )
}; };
let state = visitor(&item, state); let state = visitor(item, state);
for c in *children_index..(*children_index + *chilren_count) { for c in *children_index..(*children_index + *chilren_count) {
visit_internal(component, visitor, c as isize, &state) visit_internal(component, visitor, c as isize, &state)
} }
@ -200,7 +172,7 @@ fn visit_internal<State>(
pub fn visit_items_mut<State>( pub fn visit_items_mut<State>(
component: VRefMut<'_, ComponentVTable>, component: VRefMut<'_, ComponentVTable>,
mut visitor: impl FnMut(&mut Item, &State) -> State, mut visitor: impl FnMut(ItemRefMut<'_>, &State) -> State,
state: State, state: State,
) { ) {
visit_internal_mut(component, &mut visitor, 0, &state) visit_internal_mut(component, &mut visitor, 0, &state)
@ -208,7 +180,7 @@ pub fn visit_items_mut<State>(
fn visit_internal_mut<State>( fn visit_internal_mut<State>(
mut component: VRefMut<'_, ComponentVTable>, mut component: VRefMut<'_, ComponentVTable>,
visitor: &mut impl FnMut(&mut Item, &State) -> State, visitor: &mut impl FnMut(ItemRefMut<'_>, &State) -> State,
index: isize, index: isize,
state: &State, state: &State,
) { ) {
@ -216,15 +188,15 @@ fn visit_internal_mut<State>(
match unsafe { &*item_tree.offset(index) } { match unsafe { &*item_tree.offset(index) } {
ItemTreeNode::Item { vtable, offset, children_index, chilren_count } => { ItemTreeNode::Item { vtable, offset, children_index, chilren_count } => {
let mut item = unsafe { let mut item = unsafe {
Item::new( ItemRefMut::from_raw(
NonNull::new_unchecked(*vtable as *mut _), NonNull::new_unchecked(*vtable as *mut _),
NonNull::new_unchecked( NonNull::new_unchecked(
(VRefMut::get_ptr(&component).as_ptr() as *mut u8).offset(*offset) as *mut _, (VRefMut::get_ptr(&component).as_ptr() as *mut u8).offset(*offset)
as *mut _,
), ),
) )
}; };
let state = visitor(&mut item, state); let state = visitor(item.borrow_mut(), state);
for c in *children_index..(*children_index + *chilren_count) { for c in *children_index..(*children_index + *chilren_count) {
visit_internal_mut(component.borrow_mut(), visitor, c as isize, &state) visit_internal_mut(component.borrow_mut(), visitor, c as isize, &state)
} }
@ -323,3 +295,13 @@ pub static QT_BUTTON_VTABLE: ItemVTable = ItemVTable {
rendering_info: render_qt_button, rendering_info: render_qt_button,
}; };
*/ */
#[allow(non_upper_case_globals)]
#[no_mangle]
pub static RectangleVTable: ItemVTable = ItemVTable_static!(crate::abi::primitives::Rectangle);
#[allow(non_upper_case_globals)]
#[no_mangle]
pub static ImageVTable: ItemVTable = ItemVTable_static!(crate::abi::primitives::Image);

View file

@ -1,4 +1,6 @@
use super::datastructures::{CachedRenderingData, ItemImpl, ItemVTable, RenderingInfo}; #![allow(non_upper_case_globals)]
use super::datastructures::{CachedRenderingData, Item, ItemConsts, LayoutInfo, RenderingInfo};
/// FIXME: more properties /// FIXME: more properties
#[repr(C)] #[repr(C)]
@ -13,21 +15,23 @@ pub struct Rectangle {
pub cached_rendering_data: CachedRenderingData, pub cached_rendering_data: CachedRenderingData,
} }
unsafe extern "C" fn render_rectangle(i: *const ItemImpl) -> RenderingInfo { impl Item for Rectangle {
let r = &*(i as *const Rectangle); fn geometry(&self) {}
RenderingInfo::Rectangle(r.x, r.y, r.width, r.height, r.color) fn rendering_info(&self) -> RenderingInfo {
RenderingInfo::Rectangle(self.x, self.y, self.width, self.height, self.color)
} }
#[allow(non_upper_case_globals)] fn layouting_info(&self) -> LayoutInfo {
#[no_mangle] todo!()
pub static RectangleVTable: ItemVTable = ItemVTable { }
geometry: None,
// offset_of!(Rectangle, render_node), is not const on stable rust fn input_event(&self, _: super::datastructures::MouseEvent) {}
cached_rendering_data_offset: Rectangle::field_offsets().cached_rendering_data as isize, }
rendering_info: Some(render_rectangle),
layouting_info: None, impl ItemConsts for Rectangle {
input_event: None, const cached_rendering_data_offset: isize =
}; Rectangle::field_offsets().cached_rendering_data as isize;
}
// FIXME: remove (or use the libc one) // FIXME: remove (or use the libc one)
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -58,19 +62,23 @@ impl Default for Image {
} }
} }
unsafe extern "C" fn render_image(i: *const ItemImpl) -> RenderingInfo { impl Item for Image {
let i = &*(i as *const Image); fn geometry(&self) {}
RenderingInfo::Image(std::ffi::CStr::from_ptr(i.source).to_str().unwrap()) fn rendering_info(&self) -> RenderingInfo {
unsafe { RenderingInfo::Image(std::ffi::CStr::from_ptr(self.source).to_str().unwrap()) }
} }
/// TODO fn layouting_info(&self) -> LayoutInfo {
#[allow(non_upper_case_globals)] todo!()
#[no_mangle] }
pub static ImageVTable: super::datastructures::ItemVTable = super::datastructures::ItemVTable {
geometry: None, fn input_event(&self, _: super::datastructures::MouseEvent) {}
// offset_of!(Rectangle, render_node), is not const on stable rust }
cached_rendering_data_offset: Image::field_offsets().cached_rendering_data as isize,
rendering_info: Some(render_image), impl ItemConsts for Image {
layouting_info: None, const cached_rendering_data_offset: isize =
input_event: None, Image::field_offsets().cached_rendering_data as isize;
}; }
pub use super::datastructures::{ImageVTable, RectangleVTable};

View file

@ -1,23 +1,18 @@
use super::abi::datastructures::{Item, RenderingInfo}; use super::abi::datastructures::{ItemRefMut, RenderingInfo};
use super::graphics::{Color, Frame, GraphicsBackend, RenderingCache, RenderingPrimitivesBuilder}; use super::graphics::{Color, Frame, GraphicsBackend, RenderingCache, RenderingPrimitivesBuilder};
use cgmath::{Matrix4, SquareMatrix, Vector3}; use cgmath::{Matrix4, SquareMatrix, Vector3};
use lyon::math::{Point, Rect, Size}; use lyon::math::{Point, Rect, Size};
pub(crate) fn update_item_rendering_data<Backend: GraphicsBackend>( pub(crate) fn update_item_rendering_data<Backend: GraphicsBackend>(
item: &mut Item, mut item: ItemRefMut<'_>,
rendering_cache: &mut RenderingCache<Backend>, rendering_cache: &mut RenderingCache<Backend>,
rendering_primitives_builder: &mut Backend::RenderingPrimitivesBuilder, rendering_primitives_builder: &mut Backend::RenderingPrimitivesBuilder,
) { ) {
let item_rendering_info = { let item_rendering_info = item.rendering_info();
match item.rendering_info() {
Some(info) => info,
None => return,
}
};
println!("Caching ... {:?}", item_rendering_info); println!("Caching ... {:?}", item_rendering_info);
let rendering_data = item.cached_rendering_data_mut(); let rendering_data = super::abi::datastructures::cached_rendering_data_mut(item.borrow_mut());
match item_rendering_info { match item_rendering_info {
RenderingInfo::Rectangle(_x, _y, width, height, color) => { RenderingInfo::Rectangle(_x, _y, width, height, color) => {
@ -81,12 +76,7 @@ pub(crate) fn render_component_items<Backend: GraphicsBackend>(
component, component,
|item, transform| { |item, transform| {
let mut transform = transform.clone(); let mut transform = transform.clone();
let item_rendering_info = { let item_rendering_info = item.rendering_info();
match item.rendering_info() {
Some(info) => info,
None => return transform,
}
};
match item_rendering_info { match item_rendering_info {
RenderingInfo::Rectangle(x, y, ..) => { RenderingInfo::Rectangle(x, y, ..) => {
@ -95,14 +85,14 @@ pub(crate) fn render_component_items<Backend: GraphicsBackend>(
_ => {} _ => {}
} }
if item.cached_rendering_data().cache_ok { let cached_rendering_data = super::abi::datastructures::cached_rendering_data(item);
if cached_rendering_data.cache_ok {
println!( println!(
"Rendering... {:?} from cache {}", "Rendering... {:?} from cache {}",
item_rendering_info, item_rendering_info, cached_rendering_data.cache_index
item.cached_rendering_data().cache_index
); );
let primitive = rendering_cache.entry_at(item.cached_rendering_data().cache_index); let primitive = rendering_cache.entry_at(cached_rendering_data.cache_index);
frame.render_primitive(&primitive, &transform); frame.render_primitive(&primitive, &transform);
} }

View file

@ -47,7 +47,7 @@ impl PropertyWriter for *const i8 {
} }
} }
unsafe fn construct<T: Default>(ptr: *mut corelib::abi::datastructures::ItemImpl) { unsafe fn construct<T: Default>(ptr: *mut u8) {
core::ptr::write(ptr as *mut T, T::default()); core::ptr::write(ptr as *mut T, T::default());
} }
@ -72,12 +72,12 @@ struct MyComponentType {
unsafe extern "C" fn item_tree( unsafe extern "C" fn item_tree(
r: ComponentRef<'_>, r: ComponentRef<'_>,
) -> *const corelib::abi::datastructures::ItemTreeNode { ) -> *const corelib::abi::datastructures::ItemTreeNode {
(*(ComponentRef::get_vtable(&r).as_ptr() as *const MyComponentType)).it.as_ptr() (*(ComponentRef::get_vtable(&r) as *const ComponentVTable as *const MyComponentType)).it.as_ptr()
} }
struct RuntimeTypeInfo { struct RuntimeTypeInfo {
vtable: *const corelib::abi::datastructures::ItemVTable, vtable: *const corelib::abi::datastructures::ItemVTable,
construct: unsafe fn(*mut corelib::abi::datastructures::ItemImpl), construct: unsafe fn(*mut u8),
properties: HashMap<&'static str, (usize, unsafe fn(*mut u8, &Expression))>, properties: HashMap<&'static str, (usize, unsafe fn(*mut u8, &Expression))>,
size: usize, size: usize,
} }