Visit the item as Pin

A preparation to have Property::get to take Pin<Self>
This commit is contained in:
Olivier Goffart 2020-06-25 18:50:20 +02:00
parent 40f4265071
commit 1b748792ad
8 changed files with 86 additions and 48 deletions

View file

@ -472,6 +472,18 @@ impl<Base, T: ?Sized + VTableMeta, Flag> VOffset<Base, T, Flag> {
} }
} }
impl<Base, T: ?Sized + VTableMeta> VOffset<Base, T, PinnedFlag> {
pub fn apply_pin<'a>(self, x: Pin<&'a Base>) -> Pin<VRef<'a, T>> {
let ptr = x.get_ref() as *const Base as *mut u8;
unsafe {
Pin::new_unchecked(VRef::from_raw(
NonNull::from(self.vtable),
NonNull::new_unchecked(ptr.add(self.offset)),
))
}
}
}
// Need to implement manually otheriwse it is not implemented if T do not implement Copy / Clone // Need to implement manually otheriwse it is not implemented if T do not implement Copy / Clone
impl<Base, T: ?Sized + VTableMeta, Flag> Copy for VOffset<Base, T, Flag> {} impl<Base, T: ?Sized + VTableMeta, Flag> Copy for VOffset<Base, T, Flag> {}

View file

