From 2d22bac4514b9d4ca8ade2ed857ed03fdaa9af14 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 26 Jun 2020 13:18:04 +0200 Subject: [PATCH] Use Pin<&Self> for Property::get --- examples/rusttest/src/main.rs | 8 +-- examples/rusttest2/src/main.rs | 6 +- sixtyfps_compiler/generator/rust.rs | 30 ++++++--- sixtyfps_runtime/corelib/abi/primitives.rs | 67 +++++++++++--------- sixtyfps_runtime/corelib/abi/properties.rs | 71 +++++++++++++--------- 5 files changed, 108 insertions(+), 74 deletions(-) diff --git a/examples/rusttest/src/main.rs b/examples/rusttest/src/main.rs index eda6199dc..48d73be05 100644 --- a/examples/rusttest/src/main.rs +++ b/examples/rusttest/src/main.rs @@ -112,15 +112,15 @@ Hello := Rectangle { fn main() { let mut app = Hello::default(); - app.plus_clicked.set_handler(|context, ()| { let app = context.get_component::().unwrap(); - app.counter.set(app.counter.get(context) + 1); + let counter = Hello::field_offsets().counter.apply_pin(app); + counter.set(counter.get(context) + 1); }); app.minus_clicked.set_handler(|context, ()| { let app = context.get_component::().unwrap(); - app.counter.set(app.counter.get(context) - 1); + let counter = Hello::field_offsets().counter.apply_pin(app); + counter.set(counter.get(context) - 1); }); - app.run(); } diff --git a/examples/rusttest2/src/main.rs b/examples/rusttest2/src/main.rs index 291bb34fb..c7db99341 100644 --- a/examples/rusttest2/src/main.rs +++ b/examples/rusttest2/src/main.rs @@ -7,11 +7,13 @@ fn main() { app.plus_clicked.set_handler(|context, ()| { let app = context.get_component::().unwrap(); - app.counter.set(app.counter.get(context) + 1); + let counter = Hello::field_offsets().counter.apply_pin(app); + counter.set(counter.get(context) + 1); }); app.minus_clicked.set_handler(|context, ()| { let app = context.get_component::().unwrap(); - app.counter.set(app.counter.get(context) - 1); + let counter = Hello::field_offsets().counter.apply_pin(app); + counter.set(counter.get(context) - 1); }); app.run(); } diff --git a/sixtyfps_compiler/generator/rust.rs b/sixtyfps_compiler/generator/rust.rs index 743c381d3..6e5669639 100644 --- a/sixtyfps_compiler/generator/rust.rs +++ b/sixtyfps_compiler/generator/rust.rs @@ -55,7 +55,7 @@ pub fn generate(component: &Rc, diag: &mut Diagnostics) -> Option, diag: &mut Diagnostics) -> Option, diag: &mut Diagnostics) -> Option().unwrap()); if e.property_declarations.contains_key(name) { - (quote!(#comp.#name_ident), context) + (quote!(#component_id::field_offsets().#name_ident.apply_pin(#comp)), context) } else { let elem_ident = quote::format_ident!("{}", e.id); - (quote!(#comp.#elem_ident.#name_ident), context) + let elem_ty = quote::format_ident!("{}", e.base_type.as_builtin().class_name); + ( + quote!((#component_id::field_offsets().#elem_ident + #elem_ty::field_offsets().#name_ident) + .apply_pin(#comp) + ), + context, + ) } } else { access_member(element, name, &enclosing_component, quote!(#context.parent_context.unwrap())) @@ -438,14 +444,16 @@ fn compile_expression(e: &Expression, component: &Rc) -> TokenStream } Expression::RepeaterIndexReference { element } => { if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) { - quote!({ _self.index.get(context) }) + let component_id = component_id(&component); + quote!({ #component_id::field_offsets().index.apply_pin(_self).get(context) }) } else { todo!(); } } Expression::RepeaterModelReference { element } => { if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) { - quote!({ _self.model_data.get(context) }) + let component_id = component_id(&component); + quote!({ #component_id::field_offsets().model_data.apply_pin(_self).get(context) }) } else { todo!(); } @@ -554,6 +562,8 @@ fn compute_layout(component: &Component) -> TokenStream { let mut layouts = vec![]; for x in component.layout_constraints.borrow().0.iter() { let within = quote::format_ident!("{}", x.within.borrow().id); + let within_ty = + quote::format_ident!("{}", x.within.borrow().base_type.as_builtin().class_name); let row_constraint = vec![quote!(Constraint::default()); x.row_count()]; let col_constraint = vec![quote!(Constraint::default()); x.col_count()]; let cells = x @@ -594,8 +604,10 @@ fn compute_layout(component: &Component) -> TokenStream { solve_grid_layout(&GridLayoutData { row_constraint: Slice::from_slice(&[#(#row_constraint),*]), col_constraint: Slice::from_slice(&[#(#col_constraint),*]), - width: self.#within.width.get(eval_context), - height: self.#within.height.get(eval_context), + width: (Self::field_offsets().#within + #within_ty::field_offsets().width) + .apply_pin(self).get(eval_context), + height: (Self::field_offsets().#within + #within_ty::field_offsets().height) + .apply_pin(self).get(eval_context), x: 0., y: 0., cells: Slice::from_slice(&[#( Slice::from_slice(&[#( #cells ),*])),*]), diff --git a/sixtyfps_runtime/corelib/abi/primitives.rs b/sixtyfps_runtime/corelib/abi/primitives.rs index 094c1c593..5d914ff6e 100644 --- a/sixtyfps_runtime/corelib/abi/primitives.rs +++ b/sixtyfps_runtime/corelib/abi/primitives.rs @@ -42,25 +42,27 @@ pub struct Rectangle { impl Item for Rectangle { fn geometry(self: Pin<&Self>, context: &EvaluationContext) -> Rect { euclid::rect( - self.x.get(context), - self.y.get(context), - self.width.get(context), - self.height.get(context), + Self::field_offsets().x.apply_pin(self).get(context), + Self::field_offsets().y.apply_pin(self).get(context), + Self::field_offsets().width.apply_pin(self).get(context), + Self::field_offsets().height.apply_pin(self).get(context), ) } fn rendering_primitive( self: Pin<&Self>, context: &crate::EvaluationContext, ) -> RenderingPrimitive { - let width = self.width.get(context); - let height = self.height.get(context); + let width = Self::field_offsets().x.apply_pin(self).get(context); + let height = Self::field_offsets().height.apply_pin(self).get(context); if width > 0. && height > 0. { RenderingPrimitive::Rectangle { - x: self.x.get(context), - y: self.y.get(context), + x: Self::field_offsets().x.apply_pin(self).get(context), + y: Self::field_offsets().y.apply_pin(self).get(context), width, height, - color: Color::from_argb_encoded(self.color.get(context)), + color: Color::from_argb_encoded( + Self::field_offsets().color.apply_pin(self).get(context), + ), } } else { RenderingPrimitive::NoContents @@ -104,10 +106,10 @@ pub struct Image { impl Item for Image { fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect { euclid::rect( - self.x.get(context), - self.y.get(context), - self.width.get(context), - self.height.get(context), + Self::field_offsets().x.apply_pin(self).get(context), + Self::field_offsets().y.apply_pin(self).get(context), + Self::field_offsets().width.apply_pin(self).get(context), + Self::field_offsets().height.apply_pin(self).get(context), ) } fn rendering_primitive( @@ -115,9 +117,9 @@ impl Item for Image { context: &crate::EvaluationContext, ) -> RenderingPrimitive { RenderingPrimitive::Image { - x: self.x.get(context), - y: self.y.get(context), - source: self.source.get(context), + x: Self::field_offsets().x.apply_pin(self).get(context), + y: Self::field_offsets().y.apply_pin(self).get(context), + source: Self::field_offsets().source.apply_pin(self).get(context), } } @@ -160,19 +162,26 @@ pub struct Text { impl Item for Text { // FIXME: width / height. or maybe it doesn't matter? ( fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect { - euclid::rect(self.x.get(context), self.y.get(context), 0., 0.) + euclid::rect( + Self::field_offsets().x.apply_pin(self).get(context), + Self::field_offsets().y.apply_pin(self).get(context), + 0., + 0., + ) } fn rendering_primitive( self: Pin<&Self>, context: &crate::EvaluationContext, ) -> RenderingPrimitive { RenderingPrimitive::Text { - x: self.x.get(context), - y: self.y.get(context), - text: self.text.get(context), - font_family: self.font_family.get(context), - font_pixel_size: self.font_pixel_size.get(context), - color: Color::from_argb_encoded(self.color.get(context)), + x: Self::field_offsets().x.apply_pin(self).get(context), + y: Self::field_offsets().y.apply_pin(self).get(context), + text: Self::field_offsets().text.apply_pin(self).get(context), + font_family: Self::field_offsets().font_family.apply_pin(self).get(context), + font_pixel_size: Self::field_offsets().font_pixel_size.apply_pin(self).get(context), + color: Color::from_argb_encoded( + Self::field_offsets().color.apply_pin(self).get(context), + ), } } @@ -214,10 +223,10 @@ pub struct TouchArea { impl Item for TouchArea { fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect { euclid::rect( - self.x.get(context), - self.y.get(context), - self.width.get(context), - self.height.get(context), + Self::field_offsets().x.apply_pin(self).get(context), + Self::field_offsets().y.apply_pin(self).get(context), + Self::field_offsets().width.apply_pin(self).get(context), + Self::field_offsets().height.apply_pin(self).get(context), ) } fn rendering_primitive( @@ -237,13 +246,13 @@ impl Item for TouchArea { context: &crate::EvaluationContext, ) { println!("Touch Area Event {:?}", event); - self.pressed.set(match event.what { + Self::field_offsets().pressed.apply_pin(self).set(match event.what { super::datastructures::MouseEventType::MousePressed => true, super::datastructures::MouseEventType::MouseReleased => false, super::datastructures::MouseEventType::MouseMoved => return, }); if matches!(event.what, super::datastructures::MouseEventType::MouseReleased) { - self.clicked.emit(context, ()) + Self::field_offsets().clicked.apply_pin(self).emit(context, ()) } } } diff --git a/sixtyfps_runtime/corelib/abi/properties.rs b/sixtyfps_runtime/corelib/abi/properties.rs index 7c9e0e99c..f7a256ec8 100644 --- a/sixtyfps_runtime/corelib/abi/properties.rs +++ b/sixtyfps_runtime/corelib/abi/properties.rs @@ -9,6 +9,7 @@ use crate::abi::primitives::PropertyAnimation; use crate::ComponentRefPin; use core::cell::*; use core::ops::DerefMut; +use core::pin::Pin; use std::rc::{Rc, Weak}; thread_local!(static CURRENT_BINDING : RefCell>> = Default::default()); @@ -178,7 +179,7 @@ impl Property { /// /// The context must be the constext matching the Component which contains this /// property - pub fn get(&self, context: &EvaluationContext) -> T { + pub fn get(self: Pin<&Self>, context: &EvaluationContext) -> T { self.update(context); self.inner.clone().register_current_binding_as_dependency(); self.try_borrow().expect("Binding loop detected").1.clone() @@ -303,6 +304,10 @@ impl Property { #[test] fn properties_simple_test() { + fn g(prop: &Property, ctx: &EvaluationContext) -> i32 { + unsafe { Pin::new_unchecked(prop).get(ctx) } + } + #[derive(Default)] struct Component { width: Property, @@ -319,22 +324,22 @@ fn properties_simple_test() { let w = Rc::downgrade(&compo); compo.area.set_binding(move |ctx| { let compo = w.upgrade().unwrap(); - compo.width.get(ctx) * compo.height.get(ctx) + g(&compo.width, ctx) * g(&compo.height, ctx) }); compo.width.set(4); compo.height.set(8); - assert_eq!(compo.width.get(&dummy_eval_context), 4); - assert_eq!(compo.height.get(&dummy_eval_context), 8); - assert_eq!(compo.area.get(&dummy_eval_context), 4 * 8); + assert_eq!(g(&compo.width, &dummy_eval_context), 4); + assert_eq!(g(&compo.height, &dummy_eval_context), 8); + assert_eq!(g(&compo.area, &dummy_eval_context), 4 * 8); let w = Rc::downgrade(&compo); compo.width.set_binding(move |ctx| { let compo = w.upgrade().unwrap(); - compo.height.get(ctx) * 2 + g(&compo.height, ctx) * 2 }); - assert_eq!(compo.width.get(&dummy_eval_context), 8 * 2); - assert_eq!(compo.height.get(&dummy_eval_context), 8); - assert_eq!(compo.area.get(&dummy_eval_context), 8 * 8 * 2); + assert_eq!(g(&compo.width, &dummy_eval_context), 8 * 2); + assert_eq!(g(&compo.height, &dummy_eval_context), 8); + assert_eq!(g(&compo.area, &dummy_eval_context), 8 * 8 * 2); } #[allow(non_camel_case_types)] @@ -724,6 +729,9 @@ mod test { #[test] fn properties_test_animation_triggered_by_set() { + fn g(prop: &Property, ctx: &EvaluationContext) -> i32 { + unsafe { Pin::new_unchecked(prop).get(ctx) } + } let dummy_eval_context = EvaluationContext { component: unsafe { core::pin::Pin::new_unchecked(vtable::VRef::from_raw( @@ -738,38 +746,41 @@ mod test { let w = Rc::downgrade(&compo); compo.width_times_two.set_binding(move |context| { let compo = w.upgrade().unwrap(); - compo.width.get(context) * 2 + g(&compo.width, context) * 2 }); let animation_details = PropertyAnimation { duration: 10000 }; compo.width.set(100); - assert_eq!(compo.width.get(&dummy_eval_context), 100); - assert_eq!(compo.width_times_two.get(&dummy_eval_context), 200); + assert_eq!(g(&compo.width, &dummy_eval_context), 100); + assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200); let animation = compo.width.set_animated_value(200, &animation_details); - assert_eq!(compo.width.get(&dummy_eval_context), 100); - assert_eq!(compo.width_times_two.get(&dummy_eval_context), 200); + assert_eq!(g(&compo.width, &dummy_eval_context), 100); + assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200); assert_eq!(animation.borrow().from_value, 100); assert_eq!(animation.borrow().to_value, 200); animation.clone().update_animation_state(AnimationState::Running { progress: 0.5 }); - assert_eq!(compo.width.get(&dummy_eval_context), 150); - assert_eq!(compo.width_times_two.get(&dummy_eval_context), 300); + assert_eq!(g(&compo.width, &dummy_eval_context), 150); + assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 300); animation.clone().update_animation_state(AnimationState::Running { progress: 1.0 }); - assert_eq!(compo.width.get(&dummy_eval_context), 200); - assert_eq!(compo.width_times_two.get(&dummy_eval_context), 400); + assert_eq!(g(&compo.width, &dummy_eval_context), 200); + assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400); animation.clone().update_animation_state(AnimationState::Stopped); - assert_eq!(compo.width.get(&dummy_eval_context), 200); - assert_eq!(compo.width_times_two.get(&dummy_eval_context), 400); + assert_eq!(g(&compo.width, &dummy_eval_context), 200); + assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400); assert_eq!(Rc::strong_count(&animation), 1); } #[test] fn properties_test_animation_triggered_by_binding() { + fn g(prop: &Property, ctx: &EvaluationContext) -> i32 { + unsafe { Pin::new_unchecked(prop).get(ctx) } + } let dummy_eval_context = EvaluationContext { component: unsafe { core::pin::Pin::new_unchecked(vtable::VRef::from_raw( @@ -784,7 +795,7 @@ mod test { let w = Rc::downgrade(&compo); compo.width_times_two.set_binding(move |context| { let compo = w.upgrade().unwrap(); - compo.width.get(context) * 2 + g(&compo.width, context) * 2 }); let w = Rc::downgrade(&compo); @@ -794,29 +805,29 @@ mod test { let animation = compo.width.set_animated_binding( move |context| { let compo = w.upgrade().unwrap(); - compo.feed_property.get(context) + g(&compo.feed_property, context) }, &animation_details, ); compo.feed_property.set(100); - assert_eq!(compo.width.get(&dummy_eval_context), 100); - assert_eq!(compo.width_times_two.get(&dummy_eval_context), 200); + assert_eq!(g(&compo.width, &dummy_eval_context), 100); + assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200); compo.feed_property.set(200); - assert_eq!(compo.width.get(&dummy_eval_context), 100); - assert_eq!(compo.width_times_two.get(&dummy_eval_context), 200); + assert_eq!(g(&compo.width, &dummy_eval_context), 100); + assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200); animation.clone().update_animation_state(AnimationState::Running { progress: 0.5 }); - assert_eq!(compo.width.get(&dummy_eval_context), 150); - assert_eq!(compo.width_times_two.get(&dummy_eval_context), 300); + assert_eq!(g(&compo.width, &dummy_eval_context), 150); + assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 300); assert_eq!(animation.borrow().from_value, 100); assert_eq!(animation.borrow().to_value, 200); animation.clone().update_animation_state(AnimationState::Running { progress: 1.0 }); - assert_eq!(compo.width.get(&dummy_eval_context), 200); - assert_eq!(compo.width_times_two.get(&dummy_eval_context), 400); + assert_eq!(g(&compo.width, &dummy_eval_context), 200); + assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400); } }