From e00491811b38aab843e77698703c9ab8a7c077ba Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 13 Jul 2020 18:49:06 +0200 Subject: [PATCH] Get rid of the context in properties/signal --- api/sixtyfps-cpp/include/sixtyfps.h | 9 - api/sixtyfps-cpp/include/sixtyfps_color.h | 4 +- .../include/sixtyfps_properties.h | 16 +- api/sixtyfps-cpp/include/sixtyfps_signals.h | 8 +- api/sixtyfps-node/native/lib.rs | 8 +- api/sixtyfps-rs/lib.rs | 1 - examples/cpptest/main.cpp | 8 +- examples/rusttest/src/main.rs | 18 +- examples/rusttest2/src/main.rs | 19 +- sixtyfps_compiler/generator/cpp.rs | 84 ++---- sixtyfps_compiler/generator/rust.rs | 84 +++--- .../corelib/abi/datastructures.rs | 15 +- sixtyfps_runtime/corelib/abi/primitives.rs | 149 ++++------ sixtyfps_runtime/corelib/abi/properties.rs | 260 ++++++------------ sixtyfps_runtime/corelib/abi/signals.rs | 57 +--- sixtyfps_runtime/corelib/animations.rs | 10 +- sixtyfps_runtime/corelib/graphics.rs | 5 +- sixtyfps_runtime/corelib/input.rs | 6 +- sixtyfps_runtime/corelib/item_rendering.rs | 8 +- sixtyfps_runtime/corelib/item_tree.rs | 22 +- sixtyfps_runtime/corelib/lib.rs | 2 +- sixtyfps_runtime/corelib/rtti.rs | 27 +- .../interpreter/dynamic_component.rs | 96 ++++--- sixtyfps_runtime/interpreter/eval.rs | 104 +++---- sixtyfps_runtime/interpreter/lib.rs | 22 +- 25 files changed, 389 insertions(+), 653 deletions(-) diff --git a/api/sixtyfps-cpp/include/sixtyfps.h b/api/sixtyfps-cpp/include/sixtyfps.h index a208d306d..60f366ebe 100644 --- a/api/sixtyfps-cpp/include/sixtyfps.h +++ b/api/sixtyfps-cpp/include/sixtyfps.h @@ -46,7 +46,6 @@ private: internal::ComponentWindowOpaque inner; }; -using internal::EvaluationContext; using internal::Image; using internal::Path; using internal::Rectangle; @@ -69,14 +68,6 @@ constexpr inline ItemTreeNode make_dyn_node(std::uintptr_t offset) using internal::sixtyfps_visit_item_tree; -template -EvaluationContext evaluation_context_for_root_component(const Component *component) { - return EvaluationContext{ - VRef { &Component::component_type, const_cast(component)}, - nullptr, - }; -} - // layouts: using internal::Constraint; using internal::GridLayoutCellData; diff --git a/api/sixtyfps-cpp/include/sixtyfps_color.h b/api/sixtyfps-cpp/include/sixtyfps_color.h index 6a5c8a534..dad01663c 100644 --- a/api/sixtyfps-cpp/include/sixtyfps_color.h +++ b/api/sixtyfps-cpp/include/sixtyfps_color.h @@ -45,8 +45,8 @@ void Property::set_animated_binding(F binding, { internal::sixtyfps_property_set_animated_binding_color( &inner, - [](void *user_data, const internal::EvaluationContext *context, Color *value) { - *reinterpret_cast(value) = (*reinterpret_cast(user_data))(context); + [](void *user_data, Color *value) { + *reinterpret_cast(value) = (*reinterpret_cast(user_data))(); }, new F(binding), [](void *user_data) { delete reinterpret_cast(user_data); }, &animation_data); diff --git a/api/sixtyfps-cpp/include/sixtyfps_properties.h b/api/sixtyfps-cpp/include/sixtyfps_properties.h index e19891df4..dd454d074 100644 --- a/api/sixtyfps-cpp/include/sixtyfps_properties.h +++ b/api/sixtyfps-cpp/include/sixtyfps_properties.h @@ -31,9 +31,9 @@ struct Property internal::sixtyfps_property_set_changed(&inner); } - const T &get(const internal::EvaluationContext *context) const + const T &get() const { - internal::sixtyfps_property_update(&inner, context, &value); + internal::sixtyfps_property_update(&inner, &value); return value; } @@ -42,8 +42,8 @@ struct Property { internal::sixtyfps_property_set_binding( &inner, - [](void *user_data, const internal::EvaluationContext *context, void *value) { - *reinterpret_cast(value) = (*reinterpret_cast(user_data))(context); + [](void *user_data, void *value) { + *reinterpret_cast(value) = (*reinterpret_cast(user_data))(); }, new F(binding), [](void *user_data) { delete reinterpret_cast(user_data); }); } @@ -79,8 +79,8 @@ void Property::set_animated_binding(F binding, { internal::sixtyfps_property_set_animated_binding_int( &inner, - [](void *user_data, const internal::EvaluationContext *context, int32_t *value) { - *reinterpret_cast(value) = (*reinterpret_cast(user_data))(context); + [](void *user_data, int32_t *value) { + *reinterpret_cast(value) = (*reinterpret_cast(user_data))(); }, new F(binding), [](void *user_data) { delete reinterpret_cast(user_data); }, &animation_data); @@ -93,8 +93,8 @@ void Property::set_animated_binding(F binding, { internal::sixtyfps_property_set_animated_binding_float( &inner, - [](void *user_data, const internal::EvaluationContext *context, float *value) { - *reinterpret_cast(value) = (*reinterpret_cast(user_data))(context); + [](void *user_data, float *value) { + *reinterpret_cast(value) = (*reinterpret_cast(user_data))(); }, new F(binding), [](void *user_data) { delete reinterpret_cast(user_data); }, &animation_data); diff --git a/api/sixtyfps-cpp/include/sixtyfps_signals.h b/api/sixtyfps-cpp/include/sixtyfps_signals.h index d189f957c..d757c6ce1 100644 --- a/api/sixtyfps-cpp/include/sixtyfps_signals.h +++ b/api/sixtyfps-cpp/include/sixtyfps_signals.h @@ -18,15 +18,15 @@ struct Signal { internal::sixtyfps_signal_set_handler( &inner, - [](void *user_data, const internal::EvaluationContext *value) { - (*reinterpret_cast(user_data))(value); + [](void *user_data) { + (*reinterpret_cast(user_data))(); }, new F(binding), [](void *user_data) { delete reinterpret_cast(user_data); }); } - void emit(const internal::EvaluationContext *context) const + void emit() const { - internal::sixtyfps_signal_emit(&inner, context); + internal::sixtyfps_signal_emit(&inner); } private: diff --git a/api/sixtyfps-node/native/lib.rs b/api/sixtyfps-node/native/lib.rs index 6f7afdc98..6a39c4350 100644 --- a/api/sixtyfps-node/native/lib.rs +++ b/api/sixtyfps-node/native/lib.rs @@ -2,7 +2,7 @@ use core::cell::RefCell; use neon::prelude::*; use sixtyfps_compilerlib::typeregister::Type; use sixtyfps_corelib::abi::datastructures::Resource; -use sixtyfps_corelib::{ComponentRefPin, EvaluationContext}; +use sixtyfps_corelib::ComponentRefPin; use std::rc::Rc; @@ -65,7 +65,7 @@ fn create<'cx>( .set_signal_handler( component.borrow_mut(), prop_name.as_str(), - Box::new(move |_eval_ctx, ()| { + Box::new(move |()| { GLOBAL_CONTEXT.with(|cx_fn| { cx_fn(&move |cx, presistent_context| { presistent_context @@ -243,7 +243,7 @@ declare_types! { let x = this.borrow(&lock).0.clone(); let component = x.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?; let value = component.description() - .get_property(&EvaluationContext::for_root_component(component.borrow()), prop_name.as_str()) + .get_property(component.borrow(), prop_name.as_str()) .or_else(|_| cx.throw_error(format!("Cannot read property")))?; to_js_value(value, &mut cx) } @@ -275,7 +275,7 @@ declare_types! { let x = this.borrow(&lock).0.clone(); let component = x.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?; component.description() - .emit_signal(&EvaluationContext::for_root_component(component.borrow()), signal_name.as_str()) + .emit_signal(component.borrow(), signal_name.as_str()) .or_else(|_| cx.throw_error(format!("Cannot emit signal")))?; Ok(JsUndefined::new().as_value(&mut cx)) diff --git a/api/sixtyfps-rs/lib.rs b/api/sixtyfps-rs/lib.rs index 6f3ba666a..6af4493b0 100644 --- a/api/sixtyfps-rs/lib.rs +++ b/api/sixtyfps-rs/lib.rs @@ -86,7 +86,6 @@ pub mod re_exports { }; pub use sixtyfps_corelib::Color; pub use sixtyfps_corelib::ComponentVTable_static; - pub use sixtyfps_corelib::EvaluationContext; pub use sixtyfps_corelib::Resource; pub use sixtyfps_corelib::SharedArray; pub use sixtyfps_corelib::SharedString; diff --git a/examples/cpptest/main.cpp b/examples/cpptest/main.cpp index 31ff1a5d4..72a2e7c44 100644 --- a/examples/cpptest/main.cpp +++ b/examples/cpptest/main.cpp @@ -7,14 +7,14 @@ int main() component.foobar.set_handler([](auto...) { std::cout << "Hello from C++" << std::endl; }); - component.plus_clicked.set_handler([](auto ctx) { + component.plus_clicked.set_handler([]() { auto &counter = component.counter; - counter.set(counter.get(ctx) + 1); + counter.set(counter.get() + 1); }); - component.minus_clicked.set_handler([](auto ctx) { + component.minus_clicked.set_handler([]() { auto &counter = component.counter; - counter.set(counter.get(ctx) - 1); + counter.set(counter.get() - 1); }); sixtyfps::ComponentWindow window; diff --git a/examples/rusttest/src/main.rs b/examples/rusttest/src/main.rs index aa933ee65..ebcb55bcb 100644 --- a/examples/rusttest/src/main.rs +++ b/examples/rusttest/src/main.rs @@ -128,15 +128,17 @@ Hello := Rectangle { fn main() { let app = Hello::new(); - app.plus_clicked.set_handler(|context, ()| { - let app = context.get_component::().unwrap(); - let counter = Hello::field_offsets().counter.apply_pin(app); - counter.set(counter.get(context) + 1); + let app_weak = sixtyfps::re_exports::WeakPin::downgrade(app.clone()); + app.plus_clicked.set_handler(move |()| { + let app = app_weak.upgrade().unwrap(); + let counter = Hello::field_offsets().counter.apply_pin(app.as_ref()); + counter.set(counter.get() + 1); }); - app.minus_clicked.set_handler(|context, ()| { - let app = context.get_component::().unwrap(); - let counter = Hello::field_offsets().counter.apply_pin(app); - counter.set(counter.get(context) - 1); + let app_weak = sixtyfps::re_exports::WeakPin::downgrade(app.clone()); + app.minus_clicked.set_handler(move |()| { + let app = app_weak.upgrade().unwrap(); + let counter = Hello::field_offsets().counter.apply_pin(app.as_ref()); + counter.set(counter.get() - 1); }); app.run(); } diff --git a/examples/rusttest2/src/main.rs b/examples/rusttest2/src/main.rs index bdea3e6a3..d45426c5c 100644 --- a/examples/rusttest2/src/main.rs +++ b/examples/rusttest2/src/main.rs @@ -4,16 +4,17 @@ sixtyfps::include_modules!(); fn main() { let app = Hello::new(); - - app.plus_clicked.set_handler(|context, ()| { - let app = context.get_component::().unwrap(); - let counter = Hello::field_offsets().counter.apply_pin(app); - counter.set(counter.get(context) + 1); + let app_weak = sixtyfps::re_exports::WeakPin::downgrade(app.clone()); + app.plus_clicked.set_handler(move |()| { + let app = app_weak.upgrade().unwrap(); + let counter = Hello::field_offsets().counter.apply_pin(app.as_ref()); + counter.set(counter.get() + 1); }); - app.minus_clicked.set_handler(|context, ()| { - let app = context.get_component::().unwrap(); - let counter = Hello::field_offsets().counter.apply_pin(app); - counter.set(counter.get(context) - 1); + let app_weak = sixtyfps::re_exports::WeakPin::downgrade(app.clone()); + app.minus_clicked.set_handler(move |()| { + let app = app_weak.upgrade().unwrap(); + let counter = Hello::field_offsets().counter.apply_pin(app.as_ref()); + counter.set(counter.get() - 1); }); app.run(); } diff --git a/sixtyfps_compiler/generator/cpp.rs b/sixtyfps_compiler/generator/cpp.rs index a87121124..eab4769ea 100644 --- a/sixtyfps_compiler/generator/cpp.rs +++ b/sixtyfps_compiler/generator/cpp.rs @@ -247,13 +247,12 @@ fn handle_item(item: &Element, main_struct: &mut Struct, init: &mut Vec) format!( "{signal_accessor_prefix}{prop}.set_handler( - []([[maybe_unused]] const sixtyfps::EvaluationContext *context) {{ - [[maybe_unused]] auto self = reinterpret_cast(context->component.instance); + [this]() {{ + [[maybe_unused]] auto self = this; {code}; }});", signal_accessor_prefix = signal_accessor_prefix, prop = s, - ty = main_struct.name, code = compile_expression(i, &item.enclosing_component.upgrade().unwrap()) ) } else { @@ -267,7 +266,7 @@ fn handle_item(item: &Element, main_struct: &mut Struct, init: &mut Vec) let init = compile_expression(i, component); if i.is_constant() { - let setter = property_set_value_code(&component, item, s, init); + let setter = property_set_value_code(&component, item, s, init); format!( "{accessor_prefix}{cpp_prop}.{setter};", accessor_prefix = accessor_prefix, @@ -276,11 +275,10 @@ fn handle_item(item: &Element, main_struct: &mut Struct, init: &mut Vec) ) } else { let binding_code = format!( - "[]([[maybe_unused]] const sixtyfps::EvaluationContext *context) {{ - [[maybe_unused]] auto self = reinterpret_cast(context->component.instance); + "[this]() {{ + [[maybe_unused]] auto self = this; return {init}; }}", - ty = main_struct.name, init = init ); @@ -385,10 +383,7 @@ fn generate_component(file: &mut File, component: &Rc, diag: &mut Dia for (cpp_name, property_decl) in component.root_element.borrow().property_declarations.iter() { let ty = if property_decl.property_type == Type::Signal { if property_decl.expose_in_public_api && is_root { - let signal_emitter: Vec = vec![ - "[[maybe_unused]] auto context = sixtyfps::evaluation_context_for_root_component(this);".into(), - format!("{}.emit(&context);", cpp_name) - ]; + let signal_emitter: Vec = vec![format!("{}.emit();", cpp_name)]; component_struct.members.push(Declaration::Function(Function { name: format!("emit_{}", cpp_name), @@ -411,10 +406,7 @@ fn generate_component(file: &mut File, component: &Rc, diag: &mut Dia }); if property_decl.expose_in_public_api && is_root { - let prop_getter: Vec = vec![ - "[[maybe_unused]] auto context = sixtyfps::evaluation_context_for_root_component(this);".into(), - format!("return {}.get(&context);", cpp_name) - ]; + let prop_getter: Vec = vec![format!("return {}.get();", cpp_name)]; component_struct.members.push(Declaration::Function(Function { name: format!("get_{}", cpp_name), @@ -567,9 +559,7 @@ fn generate_component(file: &mut File, component: &Rc, diag: &mut Dia component_struct.members.push(Declaration::Function(Function { name: "compute_layout".into(), - signature: - "(sixtyfps::ComponentRef component, [[maybe_unused]] const sixtyfps::EvaluationContext *context) -> void" - .into(), + signature: "(sixtyfps::ComponentRef component) -> void".into(), is_static: true, statements: Some(compute_layout(component)), ..Default::default() @@ -601,8 +591,6 @@ fn generate_component(file: &mut File, component: &Rc, diag: &mut Dia "static const auto dyn_visit = [] (const uint8_t *base, [[maybe_unused]] sixtyfps::ItemVisitorRefMut visitor, uintptr_t dyn_index) {".to_owned(), format!(" [[maybe_unused]] auto self = reinterpret_cast(base);", component_id), // Fixme: this is not the root component - "auto context_ = sixtyfps::evaluation_context_for_root_component(self);".into(), - "[[maybe_unused]] auto context = &context_;".into(), format!(" switch(dyn_index) {{ {} }}\n }};", children_visitor_case.join("")), "return sixtyfps::sixtyfps_visit_item_tree(component, { const_cast*>(children), std::size(children)}, index, visitor, dyn_visit);".to_owned(), ]), @@ -627,28 +615,27 @@ fn component_id(component: &Rc) -> String { } } -/// Returns the code that can access the given property or signal from the context (but without the set or get) +/// Returns the code that can access the given property (but without the set or get) /// /// to be used like: /// ```ignore -/// let (access, context) = access_member(...) -/// format!("context.{access}.get({context})", ...) +/// let access = access_member(...); +/// format!("{}.get()", access) /// ``` fn access_member( element: &ElementRc, name: &str, component: &Rc, - context: &str, component_cpp: &str, -) -> (String, String) { +) -> String { let e = element.borrow(); let enclosing_component = e.enclosing_component.upgrade().unwrap(); if Rc::ptr_eq(component, &enclosing_component) { let e = element.borrow(); if e.property_declarations.contains_key(name) { - (format!("{}->{}", component_cpp, name), context.into()) + format!("{}->{}", component_cpp, name) } else { - (format!("{}->{}.{}", component_cpp, e.id.as_str(), name), context.into()) + format!("{}->{}.{}", component_cpp, e.id.as_str(), name) } } else { access_member( @@ -662,7 +649,6 @@ fn access_member( .enclosing_component .upgrade() .unwrap(), - &format!("{}->parent_context", context), &format!("{}->parent", component_cpp), ) } @@ -676,35 +662,25 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc n.to_string(), BoolLiteral(b) => b.to_string(), PropertyReference(NamedReference { element, name }) => { - let (access, context) = access_member( - &element.upgrade().unwrap(), - name.as_str(), - component, - "context", - "self", - ); - format!(r#"{}.get({})"#, access, context) + let access = + access_member(&element.upgrade().unwrap(), name.as_str(), component, "self"); + format!(r#"{}.get()"#, access) } SignalReference(NamedReference { element, name }) => { - let (access, context) = access_member( - &element.upgrade().unwrap(), - name.as_str(), - component, - "context", - "self", - ); - format!(r#"{}.emit({})"#, access, context) + let access = + access_member(&element.upgrade().unwrap(), name.as_str(), component, "self"); + format!(r#"{}.emit()"#, access) } RepeaterIndexReference { element } => { if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) { - "self->index.get(context)".to_owned() + "self->index.get()".to_owned() } else { todo!(); } } RepeaterModelReference { element } => { if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) { - "self->model_data.get(context)".to_owned() + "self->model_data.get()".to_owned() } else { todo!(); } @@ -748,19 +724,13 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc match &**lhs { PropertyReference(NamedReference { element, name }) => { - let (access, context) = access_member( - &element.upgrade().unwrap(), - name.as_str(), - component, - "context", - "self", - ); + let access = + access_member(&element.upgrade().unwrap(), name.as_str(), component, "self"); format!( - r#"{lhs}.set({lhs}.get({context}) {op} {rhs})"#, + r#"{lhs}.set({lhs}.get() {op} {rhs})"#, lhs = access, rhs = compile_expression(&*rhs, component), op = op, - context = context ) } _ => panic!("typechecking should make sure this was a PropertyReference"), @@ -894,8 +864,8 @@ fn compute_layout(component: &Rc) -> Vec { // FIXME: add auto conversion from std::array* to Slice res.push(" { row_constr.data(), row_constr.size() },".to_owned()); res.push(" { col_constr.data(), col_constr.size() },".to_owned()); - res.push(format!(" self->{}.width.get(context),", grid.within.borrow().id)); - res.push(format!(" self->{}.height.get(context),", grid.within.borrow().id)); + res.push(format!(" self->{}.width.get(),", grid.within.borrow().id)); + res.push(format!(" self->{}.height.get(),", grid.within.borrow().id)); res.push(" x, y,".to_owned()); res.push(" {cells, std::size(cells)}".to_owned()); res.push(" };".to_owned()); diff --git a/sixtyfps_compiler/generator/rust.rs b/sixtyfps_compiler/generator/rust.rs index cc97ee72e..9ddccf2d5 100644 --- a/sixtyfps_compiler/generator/rust.rs +++ b/sixtyfps_compiler/generator/rust.rs @@ -52,10 +52,7 @@ pub fn generate(component: &Rc, diag: &mut Diagnostics) -> Option) { - let eval_context = sixtyfps::re_exports::EvaluationContext::for_root_component( - sixtyfps::re_exports::ComponentRef::new_pin(self) - ); - Self::field_offsets().#prop_ident.apply_pin(self).emit(&eval_context, ()) + Self::field_offsets().#prop_ident.apply_pin(self).emit(()) } ) .into(), @@ -79,10 +76,7 @@ pub fn generate(component: &Rc, diag: &mut Diagnostics) -> Option) -> #rust_property_type { - let eval_context = sixtyfps::re_exports::EvaluationContext::for_root_component( - sixtyfps::re_exports::ComponentRef::new_pin(self) - ); - Self::field_offsets().#prop_ident.apply_pin(self).get(&eval_context) + Self::field_offsets().#prop_ident.apply_pin(self).get() } ) .into(), @@ -180,11 +174,6 @@ pub fn generate(component: &Rc, diag: &mut Diagnostics) -> Option, diag: &mut Diagnostics) -> Option().unwrap(); - #tokens_for_expression; + self_pinned.#rust_property.set_handler({ + let self_weak = sixtyfps::re_exports::WeakPin::downgrade(self_pinned.clone()); + move |()| { + let self_pinned = self_weak.upgrade().unwrap(); + let _self = self_pinned.as_ref(); + #tokens_for_expression; + } }); )); } else { @@ -246,7 +239,7 @@ pub fn generate(component: &Rc, diag: &mut Diagnostics) -> Option, - context: TokenStream, component_rust: TokenStream, -) -> (TokenStream, TokenStream) { +) -> TokenStream { let e = element.borrow(); let enclosing_component = e.enclosing_component.upgrade().unwrap(); @@ -471,15 +463,13 @@ fn access_member( let component_id = component_id(&enclosing_component); let name_ident = quote::format_ident!("{}", name); if e.property_declarations.contains_key(name) { - (quote!(#component_id::field_offsets().#name_ident.apply_pin(#component_rust)), context) + quote!(#component_id::field_offsets().#name_ident.apply_pin(#component_rust)) } else { let elem_ident = quote::format_ident!("{}", e.id); 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(#component_rust) - ), - context, + + quote!((#component_id::field_offsets().#elem_ident + #elem_ty::field_offsets().#name_ident) + .apply_pin(#component_rust) ) } } else { @@ -494,7 +484,6 @@ fn access_member( .enclosing_component .upgrade() .unwrap(), - quote!((&sixtyfps::re_exports::EvaluationContext::for_root_component(#context.component))), quote!(#component_rust.parent.upgrade().unwrap().as_ref()), ) } @@ -520,19 +509,14 @@ fn compile_expression(e: &Expression, component: &Rc) -> TokenStream } } Expression::PropertyReference(NamedReference { element, name }) => { - let (access, context) = access_member( - &element.upgrade().unwrap(), - name.as_str(), - component, - quote!(context), - quote!(_self), - ); - quote!(#access.get(#context)) + let access = + access_member(&element.upgrade().unwrap(), name.as_str(), component, quote!(_self)); + quote!(#access.get()) } Expression::RepeaterIndexReference { element } => { if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) { let component_id = component_id(&component); - quote!({ #component_id::field_offsets().index.apply_pin(_self).get(context) }) + quote!({ #component_id::field_offsets().index.apply_pin(_self).get() }) } else { todo!(); } @@ -540,7 +524,7 @@ fn compile_expression(e: &Expression, component: &Rc) -> TokenStream Expression::RepeaterModelReference { element } => { if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) { let component_id = component_id(&component); - quote!({ #component_id::field_offsets().model_data.apply_pin(_self).get(context) }) + quote!({ #component_id::field_offsets().model_data.apply_pin(_self).get() }) } else { todo!(); } @@ -562,14 +546,9 @@ fn compile_expression(e: &Expression, component: &Rc) -> TokenStream quote!({ #(#map);* }) } Expression::SignalReference(NamedReference { element, name, .. }) => { - let (access, context) = access_member( - &element.upgrade().unwrap(), - name.as_str(), - component, - quote!(context), - quote!(_self), - ); - quote!(#access.emit(#context, ())) + let access = + access_member(&element.upgrade().unwrap(), name.as_str(), component, quote!(_self)); + quote!(#access.emit(())) } Expression::FunctionCall { function } => { if matches!(function.ty(), Type::Signal) { @@ -581,16 +560,15 @@ fn compile_expression(e: &Expression, component: &Rc) -> TokenStream } Expression::SelfAssignment { lhs, rhs, op } => match &**lhs { Expression::PropertyReference(NamedReference { element, name }) => { - let (lhs, context) = access_member( + let lhs = access_member( &element.upgrade().unwrap(), name.as_str(), component, - quote!(context), quote!(_self), ); let rhs = compile_expression(&*rhs, &component); let op = proc_macro2::Punct::new(*op, proc_macro2::Spacing::Alone); - quote!( #lhs.set(#lhs.get(#context) #op &((#rhs) as _) )) + quote!( #lhs.set(#lhs.get() #op &((#rhs) as _) )) } _ => panic!("typechecking should make sure this was a PropertyReference"), }, @@ -725,9 +703,9 @@ fn compute_layout(component: &Rc) -> TokenStream { row_constraint: Slice::from_slice(&[#(#row_constraint),*]), col_constraint: Slice::from_slice(&[#(#col_constraint),*]), width: (Self::field_offsets().#within + #within_ty::field_offsets().width) - .apply_pin(self).get(context), + .apply_pin(self).get(), height: (Self::field_offsets().#within + #within_ty::field_offsets().height) - .apply_pin(self).get(context), + .apply_pin(self).get(), x: #x_pos, y: #y_pos, cells: Slice::from_slice(&[#( Slice::from_slice(&[#( #cells ),*])),*]), @@ -781,7 +759,7 @@ fn compute_layout(component: &Rc) -> TokenStream { fn layout_info(self: ::core::pin::Pin<&Self>) -> sixtyfps::re_exports::LayoutInfo { todo!("Implement in rust.rs") } - fn compute_layout(self: ::core::pin::Pin<&Self>, context: &sixtyfps::re_exports::EvaluationContext) { + fn compute_layout(self: ::core::pin::Pin<&Self>) { #![allow(unused)] use sixtyfps::re_exports::*; let dummy = Property::::default(); diff --git a/sixtyfps_runtime/corelib/abi/datastructures.rs b/sixtyfps_runtime/corelib/abi/datastructures.rs index b70ba9ab2..fb6d7ded3 100644 --- a/sixtyfps_runtime/corelib/abi/datastructures.rs +++ b/sixtyfps_runtime/corelib/abi/datastructures.rs @@ -1,7 +1,6 @@ //! This module contains the basic datastructures that are exposed to the C API use super::slice::Slice; -use crate::EvaluationContext; use core::pin::Pin; use std::cell::Cell; use vtable::*; @@ -53,8 +52,7 @@ pub struct ComponentVTable { pub layout_info: extern "C" fn(core::pin::Pin>) -> LayoutInfo, /// Will compute the layout of - pub compute_layout: - extern "C" fn(core::pin::Pin>, eval_context: &EvaluationContext), + pub compute_layout: extern "C" fn(core::pin::Pin>), } /// This structure must be present in items that are Rendered and contains information. @@ -111,8 +109,7 @@ pub enum ItemTreeNode { #[repr(C)] pub struct ItemVTable { /// Returns the geometry of this item (relative to its parent item) - pub geometry: - extern "C" fn(core::pin::Pin>, context: &crate::EvaluationContext) -> Rect, + pub geometry: extern "C" fn(core::pin::Pin>) -> Rect, /// offset in bytes fromthe *const ItemImpl. /// isize::MAX means None @@ -121,17 +118,13 @@ pub struct ItemVTable { pub cached_rendering_data_offset: usize, /// Return the rendering primitive used to display this item. - pub rendering_primitive: extern "C" fn( - core::pin::Pin>, - context: &crate::EvaluationContext, - ) -> RenderingPrimitive, + pub rendering_primitive: extern "C" fn(core::pin::Pin>) -> RenderingPrimitive, /// We would need max/min/preferred size, and all layout info pub layouting_info: extern "C" fn(core::pin::Pin>) -> LayoutInfo, /// input event - pub input_event: - extern "C" fn(core::pin::Pin>, MouseEvent, &crate::EvaluationContext), + pub input_event: extern "C" fn(core::pin::Pin>, MouseEvent), } /// The constraint that applies to an item diff --git a/sixtyfps_runtime/corelib/abi/primitives.rs b/sixtyfps_runtime/corelib/abi/primitives.rs index 0f89b6080..11bf9cdfb 100644 --- a/sixtyfps_runtime/corelib/abi/primitives.rs +++ b/sixtyfps_runtime/corelib/abi/primitives.rs @@ -21,7 +21,7 @@ use super::datastructures::{ }; #[cfg(feature = "rtti")] use crate::rtti::*; -use crate::{EvaluationContext, Property, SharedString, Signal}; +use crate::{Property, SharedString, Signal}; use const_field_offset::FieldOffsets; use core::pin::Pin; use corelib_macro::*; @@ -40,27 +40,24 @@ pub struct Rectangle { } impl Item for Rectangle { - fn geometry(self: Pin<&Self>, context: &EvaluationContext) -> Rect { + fn geometry(self: Pin<&Self>) -> Rect { euclid::rect( - 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), + Self::field_offsets().x.apply_pin(self).get(), + Self::field_offsets().y.apply_pin(self).get(), + Self::field_offsets().width.apply_pin(self).get(), + Self::field_offsets().height.apply_pin(self).get(), ) } - fn rendering_primitive( - self: Pin<&Self>, - context: &crate::EvaluationContext, - ) -> RenderingPrimitive { - let width = Self::field_offsets().width.apply_pin(self).get(context); - let height = Self::field_offsets().height.apply_pin(self).get(context); + fn rendering_primitive(self: Pin<&Self>) -> RenderingPrimitive { + let width = Self::field_offsets().width.apply_pin(self).get(); + let height = Self::field_offsets().height.apply_pin(self).get(); if width > 0. && height > 0. { RenderingPrimitive::Rectangle { - x: Self::field_offsets().x.apply_pin(self).get(context), - y: Self::field_offsets().y.apply_pin(self).get(context), + x: Self::field_offsets().x.apply_pin(self).get(), + y: Self::field_offsets().y.apply_pin(self).get(), width, height, - color: Self::field_offsets().color.apply_pin(self).get(context), + color: Self::field_offsets().color.apply_pin(self).get(), } } else { RenderingPrimitive::NoContents @@ -71,12 +68,7 @@ impl Item for Rectangle { Default::default() } - fn input_event( - self: Pin<&Self>, - _: super::datastructures::MouseEvent, - _: &crate::EvaluationContext, - ) { - } + fn input_event(self: Pin<&Self>, _: super::datastructures::MouseEvent) {} } impl ItemConsts for Rectangle { @@ -102,22 +94,19 @@ pub struct Image { } impl Item for Image { - fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect { + fn geometry(self: Pin<&Self>) -> Rect { euclid::rect( - 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), + Self::field_offsets().x.apply_pin(self).get(), + Self::field_offsets().y.apply_pin(self).get(), + Self::field_offsets().width.apply_pin(self).get(), + Self::field_offsets().height.apply_pin(self).get(), ) } - fn rendering_primitive( - self: Pin<&Self>, - context: &crate::EvaluationContext, - ) -> RenderingPrimitive { + fn rendering_primitive(self: Pin<&Self>) -> RenderingPrimitive { RenderingPrimitive::Image { - 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), + x: Self::field_offsets().x.apply_pin(self).get(), + y: Self::field_offsets().y.apply_pin(self).get(), + source: Self::field_offsets().source.apply_pin(self).get(), } } @@ -126,12 +115,7 @@ impl Item for Image { Default::default() } - fn input_event( - self: Pin<&Self>, - _: super::datastructures::MouseEvent, - _: &crate::EvaluationContext, - ) { - } + fn input_event(self: Pin<&Self>, _: super::datastructures::MouseEvent) {} } impl ItemConsts for Image { @@ -159,25 +143,22 @@ 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 { + fn geometry(self: Pin<&Self>) -> Rect { euclid::rect( - Self::field_offsets().x.apply_pin(self).get(context), - Self::field_offsets().y.apply_pin(self).get(context), + Self::field_offsets().x.apply_pin(self).get(), + Self::field_offsets().y.apply_pin(self).get(), 0., 0., ) } - fn rendering_primitive( - self: Pin<&Self>, - context: &crate::EvaluationContext, - ) -> RenderingPrimitive { + fn rendering_primitive(self: Pin<&Self>) -> RenderingPrimitive { RenderingPrimitive::Text { - 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: Self::field_offsets().color.apply_pin(self).get(context), + x: Self::field_offsets().x.apply_pin(self).get(), + y: Self::field_offsets().y.apply_pin(self).get(), + text: Self::field_offsets().text.apply_pin(self).get(), + font_family: Self::field_offsets().font_family.apply_pin(self).get(), + font_pixel_size: Self::field_offsets().font_pixel_size.apply_pin(self).get(), + color: Self::field_offsets().color.apply_pin(self).get(), } } @@ -185,12 +166,7 @@ impl Item for Text { todo!() } - fn input_event( - self: Pin<&Self>, - _: super::datastructures::MouseEvent, - _: &crate::EvaluationContext, - ) { - } + fn input_event(self: Pin<&Self>, _: super::datastructures::MouseEvent) {} } impl ItemConsts for Text { @@ -217,18 +193,15 @@ pub struct TouchArea { } impl Item for TouchArea { - fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect { + fn geometry(self: Pin<&Self>) -> Rect { euclid::rect( - 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), + Self::field_offsets().x.apply_pin(self).get(), + Self::field_offsets().y.apply_pin(self).get(), + Self::field_offsets().width.apply_pin(self).get(), + Self::field_offsets().height.apply_pin(self).get(), ) } - fn rendering_primitive( - self: Pin<&Self>, - _context: &crate::EvaluationContext, - ) -> RenderingPrimitive { + fn rendering_primitive(self: Pin<&Self>) -> RenderingPrimitive { RenderingPrimitive::NoContents } @@ -236,11 +209,7 @@ impl Item for TouchArea { todo!() } - fn input_event( - self: Pin<&Self>, - event: super::datastructures::MouseEvent, - context: &crate::EvaluationContext, - ) { + fn input_event(self: Pin<&Self>, event: super::datastructures::MouseEvent) { println!("Touch Area Event {:?}", event); Self::field_offsets().pressed.apply_pin(self).set(match event.what { super::datastructures::MouseEventType::MousePressed => true, @@ -248,7 +217,7 @@ impl Item for TouchArea { super::datastructures::MouseEventType::MouseMoved => return, }); if matches!(event.what, super::datastructures::MouseEventType::MouseReleased) { - Self::field_offsets().clicked.apply_pin(self).emit(context, ()) + Self::field_offsets().clicked.apply_pin(self).emit(()) } } } @@ -278,27 +247,24 @@ pub struct Path { } impl Item for Path { - fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect { + fn geometry(self: Pin<&Self>) -> Rect { euclid::rect( - Self::field_offsets().x.apply_pin(self).get(context), - Self::field_offsets().y.apply_pin(self).get(context), + Self::field_offsets().x.apply_pin(self).get(), + Self::field_offsets().y.apply_pin(self).get(), 0., 0., ) } - fn rendering_primitive( - self: Pin<&Self>, - context: &crate::EvaluationContext, - ) -> RenderingPrimitive { + fn rendering_primitive(self: Pin<&Self>) -> RenderingPrimitive { RenderingPrimitive::Path { - x: Self::field_offsets().x.apply_pin(self).get(context), - y: Self::field_offsets().y.apply_pin(self).get(context), - width: Self::field_offsets().width.apply_pin(self).get(context), - height: Self::field_offsets().height.apply_pin(self).get(context), - elements: Self::field_offsets().elements.apply_pin(self).get(context), - fill_color: Self::field_offsets().fill_color.apply_pin(self).get(context), - stroke_color: Self::field_offsets().stroke_color.apply_pin(self).get(context), - stroke_width: Self::field_offsets().stroke_width.apply_pin(self).get(context), + x: Self::field_offsets().x.apply_pin(self).get(), + y: Self::field_offsets().y.apply_pin(self).get(), + width: Self::field_offsets().width.apply_pin(self).get(), + height: Self::field_offsets().height.apply_pin(self).get(), + elements: Self::field_offsets().elements.apply_pin(self).get(), + fill_color: Self::field_offsets().fill_color.apply_pin(self).get(), + stroke_color: Self::field_offsets().stroke_color.apply_pin(self).get(), + stroke_width: Self::field_offsets().stroke_width.apply_pin(self).get(), } } @@ -306,12 +272,7 @@ impl Item for Path { todo!() } - fn input_event( - self: Pin<&Self>, - _: super::datastructures::MouseEvent, - _: &crate::EvaluationContext, - ) { - } + fn input_event(self: Pin<&Self>, _: super::datastructures::MouseEvent) {} } impl ItemConsts for Path { diff --git a/sixtyfps_runtime/corelib/abi/properties.rs b/sixtyfps_runtime/corelib/abi/properties.rs index 7b6b20014..98e97f243 100644 --- a/sixtyfps_runtime/corelib/abi/properties.rs +++ b/sixtyfps_runtime/corelib/abi/properties.rs @@ -66,45 +66,6 @@ use core::{marker::PhantomPinned, pin::Pin}; use crate::abi::datastructures::Color; use crate::abi::primitives::PropertyAnimation; -use crate::ComponentRefPin; - -/// This structure contains what is required for the property engine to evaluate properties -/// -/// One must pass it to the getter of the property, or emit of signals, and it can -/// be accessed from the bindings -#[repr(C)] -pub struct EvaluationContext<'a> { - /// The component which contains the Property or the Signal - pub component: core::pin::Pin>, - - /// The context of the parent component - pub parent_context: Option<&'a EvaluationContext<'a>>, -} - -impl<'a> EvaluationContext<'a> { - /// Create a new context related to the root component - /// - /// The component need to be a root component, otherwise fetching properties - /// might panic. - pub fn for_root_component(component: ComponentRefPin<'a>) -> Self { - Self { component, parent_context: None } - } - - /// Create a context for a child component of a component within the current - /// context. - pub fn child_context(&'a self, child: ComponentRefPin<'a>) -> Self { - Self { component: child, parent_context: Some(self) } - } - - /// Attempt to cast the component to the given type - pub fn get_component< - T: vtable::HasStaticVTable, - >( - &'a self, - ) -> Option> { - vtable::VRef::downcast_pin(self.component) - } -} /// The return value of a binding #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -118,11 +79,7 @@ enum BindingResult { struct BindingVTable { drop: unsafe fn(_self: *mut BindingHolder), - evaluate: unsafe fn( - _self: *mut BindingHolder, - value: *mut (), - context: &EvaluationContext, - ) -> BindingResult, + evaluate: unsafe fn(_self: *mut BindingHolder, value: *mut ()) -> BindingResult, mark_dirty: unsafe fn(_self: *const BindingHolder), } @@ -130,24 +87,16 @@ struct BindingVTable { trait BindingCallable { /// This function is called by the property to evaluate the binding and produce a new value. The /// previous property value is provided in the value parameter. - unsafe fn evaluate( - self: Pin<&Self>, - value: *mut (), - context: &EvaluationContext, - ) -> BindingResult; + unsafe fn evaluate(self: Pin<&Self>, value: *mut ()) -> BindingResult; /// This function is used to notify the binding that one of the dependencies was changed /// and therefore this binding may evaluate to a different value, too. fn mark_dirty(self: Pin<&Self>) {} } -impl BindingResult> BindingCallable for F { - unsafe fn evaluate( - self: Pin<&Self>, - value: *mut (), - context: &EvaluationContext, - ) -> BindingResult { - self(value, context) +impl BindingResult> BindingCallable for F { + unsafe fn evaluate(self: Pin<&Self>, value: *mut ()) -> BindingResult { + self(value) } } @@ -178,12 +127,10 @@ fn alloc_binding_holder(binding: B) -> *mut Bindin unsafe fn evaluate( _self: *mut BindingHolder, value: *mut (), - context: &EvaluationContext, ) -> BindingResult { let pinned_holder = Pin::new_unchecked(&*_self); CURRENT_BINDING.set(pinned_holder, || { - Pin::new_unchecked(&((*(_self as *mut BindingHolder)).binding)) - .evaluate(value, context) + Pin::new_unchecked(&((*(_self as *mut BindingHolder)).binding)).evaluate(value) }) } @@ -384,7 +331,7 @@ impl PropertyHandle { // `value` is the content of the unsafe cell and will be only dereferenced if the // handle is not locked. (Upholding the requirements of UnsafeCell) - unsafe fn update(&self, value: *mut T, context: &EvaluationContext) { + unsafe fn update(&self, value: *mut T) { let remove = self.access(|binding| { if let Some(mut binding) = binding { if binding.dirty.get() { @@ -393,7 +340,6 @@ impl PropertyHandle { let r = (binding.vtable.evaluate)( binding.as_mut().get_unchecked_mut() as *mut BindingHolder, value as *mut (), - context, ); binding.dirty.set(false); if r == BindingResult::RemoveBinding { @@ -489,8 +435,8 @@ impl Property { /// /// Panics if this property is get while evaluating its own binding or /// cloning the value. - pub fn get(self: Pin<&Self>, context: &EvaluationContext) -> T { - unsafe { self.handle.update(self.value.get(), context) }; + pub fn get(self: Pin<&Self>) -> T { + unsafe { self.handle.update(self.value.get()) }; self.handle.register_as_dependency_to_current_binding(); self.get_internal() } @@ -522,10 +468,10 @@ impl Property { /// /// If other properties have bindings depending of this property, these properties will /// be marked as dirty. - //FIXME pub fn set_binding(self: Pin<&Self>, f: impl (Fn(&EvaluationContext) -> T) + 'static) { - pub fn set_binding(&self, f: impl (Fn(&EvaluationContext) -> T) + 'static) { - self.handle.set_binding(move |val: *mut (), context: &EvaluationContext| unsafe { - *(val as *mut T) = f(context); + //FIXME pub fn set_binding(self: Pin<&Self>, f: impl (Fn() -> T) + 'static) { + pub fn set_binding(&self, f: impl (Fn() -> T) + 'static) { + self.handle.set_binding(move |val: *mut ()| unsafe { + *(val as *mut T) = f(); BindingResult::KeepBinding }); self.handle.mark_dirty(); @@ -542,7 +488,7 @@ impl Property { pub fn set_animated_value(&self, value: T, animation_data: &PropertyAnimation) { // FIXME if the current value is a dirty binding, we must run it, but we do not have the context let d = PropertyValueAnimationData::new(self.get_internal(), value, animation_data.clone()); - self.handle.set_binding(move |val: *mut (), _context: &EvaluationContext| unsafe { + self.handle.set_binding(move |val: *mut ()| unsafe { let (value, finished) = d.compute_interpolated_value(); *(val as *mut T) = value; if finished { @@ -559,14 +505,14 @@ impl Property { /// pub fn set_animated_binding( &self, - f: impl (Fn(&EvaluationContext) -> T) + 'static, + f: impl (Fn() -> T) + 'static, animation_data: &PropertyAnimation, ) { self.handle.set_binding(AnimatedBindingCallable:: { original_binding: PropertyHandle { handle: Cell::new( - (alloc_binding_holder(move |val: *mut (), context: &EvaluationContext| unsafe { - *(val as *mut T) = f(context); + (alloc_binding_holder(move |val: *mut ()| unsafe { + *(val as *mut T) = f(); BindingResult::KeepBinding }) as usize) | 0b10, @@ -626,11 +572,7 @@ struct AnimatedBindingCallable { } impl BindingCallable for AnimatedBindingCallable { - unsafe fn evaluate( - self: Pin<&Self>, - value: *mut (), - context: &EvaluationContext, - ) -> BindingResult { + unsafe fn evaluate(self: Pin<&Self>, value: *mut ()) -> BindingResult { self.original_binding.register_as_dependency_to_current_binding(); match self.state.get() { AnimatedBindingState::Animating => { @@ -644,15 +586,14 @@ impl BindingCallable for AnimatedBindingCallable { - self.original_binding.update(value, context); + self.original_binding.update(value); } AnimatedBindingState::ShouldStart => { let value = &mut *(value as *mut T); self.state.set(AnimatedBindingState::Animating); let mut animation_data = self.animation_data.borrow_mut(); animation_data.from_value = value.clone(); - self.original_binding - .update((&mut animation_data.to_value) as *mut T as *mut (), context); + self.original_binding.update((&mut animation_data.to_value) as *mut T as *mut ()); let (val, finished) = animation_data.compute_interpolated_value(); *value = val; if finished { @@ -682,8 +623,8 @@ impl BindingCallable for AnimatedBindingCallable, ctx: &EvaluationContext) -> i32 { - unsafe { Pin::new_unchecked(prop).get(ctx) } + fn g(prop: &Property) -> i32 { + unsafe { Pin::new_unchecked(prop).get() } } #[derive(Default)] @@ -692,32 +633,27 @@ fn properties_simple_test() { height: Property, area: Property, } - let dummy_eval_context = EvaluationContext::for_root_component(unsafe { - core::pin::Pin::new_unchecked(vtable::VRef::from_raw( - core::ptr::NonNull::dangling(), - core::ptr::NonNull::dangling(), - )) - }); + let compo = Rc::pin(Component::default()); let w = WeakPin::downgrade(compo.clone()); - compo.area.set_binding(move |ctx| { + compo.area.set_binding(move || { let compo = w.upgrade().unwrap(); - g(&compo.width, ctx) * g(&compo.height, ctx) + g(&compo.width) * g(&compo.height) }); compo.width.set(4); compo.height.set(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); + assert_eq!(g(&compo.width), 4); + assert_eq!(g(&compo.height), 8); + assert_eq!(g(&compo.area), 4 * 8); let w = WeakPin::downgrade(compo.clone()); - compo.width.set_binding(move |ctx| { + compo.width.set_binding(move || { let compo = w.upgrade().unwrap(); - g(&compo.height, ctx) * 2 + g(&compo.height) * 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); + assert_eq!(g(&compo.width), 8 * 2); + assert_eq!(g(&compo.height), 8); + assert_eq!(g(&compo.area), 8 * 8 * 2); } #[allow(non_camel_case_types)] @@ -735,12 +671,8 @@ pub unsafe extern "C" fn sixtyfps_property_init(out: *mut PropertyHandleOpaque) /// To be called before accessing the value #[no_mangle] -pub unsafe extern "C" fn sixtyfps_property_update( - handle: &PropertyHandleOpaque, - context: &EvaluationContext, - val: *mut c_void, -) { - handle.0.update(val, context); +pub unsafe extern "C" fn sixtyfps_property_update(handle: &PropertyHandleOpaque, val: *mut c_void) { + handle.0.update(val); handle.0.register_as_dependency_to_current_binding(); } @@ -753,12 +685,12 @@ pub unsafe extern "C" fn sixtyfps_property_set_changed(handle: &PropertyHandleOp } fn make_c_function_binding( - binding: extern "C" fn(*mut c_void, &EvaluationContext, *mut c_void), + binding: extern "C" fn(*mut c_void, *mut c_void), user_data: *mut c_void, drop_user_data: Option, -) -> impl Fn(*mut (), &EvaluationContext) -> BindingResult { +) -> impl Fn(*mut ()) -> BindingResult { struct CFunctionBinding { - binding_function: extern "C" fn(*mut c_void, &EvaluationContext, *mut T), + binding_function: extern "C" fn(*mut c_void, *mut T), user_data: *mut c_void, drop_user_data: Option, } @@ -773,14 +705,13 @@ fn make_c_function_binding( let b = CFunctionBinding { binding_function: binding, user_data, drop_user_data }; - move |value_ptr, context| { - (b.binding_function)(b.user_data, context, value_ptr); + move |value_ptr| { + (b.binding_function)(b.user_data, value_ptr); BindingResult::KeepBinding } } /// Set a binding -/// The binding has signature fn(user_data, context, pointer_to_value) /// /// The current implementation will do usually two memory alocation: /// 1. the allocation from the calling code to allocate user_data @@ -790,11 +721,7 @@ fn make_c_function_binding( #[no_mangle] pub unsafe extern "C" fn sixtyfps_property_set_binding( handle: &PropertyHandleOpaque, - binding: extern "C" fn( - user_data: *mut c_void, - context: &EvaluationContext, - pointer_to_value: *mut c_void, - ), + binding: extern "C" fn(user_data: *mut c_void, pointer_to_value: *mut c_void), user_data: *mut c_void, drop_user_data: Option, ) { @@ -845,7 +772,7 @@ fn c_set_animated_value( animation_data: &crate::abi::primitives::PropertyAnimation, ) { let d = PropertyValueAnimationData::new(from, to, animation_data.clone()); - handle.0.set_binding(move |val: *mut (), _: &EvaluationContext| { + handle.0.set_binding(move |val: *mut ()| { let (value, finished) = d.compute_interpolated_value(); unsafe { *(val as *mut T) = value; @@ -895,14 +822,14 @@ pub unsafe extern "C" fn sixtyfps_property_set_animated_value_color( unsafe fn c_set_animated_binding( handle: &PropertyHandleOpaque, - binding: extern "C" fn(*mut c_void, &EvaluationContext, *mut T), + binding: extern "C" fn(*mut c_void, *mut T), user_data: *mut c_void, drop_user_data: Option, animation_data: &crate::abi::primitives::PropertyAnimation, ) { let binding = core::mem::transmute::< - extern "C" fn(*mut c_void, &EvaluationContext, *mut T), - extern "C" fn(*mut c_void, &EvaluationContext, *mut ()), + extern "C" fn(*mut c_void, *mut T), + extern "C" fn(*mut c_void, *mut ()), >(binding); handle.0.set_binding(AnimatedBindingCallable:: { original_binding: PropertyHandle { @@ -926,7 +853,7 @@ unsafe fn c_set_animated_binding( #[no_mangle] pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_int( handle: &PropertyHandleOpaque, - binding: extern "C" fn(*mut c_void, &EvaluationContext, *mut i32), + binding: extern "C" fn(*mut c_void, *mut i32), user_data: *mut c_void, drop_user_data: Option, animation_data: &crate::abi::primitives::PropertyAnimation, @@ -938,7 +865,7 @@ pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_int( #[no_mangle] pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_float( handle: &PropertyHandleOpaque, - binding: extern "C" fn(*mut c_void, &EvaluationContext, *mut f32), + binding: extern "C" fn(*mut c_void, *mut f32), user_data: *mut c_void, drop_user_data: Option, animation_data: &crate::abi::primitives::PropertyAnimation, @@ -950,7 +877,7 @@ pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_float( #[no_mangle] pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_color( handle: &PropertyHandleOpaque, - binding: extern "C" fn(*mut c_void, &EvaluationContext, *mut Color), + binding: extern "C" fn(*mut c_void, *mut Color), user_data: *mut c_void, drop_user_data: Option, animation_data: &crate::abi::primitives::PropertyAnimation, @@ -975,52 +902,44 @@ mod animation_tests { #[test] fn properties_test_animation_triggered_by_set() { - fn g(prop: &Property, ctx: &EvaluationContext) -> i32 { - unsafe { Pin::new_unchecked(prop).get(ctx) } + fn g(prop: &Property) -> i32 { + unsafe { Pin::new_unchecked(prop).get() } } - let dummy_eval_context = EvaluationContext { - component: unsafe { - core::pin::Pin::new_unchecked(vtable::VRef::from_raw( - core::ptr::NonNull::dangling(), - core::ptr::NonNull::dangling(), - )) - }, - parent_context: None, - }; + let compo = Rc::new(Component::default()); let w = Rc::downgrade(&compo); - compo.width_times_two.set_binding(move |context| { + compo.width_times_two.set_binding(move || { let compo = w.upgrade().unwrap(); - g(&compo.width, context) * 2 + g(&compo.width) * 2 }); let animation_details = PropertyAnimation { duration: DURATION.as_millis() as _ }; compo.width.set(100); - assert_eq!(g(&compo.width, &dummy_eval_context), 100); - assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200); + assert_eq!(g(&compo.width), 100); + assert_eq!(g(&compo.width_times_two), 200); let start_time = crate::animations::CURRENT_ANIMATION_DRIVER.with(|driver| driver.current_tick()); compo.width.set_animated_value(200, &animation_details); - assert_eq!(g(&compo.width, &dummy_eval_context), 100); - assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200); + assert_eq!(g(&compo.width), 100); + assert_eq!(g(&compo.width_times_two), 200); crate::animations::CURRENT_ANIMATION_DRIVER .with(|driver| driver.update_animations(start_time + DURATION / 2)); - assert_eq!(g(&compo.width, &dummy_eval_context), 150); - assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 300); + assert_eq!(g(&compo.width), 150); + assert_eq!(g(&compo.width_times_two), 300); crate::animations::CURRENT_ANIMATION_DRIVER .with(|driver| driver.update_animations(start_time + DURATION)); - assert_eq!(g(&compo.width, &dummy_eval_context), 200); - assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400); + assert_eq!(g(&compo.width), 200); + assert_eq!(g(&compo.width_times_two), 400); crate::animations::CURRENT_ANIMATION_DRIVER .with(|driver| driver.update_animations(start_time + DURATION * 2)); - assert_eq!(g(&compo.width, &dummy_eval_context), 200); - assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400); + assert_eq!(g(&compo.width), 200); + assert_eq!(g(&compo.width_times_two), 400); // the binding should be removed compo.width.handle.access(|binding| assert!(binding.is_none())); @@ -1028,24 +947,15 @@ mod animation_tests { #[test] fn properties_test_animation_triggered_by_binding() { - fn g(prop: &Property, ctx: &EvaluationContext) -> i32 { - unsafe { Pin::new_unchecked(prop).get(ctx) } + fn g(prop: &Property) -> i32 { + unsafe { Pin::new_unchecked(prop).get() } } - let dummy_eval_context = EvaluationContext { - component: unsafe { - core::pin::Pin::new_unchecked(vtable::VRef::from_raw( - core::ptr::NonNull::dangling(), - core::ptr::NonNull::dangling(), - )) - }, - parent_context: None, - }; let compo = Rc::new(Component::default()); let w = Rc::downgrade(&compo); - compo.width_times_two.set_binding(move |context| { + compo.width_times_two.set_binding(move || { let compo = w.upgrade().unwrap(); - g(&compo.width, context) * 2 + g(&compo.width) * 2 }); let start_time = @@ -1055,32 +965,32 @@ mod animation_tests { let w = Rc::downgrade(&compo); compo.width.set_animated_binding( - move |context| { + move || { let compo = w.upgrade().unwrap(); - g(&compo.feed_property, context) + g(&compo.feed_property) }, &animation_details, ); compo.feed_property.set(100); - assert_eq!(g(&compo.width, &dummy_eval_context), 100); - assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200); + assert_eq!(g(&compo.width), 100); + assert_eq!(g(&compo.width_times_two), 200); compo.feed_property.set(200); - assert_eq!(g(&compo.width, &dummy_eval_context), 100); - assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200); + assert_eq!(g(&compo.width), 100); + assert_eq!(g(&compo.width_times_two), 200); crate::animations::CURRENT_ANIMATION_DRIVER .with(|driver| driver.update_animations(start_time + DURATION / 2)); - assert_eq!(g(&compo.width, &dummy_eval_context), 150); - assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 300); + assert_eq!(g(&compo.width), 150); + assert_eq!(g(&compo.width_times_two), 300); crate::animations::CURRENT_ANIMATION_DRIVER .with(|driver| driver.update_animations(start_time + DURATION)); - assert_eq!(g(&compo.width, &dummy_eval_context), 200); - assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400); + assert_eq!(g(&compo.width), 200); + assert_eq!(g(&compo.width_times_two), 400); } } @@ -1094,7 +1004,7 @@ impl Default for PropertyListenerScope { fn default() -> Self { static VT: &'static BindingVTable = &BindingVTable { drop: |_| (), - evaluate: |_, _, _| BindingResult::KeepBinding, + evaluate: |_, _| BindingResult::KeepBinding, mark_dirty: |_| (), }; @@ -1134,21 +1044,13 @@ fn test_property_listener_scope() { let scope = Box::pin(PropertyListenerScope::default()); let prop1 = Box::pin(Property::new(42)); assert!(scope.is_dirty()); // It is dirty at the beginning - let dummy_eval_context = EvaluationContext { - component: unsafe { - core::pin::Pin::new_unchecked(vtable::VRef::from_raw( - core::ptr::NonNull::dangling(), - core::ptr::NonNull::dangling(), - )) - }, - parent_context: None, - }; - let r = scope.as_ref().evaluate(|| prop1.as_ref().get(&dummy_eval_context)); + + let r = scope.as_ref().evaluate(|| prop1.as_ref().get()); assert_eq!(r, 42); assert!(!scope.is_dirty()); // It is no longer dirty prop1.as_ref().set(88); assert!(scope.is_dirty()); // now dirty for prop1 changed. - let r = scope.as_ref().evaluate(|| prop1.as_ref().get(&dummy_eval_context) + 1); + let r = scope.as_ref().evaluate(|| prop1.as_ref().get() + 1); assert_eq!(r, 89); assert!(!scope.is_dirty()); let r = scope.as_ref().evaluate(|| 12); diff --git a/sixtyfps_runtime/corelib/abi/signals.rs b/sixtyfps_runtime/corelib/abi/signals.rs index ea28d92c4..d14349d5f 100644 --- a/sixtyfps_runtime/corelib/abi/signals.rs +++ b/sixtyfps_runtime/corelib/abi/signals.rs @@ -5,7 +5,6 @@ TODO: reconsider if we should rename that to `Event` but then it should also be renamed everywhere, including in the language grammar */ -use super::properties::EvaluationContext; use core::cell::Cell; /// A Signal that can be connected to a handler. @@ -16,16 +15,14 @@ use core::cell::Cell; #[repr(C)] pub struct Signal { /// FIXME: Box is a fat object and we probaly want to put an erased type in there - handler: Cell>>, + handler: Cell>>, } impl Signal { /// Emit the signal with the given argument. - /// - /// The constext must be a context corresponding to the component in which the signal is contained. - pub fn emit(&self, context: &EvaluationContext, a: Arg) { + pub fn emit(&self, a: Arg) { if let Some(h) = self.handler.take() { - h(context, a); + h(a); assert!(self.handler.take().is_none(), "Signal Handler set while emitted"); self.handler.set(Some(h)) } @@ -34,44 +31,23 @@ impl Signal { /// Set an handler to be called when the signal is emited /// /// There can only be one single handler per signal. - pub fn set_handler(&self, f: impl Fn(&EvaluationContext, Arg) + 'static) { + pub fn set_handler(&self, f: impl Fn(Arg) + 'static) { self.handler.set(Some(Box::new(f))); } } #[test] fn signal_simple_test() { - use std::pin::Pin; + use std::rc::Rc; #[derive(Default)] struct Component { pressed: core::cell::Cell, clicked: Signal<()>, } - impl crate::abi::datastructures::Component for Component { - fn visit_children_item( - self: Pin<&Self>, - _: isize, - _: crate::abi::datastructures::ItemVisitorRefMut, - ) { - } - fn layout_info(self: Pin<&Self>) -> crate::abi::datastructures::LayoutInfo { - unimplemented!() - } - fn compute_layout(self: Pin<&Self>, _: &crate::EvaluationContext) {} - } - use crate::abi::datastructures::ComponentVTable; - let c = Component::default(); - c.clicked.set_handler(|c, ()| unsafe { - (*(c.component.as_ptr() as *const Component)).pressed.set(true) - }); - let vtable = ComponentVTable::new::(); - let ctx = super::properties::EvaluationContext::for_root_component(unsafe { - Pin::new_unchecked(vtable::VRef::from_raw( - core::ptr::NonNull::from(&vtable), - core::ptr::NonNull::from(&c).cast(), - )) - }); - c.clicked.emit(&ctx, ()); + let c = Rc::new(Component::default()); + let weak = Rc::downgrade(&c); + c.clicked.set_handler(move |()| weak.upgrade().unwrap().pressed.set(true)); + c.clicked.emit(()); assert_eq!(c.pressed.get(), true); } @@ -94,21 +70,18 @@ pub unsafe extern "C" fn sixtyfps_signal_init(out: *mut SignalOpaque) { /// Emit the signal #[no_mangle] -pub unsafe extern "C" fn sixtyfps_signal_emit( - sig: *const SignalOpaque, - component: &EvaluationContext, -) { +pub unsafe extern "C" fn sixtyfps_signal_emit(sig: *const SignalOpaque) { let sig = &*(sig as *const Signal<()>); - sig.emit(component, ()); + sig.emit(()); } /// Set signal handler. /// -/// The binding has signature fn(user_data, context) +/// The binding has signature fn(user_data) #[no_mangle] pub unsafe extern "C" fn sixtyfps_signal_set_handler( sig: *mut SignalOpaque, - binding: extern "C" fn(*mut c_void, &EvaluationContext), + binding: extern "C" fn(user_data: *mut c_void), user_data: *mut c_void, drop_user_data: Option, ) { @@ -128,8 +101,8 @@ pub unsafe extern "C" fn sixtyfps_signal_set_handler( } let ud = UserData { user_data, drop_user_data }; - let real_binding = move |compo: &EvaluationContext, ()| { - binding(ud.user_data, compo); + let real_binding = move |()| { + binding(ud.user_data); }; sig.set_handler(real_binding); } diff --git a/sixtyfps_runtime/corelib/animations.rs b/sixtyfps_runtime/corelib/animations.rs index 55de6608f..8a2172459 100644 --- a/sixtyfps_runtime/corelib/animations.rs +++ b/sixtyfps_runtime/corelib/animations.rs @@ -39,15 +39,7 @@ impl AnimationDriver { /// The current instant that is to be used for animation /// using this function register the current binding as a dependency pub fn current_tick(&self) -> instant::Instant { - // FIXME! we need to get rid of the contect there - #[allow(unsafe_code)] - let dummy_eval_context = crate::EvaluationContext::for_root_component(unsafe { - core::pin::Pin::new_unchecked(vtable::VRef::from_raw( - core::ptr::NonNull::dangling(), - core::ptr::NonNull::dangling(), - )) - }); - self.global_instant.as_ref().get(&dummy_eval_context) + self.global_instant.as_ref().get() } } diff --git a/sixtyfps_runtime/corelib/graphics.rs b/sixtyfps_runtime/corelib/graphics.rs index d0b211991..5747c7f58 100644 --- a/sixtyfps_runtime/corelib/graphics.rs +++ b/sixtyfps_runtime/corelib/graphics.rs @@ -145,7 +145,7 @@ impl crate::eventloop::GenericWindow { fn draw(&self, component: crate::ComponentRefPin) { // FIXME: we should do that only if some property change - component.as_ref().compute_layout(&crate::EvaluationContext::for_root_component(component)); + component.as_ref().compute_layout(); let mut this = self.borrow_mut(); @@ -156,9 +156,8 @@ impl crate::eventloop::GenericWindow // Generate cached rendering data once crate::item_tree::visit_items( component, - |ctx, item, _| { + |_, item, _| { crate::item_rendering::update_item_rendering_data( - ctx, item, &mut this.rendering_cache, &mut rendering_primitives_builder, diff --git a/sixtyfps_runtime/corelib/input.rs b/sixtyfps_runtime/corelib/input.rs index 51d55f42e..86a726ba5 100644 --- a/sixtyfps_runtime/corelib/input.rs +++ b/sixtyfps_runtime/corelib/input.rs @@ -12,14 +12,14 @@ pub fn process_mouse_event(component: ComponentRefPin, event: MouseEvent) { crate::item_tree::visit_items( component, - |context, item, offset| { - let geom = item.as_ref().geometry(context); + |_, item, offset| { + let geom = item.as_ref().geometry(); let geom = geom.translate(*offset); if geom.contains(event.pos) { let mut event2 = event.clone(); event2.pos -= geom.origin.to_vector(); - item.as_ref().input_event(event2, context); + item.as_ref().input_event(event2); } geom.origin.to_vector() diff --git a/sixtyfps_runtime/corelib/item_rendering.rs b/sixtyfps_runtime/corelib/item_rendering.rs index 00a65ef7b..7389db085 100644 --- a/sixtyfps_runtime/corelib/item_rendering.rs +++ b/sixtyfps_runtime/corelib/item_rendering.rs @@ -2,16 +2,14 @@ use super::abi::datastructures::ItemRef; use super::graphics::{ Frame, GraphicsBackend, HasRenderingPrimitive, RenderingCache, RenderingPrimitivesBuilder, }; -use super::EvaluationContext; use cgmath::{Matrix4, SquareMatrix, Vector3}; pub(crate) fn update_item_rendering_data( - context: &EvaluationContext, item: core::pin::Pin, rendering_cache: &mut RenderingCache, rendering_primitives_builder: &mut Backend::RenderingPrimitivesBuilder, ) { - let item_rendering_primitive = item.as_ref().rendering_primitive(context); + let item_rendering_primitive = item.as_ref().rendering_primitive(); let rendering_data = item.cached_rendering_data_offset(); @@ -41,8 +39,8 @@ pub(crate) fn render_component_items( crate::item_tree::visit_items( component, - |context, item, transform| { - let origin = item.as_ref().geometry(context).origin; + |_, item, transform| { + let origin = item.as_ref().geometry().origin; let transform = transform * Matrix4::from_translation(Vector3::new(origin.x, origin.y, 0.)); diff --git a/sixtyfps_runtime/corelib/item_tree.rs b/sixtyfps_runtime/corelib/item_tree.rs index d0897a4ad..2344d94f0 100644 --- a/sixtyfps_runtime/corelib/item_tree.rs +++ b/sixtyfps_runtime/corelib/item_tree.rs @@ -1,6 +1,5 @@ use crate::abi::datastructures::{ItemRef, ItemTreeNode, ItemVisitor, ItemVisitorVTable}; use crate::ComponentRefPin; -use crate::EvaluationContext; use core::pin::Pin; /// Visit each items recursively @@ -8,31 +7,24 @@ use core::pin::Pin; /// The state parametter returned by the visitor is passed to each children. pub fn visit_items( component: ComponentRefPin, - mut visitor: impl FnMut(&EvaluationContext, Pin, &State) -> State, + mut visitor: impl FnMut(ComponentRefPin, Pin, &State) -> State, state: State, ) { - let context = EvaluationContext::for_root_component(component); - visit_internal(&context, &mut visitor, -1, &state) + visit_internal(component, &mut visitor, -1, &state) } fn visit_internal( - context: &EvaluationContext, - visitor: &mut impl FnMut(&EvaluationContext, Pin, &State) -> State, + component: ComponentRefPin, + visitor: &mut impl FnMut(ComponentRefPin, Pin, &State) -> State, index: isize, state: &State, ) { let mut actual_visitor = |component: ComponentRefPin, index: isize, item: Pin| { - if component.as_ptr() == context.component.as_ptr() { - let s = visitor(context, item, state); - visit_internal(context, visitor, index, &s); - } else { - let context = context.child_context(component); - let s = visitor(&context, item, state); - visit_internal(&context, visitor, index, &s); - } + let s = visitor(component, item, state); + visit_internal(component, visitor, index, &s); }; vtable::new_vref!(let mut actual_visitor : VRefMut for ItemVisitor = &mut actual_visitor); - context.component.as_ref().visit_children_item(index, actual_visitor); + component.as_ref().visit_children_item(index, actual_visitor); } /// Visit the children within an array of ItemTreeNode diff --git a/sixtyfps_runtime/corelib/lib.rs b/sixtyfps_runtime/corelib/lib.rs index 064b5813e..1d7668f19 100644 --- a/sixtyfps_runtime/corelib/lib.rs +++ b/sixtyfps_runtime/corelib/lib.rs @@ -44,7 +44,7 @@ pub use abi::sharedarray::SharedArray; pub use abi::datastructures::Resource; #[doc(inline)] -pub use abi::properties::{EvaluationContext, Property}; +pub use abi::properties::Property; #[doc(inline)] pub use abi::signals::Signal; diff --git a/sixtyfps_runtime/corelib/rtti.rs b/sixtyfps_runtime/corelib/rtti.rs index 6b99467a6..dc4fe5768 100644 --- a/sixtyfps_runtime/corelib/rtti.rs +++ b/sixtyfps_runtime/corelib/rtti.rs @@ -27,7 +27,7 @@ declare_ValueType![ ]; pub trait PropertyInfo { - fn get(&self, item: Pin<&Item>, context: &crate::EvaluationContext) -> Result; + fn get(&self, item: Pin<&Item>) -> Result; fn set( &self, item: Pin<&Item>, @@ -37,7 +37,7 @@ pub trait PropertyInfo { fn set_binding( &self, item: Pin<&Item>, - binding: Box Value>, + binding: Box Value>, animation: Option, ) -> Result<(), ()>; @@ -61,8 +61,8 @@ where Value: TryInto, T: TryInto, { - fn get(&self, item: Pin<&Item>, context: &crate::EvaluationContext) -> Result { - self.apply_pin(item).get(context).try_into().map_err(|_| ()) + fn get(&self, item: Pin<&Item>) -> Result { + self.apply_pin(item).get().try_into().map_err(|_| ()) } fn set( &self, @@ -80,14 +80,14 @@ where fn set_binding( &self, item: Pin<&Item>, - binding: Box Value>, + binding: Box Value>, animation: Option, ) -> Result<(), ()> { if animation.is_some() { Err(()) } else { - self.apply_pin(item).set_binding(move |context| { - binding(context).try_into().map_err(|_| ()).expect("binding was of the wrong type") + self.apply_pin(item).set_binding(move || { + binding().try_into().map_err(|_| ()).expect("binding was of the wrong type") }); Ok(()) } @@ -109,8 +109,8 @@ where T: TryInto, T: crate::abi::properties::InterpolatedPropertyValue, { - fn get(&self, item: Pin<&Item>, context: &crate::EvaluationContext) -> Result { - self.0.get(item, context) + fn get(&self, item: Pin<&Item>) -> Result { + self.0.get(item) } fn set( &self, @@ -128,16 +128,13 @@ where fn set_binding( &self, item: Pin<&Item>, - binding: Box Value>, + binding: Box Value>, animation: Option, ) -> Result<(), ()> { if let Some(animation) = &animation { self.apply_pin(item).set_animated_binding( - move |context| { - binding(context) - .try_into() - .map_err(|_| ()) - .expect("binding was of the wrong type") + move || { + binding().try_into().map_err(|_| ()).expect("binding was of the wrong type") }, animation, ); diff --git a/sixtyfps_runtime/interpreter/dynamic_component.rs b/sixtyfps_runtime/interpreter/dynamic_component.rs index 667b1a6a6..69d8068f1 100644 --- a/sixtyfps_runtime/interpreter/dynamic_component.rs +++ b/sixtyfps_runtime/interpreter/dynamic_component.rs @@ -13,7 +13,7 @@ use sixtyfps_corelib::abi::primitives::PropertyAnimation; use sixtyfps_corelib::abi::{properties::PropertyListenerScope, slice::Slice}; use sixtyfps_corelib::rtti::PropertyInfo; use sixtyfps_corelib::ComponentRefPin; -use sixtyfps_corelib::{rtti, Color, EvaluationContext, Property, SharedString, Signal}; +use sixtyfps_corelib::{rtti, Color, Property, SharedString, Signal}; use std::collections::HashMap; use std::{pin::Pin, rc::Rc}; @@ -129,28 +129,24 @@ unsafe extern "C" fn visit_children_item( &*(component.as_ptr().add(listener_offset) as *const PropertyListenerScope), ); if listener.is_dirty() { - let eval_context = EvaluationContext::for_root_component(component); listener.evaluate(|| { - match eval::eval_expression( - &rep_in_comp.model, - &*component_type, - &eval_context, - ) { + match eval::eval_expression(&rep_in_comp.model, &*component_type, component) + { crate::Value::Number(count) => populate_model( vec, rep_in_comp, - &eval_context, + component, (0..count as i32) .into_iter() .map(|v| crate::Value::Number(v as f64)), ), crate::Value::Array(a) => { - populate_model(vec, rep_in_comp, &eval_context, a.into_iter()) + populate_model(vec, rep_in_comp, component, a.into_iter()) } crate::Value::Bool(b) => populate_model( vec, rep_in_comp, - &eval_context, + component, (if b { Some(crate::Value::Void) } else { None }).into_iter(), ), _ => panic!("Unsupported model"), @@ -370,7 +366,7 @@ fn generate_component( fn animation_for_property( component_type: Rc, - eval_context: &EvaluationContext, + eval_context: ComponentRefPin, all_animations: &HashMap, property_name: &String, ) -> Option { @@ -386,7 +382,7 @@ fn animation_for_property( fn animation_for_element_property( component_type: Rc, - eval_context: &EvaluationContext, + eval_context: ComponentRefPin, element: &Element, property_name: &String, ) -> Option { @@ -401,11 +397,11 @@ fn animation_for_element_property( fn populate_model( vec: &mut Vec, rep_in_comp: &RepeaterWithinComponent, - eval_context: &EvaluationContext, + component: ComponentRefPin, model: impl Iterator + ExactSizeIterator, ) { vec.resize_with(model.size_hint().1.unwrap(), || { - instantiate(rep_in_comp.component_to_repeat.clone(), Some(eval_context)) + instantiate(rep_in_comp.component_to_repeat.clone(), Some(component)) }); for (i, (x, val)) in vec.iter().zip(model).enumerate() { rep_in_comp @@ -418,20 +414,17 @@ fn populate_model( pub fn instantiate( component_type: Rc, - parent_ctx: Option<&EvaluationContext>, + parent_ctx: Option, ) -> ComponentBox { let instance = component_type.dynamic_type.clone().create_instance(); let mem = instance.as_ptr().as_ptr() as *mut u8; let component_box = ComponentBox { instance, component_type: component_type.clone() }; - let eval_context = if let Some(parent) = parent_ctx { + if let Some(parent) = parent_ctx { unsafe { *(mem.add(component_type.parent_component_offset.unwrap()) - as *mut Option) = Some(parent.component); + as *mut Option) = Some(parent); } - parent.child_context(component_box.borrow()) - } else { - EvaluationContext::for_root_component(component_box.borrow()) }; for item_within_component in component_type.items.values() { @@ -453,8 +446,13 @@ pub fn instantiate( as *mut Signal<()>); let expr = expr.clone(); let component_type = component_type.clone(); - signal.set_handler(move |eval_context, _| { - eval::eval_expression(&expr, &*component_type, &eval_context); + let instance = component_box.instance.as_ptr(); + signal.set_handler(move |_| { + let c = Pin::new_unchecked(vtable::VRef::from_raw( + NonNull::from(&component_type.ct).cast(), + instance.cast(), + )); + eval::eval_expression(&expr, &*component_type, c); }) } else { if let Some(prop_rtti) = @@ -462,7 +460,7 @@ pub fn instantiate( { let maybe_animation = animation_for_element_property( component_type.clone(), - &eval_context, + component_box.borrow(), &elem, prop, ); @@ -470,17 +468,26 @@ pub fn instantiate( if expr.is_constant() { prop_rtti.set( item, - eval::eval_expression(expr, &*component_type, &eval_context), + eval::eval_expression( + expr, + &*component_type, + component_box.borrow(), + ), maybe_animation, ); } else { let expr = expr.clone(); let component_type = component_type.clone(); + let instance = component_box.instance.as_ptr(); prop_rtti.set_binding( item, - Box::new(move |eval_context| { - eval::eval_expression(&expr, &*component_type, eval_context) + Box::new(move || { + let c = Pin::new_unchecked(vtable::VRef::from_raw( + NonNull::from(&component_type.ct).cast(), + instance.cast(), + )); + eval::eval_expression(&expr, &*component_type, c) }), maybe_animation, ); @@ -491,24 +498,33 @@ pub fn instantiate( { let maybe_animation = animation_for_property( component_type.clone(), - &eval_context, + component_box.borrow(), &component_type.original.root_element.borrow().property_animations, prop, ); if expr.is_constant() { - let v = eval::eval_expression(expr, &*component_type, &eval_context); + let v = eval::eval_expression( + expr, + &*component_type, + component_box.borrow(), + ); prop_info .set(Pin::new_unchecked(&*mem.add(*offset)), v, maybe_animation) .unwrap(); } else { let expr = expr.clone(); let component_type = component_type.clone(); + let instance = component_box.instance.as_ptr(); prop_info .set_binding( Pin::new_unchecked(&*mem.add(*offset)), - Box::new(move |eval_context| { - eval::eval_expression(&expr, &*component_type, eval_context) + Box::new(move || { + let c = Pin::new_unchecked(vtable::VRef::from_raw( + NonNull::from(&component_type.ct).cast(), + instance.cast(), + )); + eval::eval_expression(&expr, &*component_type, c) }), maybe_animation, ) @@ -527,20 +543,20 @@ pub fn instantiate( continue; } let vec = unsafe { &mut *(mem.add(rep_in_comp.offset) as *mut RepeaterVec) }; - match eval::eval_expression(&rep_in_comp.model, &*component_type, &eval_context) { + match eval::eval_expression(&rep_in_comp.model, &*component_type, component_box.borrow()) { crate::Value::Number(count) => populate_model( vec, rep_in_comp, - &eval_context, + component_box.borrow(), (0..count as i32).into_iter().map(|v| crate::Value::Number(v as f64)), ), crate::Value::Array(a) => { - populate_model(vec, rep_in_comp, &eval_context, a.into_iter()) + populate_model(vec, rep_in_comp, component_box.borrow(), a.into_iter()) } crate::Value::Bool(b) => populate_model( vec, rep_in_comp, - &eval_context, + component_box.borrow(), (if b { Some(crate::Value::Void) } else { None }).into_iter(), ), _ => panic!("Unsupported model"), @@ -550,17 +566,13 @@ pub fn instantiate( component_box } -unsafe extern "C" fn compute_layout(component: ComponentRefPin, eval_context: &EvaluationContext) { - debug_assert!(component.as_ptr() == eval_context.component.as_ptr()); - +unsafe extern "C" fn compute_layout(component: ComponentRefPin) { // This is fine since we can only be called with a component that with our vtable which is a ComponentDescription let component_type = &*(component.get_vtable() as *const ComponentVTable as *const ComponentDescription); let resolve_prop_ref = |prop_ref: &expression_tree::Expression| { - eval::eval_expression(&prop_ref, &component_type, eval_context) - .try_into() - .unwrap_or_default() + eval::eval_expression(&prop_ref, &component_type, component).try_into().unwrap_or_default() }; for it in &component_type.original.layout_constraints.borrow().grids { @@ -605,7 +617,7 @@ unsafe extern "C" fn compute_layout(component: ComponentRefPin, eval_context: &E let within_info = &component_type.items[it.within.borrow().id.as_str()]; let within_prop = |name| { within_info.rtti.properties[name] - .get(within_info.item_from_component(component.as_ptr()), &eval_context) + .get(within_info.item_from_component(component.as_ptr())) .try_into() .unwrap() }; @@ -639,7 +651,7 @@ unsafe extern "C" fn compute_layout(component: ComponentRefPin, eval_context: &E }) .collect::>(); - let path_elements = eval::convert_path(&it.path, component_type, eval_context); + let path_elements = eval::convert_path(&it.path, component_type, component); solve_path_layout(&PathLayoutData { items: Slice::from(items.as_slice()), diff --git a/sixtyfps_runtime/interpreter/eval.rs b/sixtyfps_runtime/interpreter/eval.rs index ee712fc0b..65b475624 100644 --- a/sixtyfps_runtime/interpreter/eval.rs +++ b/sixtyfps_runtime/interpreter/eval.rs @@ -7,18 +7,18 @@ use sixtyfps_compilerlib::{object_tree::ElementRc, typeregister::Type}; use sixtyfps_corelib as corelib; use sixtyfps_corelib::{ abi::datastructures::ItemRef, abi::datastructures::PathElement, - abi::primitives::PropertyAnimation, Color, EvaluationContext, PathData, Resource, SharedArray, + abi::primitives::PropertyAnimation, Color, ComponentRefPin, PathData, Resource, SharedArray, SharedString, }; use std::{collections::HashMap, rc::Rc}; pub trait ErasedPropertyInfo { - fn get(&self, item: Pin, context: &EvaluationContext) -> Value; + fn get(&self, item: Pin) -> Value; fn set(&self, item: Pin, value: Value, animation: Option); fn set_binding( &self, item: Pin, - binding: Box Value>, + binding: Box Value>, animation: Option, ); fn offset(&self) -> usize; @@ -27,8 +27,8 @@ pub trait ErasedPropertyInfo { impl> ErasedPropertyInfo for &'static dyn corelib::rtti::PropertyInfo { - fn get(&self, item: Pin, context: &EvaluationContext) -> Value { - (*self).get(ItemRef::downcast_pin(item).unwrap(), context).unwrap() + fn get(&self, item: Pin) -> Value { + (*self).get(ItemRef::downcast_pin(item).unwrap()).unwrap() } fn set(&self, item: Pin, value: Value, animation: Option) { (*self).set(ItemRef::downcast_pin(item).unwrap(), value, animation).unwrap() @@ -36,7 +36,7 @@ impl> Er fn set_binding( &self, item: Pin, - binding: Box Value>, + binding: Box Value>, animation: Option, ) { (*self).set_binding(ItemRef::downcast_pin(item).unwrap(), binding, animation).unwrap(); @@ -119,7 +119,7 @@ declare_value_conversion!(PathElements => [PathData]); pub fn eval_expression( e: &Expression, component_type: &crate::ComponentDescription, - eval_context: &corelib::EvaluationContext, + component_ref: ComponentRefPin, ) -> Value { match e { Expression::Invalid => panic!("invalid expression while evaluating"), @@ -130,23 +130,21 @@ pub fn eval_expression( Expression::SignalReference { .. } => panic!("signal in expression"), Expression::PropertyReference(NamedReference { element, name }) => { let element = element.upgrade().unwrap(); - let (component_mem, component_type, eval_context) = - enclosing_component_for_element(&element, component_type, eval_context); + let (component_mem, component_type, _) = + enclosing_component_for_element(&element, component_type, component_ref); let element = element.borrow(); if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id { if let Some(x) = component_type.custom_properties.get(name) { return unsafe { - x.prop - .get(Pin::new_unchecked(&*component_mem.add(x.offset)), &eval_context) - .unwrap() + x.prop.get(Pin::new_unchecked(&*component_mem.add(x.offset))).unwrap() }; } }; let item_info = &component_type.items[element.id.as_str()]; core::mem::drop(element); let item = unsafe { item_info.item_from_component(component_mem) }; - item_info.rtti.properties[name.as_str()].get(item, &eval_context) + item_info.rtti.properties[name.as_str()].get(item) } Expression::RepeaterIndexReference { element } => { if element.upgrade().unwrap().borrow().base_type @@ -154,12 +152,7 @@ pub fn eval_expression( { let x = &component_type.custom_properties["index"]; unsafe { - x.prop - .get( - Pin::new_unchecked(&*eval_context.component.as_ptr().add(x.offset)), - &eval_context, - ) - .unwrap() + x.prop.get(Pin::new_unchecked(&*component_ref.as_ptr().add(x.offset))).unwrap() } } else { todo!(); @@ -171,26 +164,21 @@ pub fn eval_expression( { let x = &component_type.custom_properties["model_data"]; unsafe { - x.prop - .get( - Pin::new_unchecked(&*eval_context.component.as_ptr().add(x.offset)), - &eval_context, - ) - .unwrap() + x.prop.get(Pin::new_unchecked(&*component_ref.as_ptr().add(x.offset))).unwrap() } } else { todo!(); } } Expression::ObjectAccess { base, name } => { - if let Value::Object(mut o) = eval_expression(base, component_type, eval_context) { + if let Value::Object(mut o) = eval_expression(base, component_type, component_ref) { o.remove(name).unwrap_or(Value::Void) } else { Value::Void } } Expression::Cast { from, to } => { - let v = eval_expression(&*from, component_type, eval_context); + let v = eval_expression(&*from, component_type, component_ref); match (v, to) { (Value::Number(n), Type::Int32) => Value::Number(n.round()), (Value::Number(n), Type::String) => { @@ -203,15 +191,15 @@ pub fn eval_expression( Expression::CodeBlock(sub) => { let mut v = Value::Void; for e in sub { - v = eval_expression(e, component_type, eval_context); + v = eval_expression(e, component_type, component_ref); } v } Expression::FunctionCall { function, .. } => { if let Expression::SignalReference(NamedReference { element, name }) = &**function { let element = element.upgrade().unwrap(); - let (component_mem, component_type, eval_context) = - enclosing_component_for_element(&element, component_type, eval_context); + let (component_mem, component_type, _) = + enclosing_component_for_element(&element, component_type, component_ref); let item_info = &component_type.items[element.borrow().id.as_str()]; let item = unsafe { item_info.item_from_component(component_mem) }; @@ -230,7 +218,7 @@ pub fn eval_expression( .unwrap_or_else(|| panic!("unkown signal {}", name)) as *mut corelib::Signal<()>) }; - signal.emit(&eval_context, ()); + signal.emit(()); Value::Void } else { panic!("call of something not a signal") @@ -239,7 +227,7 @@ pub fn eval_expression( Expression::SelfAssignment { lhs, rhs, op } => match &**lhs { Expression::PropertyReference(NamedReference { element, name }) => { let eval = |lhs| { - let rhs = eval_expression(&**rhs, component_type, eval_context); + let rhs = eval_expression(&**rhs, component_type, component_ref); match (lhs, rhs, op) { (Value::Number(a), Value::Number(b), '+') => Value::Number(a + b), (Value::Number(a), Value::Number(b), '-') => Value::Number(a - b), @@ -250,17 +238,15 @@ pub fn eval_expression( }; let element = element.upgrade().unwrap(); - let (component_mem, component_type, eval_context) = - enclosing_component_for_element(&element, component_type, eval_context); + let (component_mem, component_type, _) = + enclosing_component_for_element(&element, component_type, component_ref); let component = element.borrow().enclosing_component.upgrade().unwrap(); if element.borrow().id == component.root_element.borrow().id { if let Some(x) = component_type.custom_properties.get(name) { unsafe { let p = Pin::new_unchecked(&*component_mem.add(x.offset)); - x.prop - .set(p, eval(x.prop.get(p, &eval_context).unwrap()), None) - .unwrap(); + x.prop.set(p, eval(x.prop.get(p).unwrap()), None).unwrap(); } return Value::Void; } @@ -268,14 +254,14 @@ pub fn eval_expression( let item_info = &component_type.items[element.borrow().id.as_str()]; let item = unsafe { item_info.item_from_component(component_mem) }; let p = &item_info.rtti.properties[name.as_str()]; - p.set(item, eval(p.get(item, &eval_context)), None); + p.set(item, eval(p.get(item)), None); Value::Void } _ => panic!("typechecking should make sure this was a PropertyReference"), }, Expression::BinaryExpression { lhs, rhs, op } => { - let lhs = eval_expression(&**lhs, component_type, eval_context); - let rhs = eval_expression(&**rhs, component_type, eval_context); + let lhs = eval_expression(&**lhs, component_type, component_ref); + let rhs = eval_expression(&**rhs, component_type, component_ref); match (op, lhs, rhs) { ('+', Value::Number(a), Value::Number(b)) => Value::Number(a + b), @@ -294,7 +280,7 @@ pub fn eval_expression( } } Expression::UnaryOp { sub, op } => { - let sub = eval_expression(&**sub, component_type, eval_context); + let sub = eval_expression(&**sub, component_type, component_ref); match (sub, op) { (Value::Number(a), '+') => Value::Number(a), (Value::Number(a), '-') => Value::Number(-a), @@ -306,25 +292,25 @@ pub fn eval_expression( Value::Resource(Resource::AbsoluteFilePath(absolute_source_path.as_str().into())) } Expression::Condition { condition, true_expr, false_expr } => { - match eval_expression(&**condition, component_type, eval_context).try_into() + match eval_expression(&**condition, component_type, component_ref).try_into() as Result { - Ok(true) => eval_expression(&**true_expr, component_type, eval_context), - Ok(false) => eval_expression(&**false_expr, component_type, eval_context), + Ok(true) => eval_expression(&**true_expr, component_type, component_ref), + Ok(false) => eval_expression(&**false_expr, component_type, component_ref), _ => panic!("conditional expression did not evaluate to boolean"), } } Expression::Array { values, .. } => Value::Array( - values.iter().map(|e| eval_expression(e, component_type, eval_context)).collect(), + values.iter().map(|e| eval_expression(e, component_type, component_ref)).collect(), ), Expression::Object { values, .. } => Value::Object( values .iter() - .map(|(k, v)| (k.clone(), eval_expression(v, component_type, eval_context))) + .map(|(k, v)| (k.clone(), eval_expression(v, component_type, component_ref))) .collect(), ), Expression::PathElements { elements } => { - Value::PathElements(convert_path(elements, component_type, eval_context)) + Value::PathElements(convert_path(elements, component_type, component_ref)) } } } @@ -332,16 +318,16 @@ pub fn eval_expression( fn enclosing_component_for_element<'a>( element: &ElementRc, component_type: &'a crate::ComponentDescription, - eval_context: &corelib::EvaluationContext<'a>, -) -> (*const u8, &'a crate::ComponentDescription, corelib::EvaluationContext<'a>) { + component_ref: ComponentRefPin<'a>, +) -> (*const u8, &'a crate::ComponentDescription, ComponentRefPin<'a>) { if Rc::ptr_eq( &element.borrow().enclosing_component.upgrade().unwrap(), &component_type.original, ) { - let mem = eval_context.component.as_ptr(); - (mem, component_type, EvaluationContext::for_root_component(eval_context.component)) + let mem = component_ref.as_ptr(); + (mem, component_type, component_ref) } else { - let mem = eval_context.component.as_ptr(); + let mem = component_ref.as_ptr(); let parent_component = unsafe { *(mem.add(component_type.parent_component_offset.unwrap()) as *const Option) @@ -349,11 +335,7 @@ fn enclosing_component_for_element<'a>( .unwrap(); let parent_component_type = unsafe { crate::dynamic_component::get_component_type(parent_component) }; - enclosing_component_for_element( - element, - parent_component_type, - &EvaluationContext::for_root_component(parent_component), - ) + enclosing_component_for_element(element, parent_component_type, parent_component) } } @@ -362,12 +344,12 @@ pub fn new_struct_with_bindings< >( bindings: &HashMap, component_type: &crate::ComponentDescription, - eval_context: &corelib::EvaluationContext, + component_ref: ComponentRefPin, ) -> ElementType { let mut element = ElementType::default(); for (prop, info) in ElementType::fields::().into_iter() { if let Some(binding) = &bindings.get(prop) { - let value = eval_expression(&binding, &*component_type, &eval_context); + let value = eval_expression(&binding, &*component_type, component_ref); info.set_field(&mut element, value).unwrap(); } } @@ -428,7 +410,7 @@ fn convert_from_lyon_path<'a>( pub fn convert_path( path: &ExprPath, component_type: &crate::ComponentDescription, - eval_context: &corelib::EvaluationContext, + eval_context: ComponentRefPin, ) -> PathData { match path { ExprPath::Elements(elements) => PathData::Elements(SharedArray::::from_iter( @@ -443,7 +425,7 @@ pub fn convert_path( fn convert_path_element( expr_element: &ExprPathElement, component_type: &crate::ComponentDescription, - eval_context: &corelib::EvaluationContext, + eval_context: ComponentRefPin, ) -> PathElement { match expr_element.element_type.class_name.as_str() { "LineTo" => PathElement::LineTo(new_struct_with_bindings( diff --git a/sixtyfps_runtime/interpreter/lib.rs b/sixtyfps_runtime/interpreter/lib.rs index e36976153..592965234 100644 --- a/sixtyfps_runtime/interpreter/lib.rs +++ b/sixtyfps_runtime/interpreter/lib.rs @@ -16,7 +16,7 @@ pub use eval::Value; pub use dynamic_component::ComponentBox; use sixtyfps_corelib::abi::datastructures::{ComponentRef, ComponentRefMut}; -use sixtyfps_corelib::{ComponentRefPin, EvaluationContext, Signal}; +use sixtyfps_corelib::{ComponentRefPin, Signal}; use std::{collections::HashMap, pin::Pin, rc::Rc}; impl ComponentDescription { @@ -66,7 +66,7 @@ impl ComponentDescription { &self, component: ComponentRef, name: &str, - binding: Box Value>, + binding: Box Value>, ) -> Result<(), ()> { if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) { return Err(()); @@ -84,17 +84,12 @@ impl ComponentDescription { /// /// Returns an error if the component is not an instance corresponding to this ComponentDescription, /// or if a signal with this name does not exist in this component - pub fn get_property(&self, eval_context: &EvaluationContext, name: &str) -> Result { - if !core::ptr::eq((&self.ct) as *const _, eval_context.component.get_vtable() as *const _) { + pub fn get_property(&self, component: ComponentRefPin, name: &str) -> Result { + if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) { return Err(()); } let x = self.custom_properties.get(name).ok_or(())?; - unsafe { - x.prop.get( - Pin::new_unchecked(&*eval_context.component.as_ptr().add(x.offset)), - eval_context, - ) - } + unsafe { x.prop.get(Pin::new_unchecked(&*component.as_ptr().add(x.offset))) } } /// Sets an handler for a signal @@ -105,7 +100,7 @@ impl ComponentDescription { &self, component: Pin, name: &str, - handler: Box, + handler: Box, ) -> Result<(), ()> { if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) { return Err(()); @@ -120,14 +115,13 @@ impl ComponentDescription { /// /// Returns an error if the component is not an instance corresponding to this ComponentDescription, /// or if the signal with this name does not exist in this component - pub fn emit_signal(&self, eval_context: &EvaluationContext, name: &str) -> Result<(), ()> { - let component = eval_context.component; + pub fn emit_signal(&self, component: ComponentRefPin, name: &str) -> Result<(), ()> { if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) { return Err(()); } let x = self.custom_signals.get(name).ok_or(())?; let sig = unsafe { &mut *(component.as_ptr().add(*x) as *mut Signal<()>) }; - sig.emit(eval_context, ()); + sig.emit(()); Ok(()) } }