@ -277,7 +277,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
#(#repeated_element_names : sixtyfps::re_exports::Repeater<#repeated_element_components>,)* #(#repeated_element_names : sixtyfps::re_exports::Repeater<#repeated_element_components>,)*
} }
impl core::default::Default for #component_id { impl ::core::default::Default for #component_id {
fn default() -> Self { fn default() -> Self {
#![allow(unused)] #![allow(unused)]
use sixtyfps::re_exports::*; use sixtyfps::re_exports::*;
@ -294,12 +294,12 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
} }
impl sixtyfps::re_exports::Component for #component_id { impl sixtyfps::re_exports::Component for #component_id {
fn visit_children_item(self: core::pin::Pin<&Self>, index: isize, visitor: sixtyfps::re_exports::ItemVisitorRefMut) { fn visit_children_item(self: ::core::pin::Pin<&Self>, index: isize, visitor: sixtyfps::re_exports::ItemVisitorRefMut) {
use sixtyfps::re_exports::*; use sixtyfps::re_exports::*;
let tree = &[#(#item_tree_array),*]; let tree = &[#(#item_tree_array),*];
sixtyfps::re_exports::visit_item_tree(self.get_ref(), VRef::new_pin(self), tree, index, visitor, visit_dynamic); sixtyfps::re_exports::visit_item_tree(self, VRef::new_pin(self), tree, index, visitor, visit_dynamic);
#[allow(unused)] #[allow(unused)]
fn visit_dynamic(base: &#component_id, visitor: ItemVisitorRefMut, dyn_index: usize) { fn visit_dynamic(base: ::core::pin::Pin<&#component_id>, visitor: ItemVisitorRefMut, dyn_index: usize) {
match dyn_index { match dyn_index {
#(#repeated_visit_branch)* #(#repeated_visit_branch)*
_ => panic!("invalid dyn_index {}", dyn_index), _ => panic!("invalid dyn_index {}", dyn_index),
@ -604,10 +604,10 @@ fn compute_layout(component: &Component) -> TokenStream {
} }
quote! { quote! {
fn layout_info(self: core::pin::Pin<&Self>) -> sixtyfps::re_exports::LayoutInfo { fn layout_info(self: ::core::pin::Pin<&Self>) -> sixtyfps::re_exports::LayoutInfo {
todo!("Implement in rust.rs") todo!("Implement in rust.rs")
} }
fn compute_layout(self: core::pin::Pin<&Self>, eval_context: &sixtyfps::re_exports::EvaluationContext) { fn compute_layout(self: ::core::pin::Pin<&Self>, eval_context: &sixtyfps::re_exports::EvaluationContext) {
#![allow(unused)] #![allow(unused)]
use sixtyfps::re_exports::*; use sixtyfps::re_exports::*;
let dummy = Property::<f32>::default(); let dummy = Property::<f32>::default();

View file

@ -106,7 +106,8 @@ pub enum ItemTreeNode<T> {
#[repr(C)] #[repr(C)]
pub struct ItemVTable { pub struct ItemVTable {
/// Returns the geometry of this item (relative to its parent item) /// Returns the geometry of this item (relative to its parent item)
pub geometry: extern "C" fn(VRef<'_, ItemVTable>, context: &crate::EvaluationContext) -> Rect, pub geometry:
extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, context: &crate::EvaluationContext) -> Rect,
/// offset in bytes fromthe *const ItemImpl. /// offset in bytes fromthe *const ItemImpl.
/// isize::MAX means None /// isize::MAX means None
@ -116,15 +117,16 @@ pub struct ItemVTable {
/// Return the rendering primitive used to display this item. /// Return the rendering primitive used to display this item.
pub rendering_primitive: extern "C" fn( pub rendering_primitive: extern "C" fn(
VRef<'_, ItemVTable>, core::pin::Pin<VRef<ItemVTable>>,
context: &crate::EvaluationContext, context: &crate::EvaluationContext,
) -> RenderingPrimitive, ) -> RenderingPrimitive,
/// 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: extern "C" fn(VRef<'_, ItemVTable>) -> LayoutInfo, pub layouting_info: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>) -> LayoutInfo,
/// input event /// input event
pub input_event: extern "C" fn(VRef<'_, ItemVTable>, MouseEvent, &crate::EvaluationContext), pub input_event:
extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, MouseEvent, &crate::EvaluationContext),
} }
/// The constraint that applies to an item /// The constraint that applies to an item
@ -328,19 +330,14 @@ pub struct ItemVisitorVTable {
VRefMut<ItemVisitorVTable>, VRefMut<ItemVisitorVTable>,
component: Pin<VRef<ComponentVTable>>, component: Pin<VRef<ComponentVTable>>,
index: isize, index: isize,
item: VRef<ItemVTable>, item: Pin<VRef<ItemVTable>>,
), ),
/// Destructor /// Destructor
drop: fn(VRefMut<ItemVisitorVTable>), drop: fn(VRefMut<ItemVisitorVTable>),
} }
impl<T: FnMut(crate::ComponentRefPin, isize, VRef<ItemVTable>)> ItemVisitor for T { impl<T: FnMut(crate::ComponentRefPin, isize, Pin<ItemRef>)> ItemVisitor for T {
fn visit_item( fn visit_item(&mut self, component: crate::ComponentRefPin, index: isize, item: Pin<ItemRef>) {
&mut self,
component: crate::ComponentRefPin,
index: isize,
item: VRef<ItemVTable>,
) {
self(component, index, item) self(component, index, item)
} }
} }
@ -361,12 +358,12 @@ pub unsafe extern "C" fn sixtyfps_visit_item_tree(
), ),
) { ) {
crate::item_tree::visit_item_tree( crate::item_tree::visit_item_tree(
&*(component.as_ptr() as *const u8), Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
component, component,
item_tree.as_slice(), item_tree.as_slice(),
index, index,
visitor, visitor,
|a, b, c| visit_dynamic(a, b, c), |a, b, c| visit_dynamic(a.get_ref(), b, c),
) )
} }

View file

@ -22,6 +22,7 @@ use super::datastructures::{
use crate::rtti::*; use crate::rtti::*;
use crate::{EvaluationContext, Property, SharedString, Signal}; use crate::{EvaluationContext, Property, SharedString, Signal};
use const_field_offset::FieldOffsets; use const_field_offset::FieldOffsets;
use core::pin::Pin;
use corelib_macro::*; use corelib_macro::*;
#[repr(C)] #[repr(C)]
@ -39,7 +40,7 @@ pub struct Rectangle {
} }
impl Item for Rectangle { impl Item for Rectangle {
fn geometry(&self, context: &EvaluationContext) -> Rect { fn geometry(self: Pin<&Self>, context: &EvaluationContext) -> Rect {
euclid::rect( euclid::rect(
self.x.get(context), self.x.get(context),
self.y.get(context), self.y.get(context),
@ -47,7 +48,10 @@ impl Item for Rectangle {
self.height.get(context), self.height.get(context),
) )
} }
fn rendering_primitive(&self, context: &crate::EvaluationContext) -> RenderingPrimitive { fn rendering_primitive(
self: Pin<&Self>,
context: &crate::EvaluationContext,
) -> RenderingPrimitive {
let width = self.width.get(context); let width = self.width.get(context);
let height = self.height.get(context); let height = self.height.get(context);
if width > 0. && height > 0. { if width > 0. && height > 0. {
@ -63,11 +67,16 @@ impl Item for Rectangle {
} }
} }
fn layouting_info(&self) -> LayoutInfo { fn layouting_info(self: Pin<&Self>) -> LayoutInfo {
Default::default() Default::default()
} }
fn input_event(&self, _: super::datastructures::MouseEvent, _: &crate::EvaluationContext) {} fn input_event(
self: Pin<&Self>,
_: super::datastructures::MouseEvent,
_: &crate::EvaluationContext,
) {
}
} }
impl ItemConsts for Rectangle { impl ItemConsts for Rectangle {
@ -93,7 +102,7 @@ pub struct Image {
} }
impl Item for Image { impl Item for Image {
fn geometry(&self, context: &crate::EvaluationContext) -> Rect { fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect {
euclid::rect( euclid::rect(
self.x.get(context), self.x.get(context),
self.y.get(context), self.y.get(context),
@ -101,7 +110,10 @@ impl Item for Image {
self.height.get(context), self.height.get(context),
) )
} }
fn rendering_primitive(&self, context: &crate::EvaluationContext) -> RenderingPrimitive { fn rendering_primitive(
self: Pin<&Self>,
context: &crate::EvaluationContext,
) -> RenderingPrimitive {
RenderingPrimitive::Image { RenderingPrimitive::Image {
x: self.x.get(context), x: self.x.get(context),
y: self.y.get(context), y: self.y.get(context),
@ -109,12 +121,17 @@ impl Item for Image {
} }
} }
fn layouting_info(&self) -> LayoutInfo { fn layouting_info(self: Pin<&Self>) -> LayoutInfo {
// FIXME: should we use the image size here // FIXME: should we use the image size here
Default::default() Default::default()
} }
fn input_event(&self, _: super::datastructures::MouseEvent, _: &crate::EvaluationContext) {} fn input_event(
self: Pin<&Self>,
_: super::datastructures::MouseEvent,
_: &crate::EvaluationContext,
) {
}
} }
impl ItemConsts for Image { impl ItemConsts for Image {
@ -142,10 +159,13 @@ pub struct Text {
impl Item for Text { impl Item for Text {
// FIXME: width / height. or maybe it doesn't matter? ( // FIXME: width / height. or maybe it doesn't matter? (
fn geometry(&self, context: &crate::EvaluationContext) -> Rect { fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect {
euclid::rect(self.x.get(context), self.y.get(context), 0., 0.) euclid::rect(self.x.get(context), self.y.get(context), 0., 0.)
} }
fn rendering_primitive(&self, context: &crate::EvaluationContext) -> RenderingPrimitive { fn rendering_primitive(
self: Pin<&Self>,
context: &crate::EvaluationContext,
) -> RenderingPrimitive {
RenderingPrimitive::Text { RenderingPrimitive::Text {
x: self.x.get(context), x: self.x.get(context),
y: self.y.get(context), y: self.y.get(context),
@ -156,11 +176,16 @@ impl Item for Text {
} }
} }
fn layouting_info(&self) -> LayoutInfo { fn layouting_info(self: Pin<&Self>) -> LayoutInfo {
todo!() todo!()
} }
fn input_event(&self, _: super::datastructures::MouseEvent, _: &crate::EvaluationContext) {} fn input_event(
self: Pin<&Self>,
_: super::datastructures::MouseEvent,
_: &crate::EvaluationContext,
) {
}
} }
impl ItemConsts for Text { impl ItemConsts for Text {
@ -187,7 +212,7 @@ pub struct TouchArea {
} }
impl Item for TouchArea { impl Item for TouchArea {
fn geometry(&self, context: &crate::EvaluationContext) -> Rect { fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect {
euclid::rect( euclid::rect(
self.x.get(context), self.x.get(context),
self.y.get(context), self.y.get(context),
@ -195,16 +220,19 @@ impl Item for TouchArea {
self.height.get(context), self.height.get(context),
) )
} }
fn rendering_primitive(&self, _context: &crate::EvaluationContext) -> RenderingPrimitive { fn rendering_primitive(
self: Pin<&Self>,
_context: &crate::EvaluationContext,
) -> RenderingPrimitive {
RenderingPrimitive::NoContents RenderingPrimitive::NoContents
} }
fn layouting_info(&self) -> LayoutInfo { fn layouting_info(self: Pin<&Self>) -> LayoutInfo {
todo!() todo!()
} }
fn input_event( fn input_event(
&self, self: Pin<&Self>,
event: super::datastructures::MouseEvent, event: super::datastructures::MouseEvent,
context: &crate::EvaluationContext, context: &crate::EvaluationContext,
) { ) {

View file

@ -13,13 +13,13 @@ pub fn process_mouse_event(component: ComponentRefPin, event: MouseEvent) {
crate::item_tree::visit_items( crate::item_tree::visit_items(
component, component,
|context, item, offset| { |context, item, offset| {
let geom = item.geometry(context); let geom = item.as_ref().geometry(context);
let geom = geom.translate(*offset); let geom = geom.translate(*offset);
if geom.contains(event.pos) { if geom.contains(event.pos) {
let mut event2 = event.clone(); let mut event2 = event.clone();
event2.pos -= geom.origin.to_vector(); event2.pos -= geom.origin.to_vector();
item.input_event(event2, context); item.as_ref().input_event(event2, context);
} }
geom.origin.to_vector() geom.origin.to_vector()

View file

@ -7,11 +7,11 @@ use cgmath::{Matrix4, SquareMatrix, Vector3};
pub(crate) fn update_item_rendering_data<Backend: GraphicsBackend>( pub(crate) fn update_item_rendering_data<Backend: GraphicsBackend>(
context: &EvaluationContext, context: &EvaluationContext,
item: ItemRef<'_>, item: core::pin::Pin<ItemRef>,
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_primitive = item.rendering_primitive(context); let item_rendering_primitive = item.as_ref().rendering_primitive(context);
let rendering_data = item.cached_rendering_data_offset(); let rendering_data = item.cached_rendering_data_offset();
@ -47,7 +47,7 @@ pub(crate) fn render_component_items<Backend: GraphicsBackend>(
crate::item_tree::visit_items( crate::item_tree::visit_items(
component, component,
|context, item, transform| { |context, item, transform| {
let origin = item.geometry(context).origin; let origin = item.as_ref().geometry(context).origin;
let transform = let transform =
transform * Matrix4::from_translation(Vector3::new(origin.x, origin.y, 0.)); transform * Matrix4::from_translation(Vector3::new(origin.x, origin.y, 0.));

View file

@ -1,13 +1,14 @@
use crate::abi::datastructures::{ItemRef, ItemTreeNode, ItemVisitor, ItemVisitorVTable}; use crate::abi::datastructures::{ItemRef, ItemTreeNode, ItemVisitor, ItemVisitorVTable};
use crate::ComponentRefPin; use crate::ComponentRefPin;
use crate::EvaluationContext; use crate::EvaluationContext;
use core::pin::Pin;
/// 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: ComponentRefPin, component: ComponentRefPin,
mut visitor: impl FnMut(&EvaluationContext, ItemRef, &State) -> State, mut visitor: impl FnMut(&EvaluationContext, Pin<ItemRef>, &State) -> State,
state: State, state: State,
) { ) {
let context = EvaluationContext::for_root_component(component); let context = EvaluationContext::for_root_component(component);
@ -16,11 +17,11 @@ pub fn visit_items<State>(
fn visit_internal<State>( fn visit_internal<State>(
context: &EvaluationContext, context: &EvaluationContext,
visitor: &mut impl FnMut(&EvaluationContext, ItemRef, &State) -> State, visitor: &mut impl FnMut(&EvaluationContext, Pin<ItemRef>, &State) -> State,
index: isize, index: isize,
state: &State, state: &State,
) { ) {
let mut actual_visitor = |component: ComponentRefPin, index: isize, item: ItemRef| { let mut actual_visitor = |component: ComponentRefPin, index: isize, item: Pin<ItemRef>| {
if component.as_ptr() == context.component.as_ptr() { if component.as_ptr() == context.component.as_ptr() {
let s = visitor(context, item, state); let s = visitor(context, item, state);
visit_internal(context, visitor, index, &s); visit_internal(context, visitor, index, &s);
@ -43,16 +44,16 @@ fn visit_internal<State>(
/// Need to check if the compiler is able to optimize away some of it. /// Need to check if the compiler is able to optimize away some of it.
/// Possibly we should generate code that directly call the visitor instead /// Possibly we should generate code that directly call the visitor instead
pub fn visit_item_tree<Base>( pub fn visit_item_tree<Base>(
base: &Base, base: Pin<&Base>,
component: ComponentRefPin, component: ComponentRefPin,
item_tree: &[ItemTreeNode<Base>], item_tree: &[ItemTreeNode<Base>],
index: isize, index: isize,
mut visitor: vtable::VRefMut<ItemVisitorVTable>, mut visitor: vtable::VRefMut<ItemVisitorVTable>,
visit_dynamic: impl Fn(&Base, vtable::VRefMut<ItemVisitorVTable>, usize), visit_dynamic: impl Fn(Pin<&Base>, vtable::VRefMut<ItemVisitorVTable>, usize),
) { ) {
let mut visit_at_index = |idx: usize| match &item_tree[idx] { let mut visit_at_index = |idx: usize| match &item_tree[idx] {
ItemTreeNode::Item { item, .. } => { ItemTreeNode::Item { item, .. } => {
visitor.visit_item(component, idx as isize, item.apply(base)); visitor.visit_item(component, idx as isize, item.apply_pin(base));
} }
ItemTreeNode::DynamicTree { index } => visit_dynamic(base, visitor.borrow_mut(), *index), ItemTreeNode::DynamicTree { index } => visit_dynamic(base, visitor.borrow_mut(), *index),
}; };

View file

@ -108,7 +108,7 @@ unsafe extern "C" fn visit_children_item(
&*(component.get_vtable() as *const ComponentVTable as *const ComponentDescription); &*(component.get_vtable() as *const ComponentVTable as *const ComponentDescription);
let item_tree = &component_type.it; let item_tree = &component_type.it;
sixtyfps_corelib::item_tree::visit_item_tree( sixtyfps_corelib::item_tree::visit_item_tree(
&*(component.as_ptr() as *const Instance), Pin::new_unchecked(&*(component.as_ptr() as *const Instance)),
component, component,
item_tree.as_slice().into(), item_tree.as_slice().into(),
index, index,