Some refactoring of the rust generated code

Always use a Pin<Rc> for the component. (This is required to support repeater
within repeater as well anyway)
Do not use the context within the binding. We can get along by simply capturing
a weak pointer to the component
This commit is contained in:
Olivier Goffart 2020-07-13 15:34:09 +02:00
parent 1a0d053889
commit ab7ae9f3e2
15 changed files with 74 additions and 73 deletions

View file

@ -20,7 +20,7 @@ sixtyfps::sixtyfps!{
}
fn main() {
# return; // Don't run a window in an example
HelloWorld::default().run()
HelloWorld::new().run()
}
```
@ -56,7 +56,7 @@ Then in your main file
```ignore
sixtyfps::include_modules!();
fn main() {
HelloWorld::default().run()
HelloWorld::new().run()
}
```
*/

View file

@ -1,4 +1,6 @@
use core::cell::RefCell;
use core::pin::Pin;
use std::rc::Rc;
/// Component that can be instantiated by a repeater.
pub trait RepeatedComponent: sixtyfps_corelib::abi::datastructures::Component {
@ -11,9 +13,14 @@ pub trait RepeatedComponent: sixtyfps_corelib::abi::datastructures::Component {
/// This field is put in a component when using the `for` syntax
/// It helps instantiating the components `C`
#[derive(Default)]
pub struct Repeater<C> {
components: RefCell<Vec<core::pin::Pin<Box<C>>>>,
components: RefCell<Vec<Pin<Rc<C>>>>,
}
impl<C> Default for Repeater<C> {
fn default() -> Self {
Repeater { components: Default::default() }
}
}
impl<Data, C> Repeater<C>
@ -21,7 +28,7 @@ where
C: RepeatedComponent<Data = Data>,
{
/// Called when the model is changed
pub fn update_model<'a>(&self, data: impl Iterator<Item = Data>, init: impl Fn() -> C)
pub fn update_model<'a>(&self, data: impl Iterator<Item = Data>, init: impl Fn() -> Pin<Rc<C>>)
where
Data: 'a,
{
@ -29,7 +36,7 @@ where
for (i, d) in data.enumerate() {
let c = init();
c.update(i, d);
self.components.borrow_mut().push(Box::pin(c));
self.components.borrow_mut().push(c);
}
}

View file

@ -127,7 +127,7 @@ Hello := Rectangle {
}
fn main() {
let mut app = Hello::default();
let app = Hello::new();
app.plus_clicked.set_handler(|context, ()| {
let app = context.get_component::<Hello>().unwrap();
let counter = Hello::field_offsets().counter.apply_pin(app);

View file

@ -3,7 +3,7 @@
sixtyfps::include_modules!();
fn main() {
let mut app = Hello::default();
let app = Hello::new();
app.plus_clicked.set_handler(|context, ()| {
let app = context.get_component::<Hello>().unwrap();

View file

@ -10,5 +10,5 @@ pub fn wasm_main() {
#[cfg(debug_assertions)]
console_error_panic_hook::set_once();
Hello::default().run();
Hello::new().run();
}

View file

@ -115,7 +115,6 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
let mut repeated_dynmodel_names = Vec::new();
let mut repeated_visit_branch = Vec::new();
let mut init = Vec::new();
let mut init_repeaters = Vec::new();
super::build_array_helper(component, |item_rc, children_index| {
let item = item_rc.borrow();
if let Some(repeated) = &item.repeated {
@ -166,11 +165,9 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
}
if repeated.model.is_constant() {
init_repeaters.push(quote! {
init.push(quote! {
self_pinned.#repeater_id.update_model(#model, || {
let mut new_comp = #rep_component_id::default();
new_comp.parent = self_pinned.self_weak.get().unwrap().clone();
new_comp
#rep_component_id::new(self_pinned.self_weak.get().unwrap().clone())
});
});
repeated_visit_branch.push(quote!(
@ -189,9 +186,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
);
let context = &context;
self_pinned.#repeater_id.update_model(#model, || {
let mut new_comp = #rep_component_id::default();
new_comp.parent = self_pinned.self_weak.get().unwrap().clone();
new_comp
#rep_component_id::new(self_pinned.self_weak.get().unwrap().clone())
});
});
}
@ -231,40 +226,39 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
if matches!(item.lookup_property(k.as_str()), Type::Signal) {
init.push(quote!(
self_.#rust_property.set_handler(|context, ()| {
self_pinned.#rust_property.set_handler(|context, ()| {
let _self = context.get_component::<#component_id>().unwrap();
#tokens_for_expression;
});
));
} else {
if binding_expression.is_constant() {
let setter = property_set_value_tokens(
let setter = if binding_expression.is_constant() {
property_set_value_tokens(
component,
&item_rc,
k,
quote!((#tokens_for_expression) as _),
);
init.push(quote!(
self_.#rust_property.#setter;
));
)
} else {
let setter = property_set_binding_tokens(
property_set_binding_tokens(
component,
&item_rc,
k,
quote!(
|context| {
let _self = context.get_component::<#component_id>().unwrap();
quote!({
let self_weak = sixtyfps::re_exports::WeakPin::downgrade(self_pinned.clone());
move |context| {
let self_pinned = self_weak.upgrade().unwrap();
let _self = self_pinned.as_ref();
(#tokens_for_expression) as _
}
),
);
}),
)
};
init.push(quote!(
self_.#rust_property.#setter;
self_pinned.#rust_property.#setter;
));
}
}
}
item_names.push(field_name);
item_types.push(quote::format_ident!("{}", item.base_type.as_builtin().class_name));
}
@ -312,15 +306,10 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
));
} else {
property_and_signal_accessors.push(quote! {
fn run(self) {
fn run(self : core::pin::Pin<std::rc::Rc<Self>>) {
use sixtyfps::re_exports::*;
let window = sixtyfps::create_window();
let self_pinned = Rc::pin(self);
self_pinned.self_weak.set(WeakPin::downgrade(self_pinned.clone()))
.map_err(|_|())
.expect("Can only be pinned once");
#(#init_repeaters)*
window.run(VRef::new_pin(self_pinned.as_ref()));
window.run(VRef::new_pin(self.as_ref()));
}
});
};
@ -349,25 +338,6 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
#(parent : sixtyfps::re_exports::WeakPin<#parent_component_type>,)*
}
impl ::core::default::Default for #component_id {
fn default() -> Self {
#![allow(unused)]
use sixtyfps::re_exports::*;
ComponentVTable_static!(static VT for #component_id);
let mut self_ = Self {
#(#item_names : ::core::default::Default::default(),)*
#(#declared_property_vars : ::core::default::Default::default(),)*
#(#declared_signals : ::core::default::Default::default(),)*
#(#repeated_element_names : ::core::default::Default::default(),)*
#(#repeated_dynmodel_names : ::core::default::Default::default(),)*
self_weak : ::core::default::Default::default(),
#(parent : sixtyfps::re_exports::WeakPin::<#parent_component_type>::default(),)*
};
#(#init)*
self_
}
}
impl sixtyfps::re_exports::Component for #component_id {
fn visit_children_item(self: ::core::pin::Pin<&Self>, index: isize, visitor: sixtyfps::re_exports::ItemVisitorRefMut) {
use sixtyfps::re_exports::*;
@ -386,6 +356,27 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
}
impl #component_id{
fn new(#(parent: sixtyfps::re_exports::WeakPin::<#parent_component_type>)*)
-> core::pin::Pin<std::rc::Rc<Self>>
{
#![allow(unused)]
use sixtyfps::re_exports::*;
ComponentVTable_static!(static VT for #component_id);
let mut self_ = Self {
#(#item_names : ::core::default::Default::default(),)*
#(#declared_property_vars : ::core::default::Default::default(),)*
#(#declared_signals : ::core::default::Default::default(),)*
#(#repeated_element_names : ::core::default::Default::default(),)*
#(#repeated_dynmodel_names : ::core::default::Default::default(),)*
self_weak : ::core::default::Default::default(),
#(parent : parent as sixtyfps::re_exports::WeakPin::<#parent_component_type>,)*
};
let self_pinned = std::rc::Rc::pin(self_);
self_pinned.self_weak.set(WeakPin::downgrade(self_pinned.clone())).map_err(|_|())
.expect("Can only be pinned once");
#(#init)*
self_pinned
}
#(#property_and_signal_accessors)*
}

View file

@ -6,6 +6,7 @@ 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.
///
@ -15,7 +16,7 @@ use super::properties::EvaluationContext;
#[repr(C)]
pub struct Signal<Arg> {
/// FIXME: Box<dyn> is a fat object and we probaly want to put an erased type in there
handler: Option<Box<dyn Fn(&EvaluationContext, Arg)>>,
handler: Cell<Option<Box<dyn Fn(&EvaluationContext, Arg)>>>,
}
impl<Arg> Signal<Arg> {
@ -23,16 +24,18 @@ impl<Arg> Signal<Arg> {
///
/// The constext must be a context corresponding to the component in which the signal is contained.
pub fn emit(&self, context: &EvaluationContext, a: Arg) {
if let Some(h) = &self.handler {
if let Some(h) = self.handler.take() {
h(context, a);
assert!(self.handler.take().is_none(), "Signal Handler set while emitted");
self.handler.set(Some(h))
}
}
/// Set an handler to be called when the signal is emited
///
/// There can only be one single handler per signal.
pub fn set_handler(&mut self, f: impl Fn(&EvaluationContext, Arg) + 'static) {
self.handler = Some(Box::new(f));
pub fn set_handler(&self, f: impl Fn(&EvaluationContext, Arg) + 'static) {
self.handler.set(Some(Box::new(f)));
}
}
@ -57,7 +60,7 @@ fn signal_simple_test() {
fn compute_layout(self: Pin<&Self>, _: &crate::EvaluationContext) {}
}
use crate::abi::datastructures::ComponentVTable;
let mut c = Component::default();
let c = Component::default();
c.clicked.set_handler(|c, ()| unsafe {
(*(c.component.as_ptr() as *const Component)).pressed.set(true)
});

View file

@ -18,7 +18,7 @@ assert(instance.get_t4() == 3 + - 5 - 8 - -9 * - - - 120);
```rust
let instance = Box::pin(TestCase::default());
let instance = TestCase::new();
let instance = instance.as_ref();
assert_eq!(instance.get_t1(), 4 + 3 * 2 + 2 - 50 - 2);
assert_eq!(instance.get_t2(), 500 / 2 * 30 - 1);

View file

@ -11,7 +11,7 @@ assert(!instance.get_falsevar());
```rust
let instance = Box::pin(TestCase::default());
let instance = TestCase::new();
let instance = instance.as_ref();
assert!(instance.get_truevar(), 1);
assert!(!instance.get_falsevar(), 1);

View file

@ -21,7 +21,7 @@ assert(instance.get_s1() == "123");
```rust
let instance = Box::pin(TestCase::default());
let instance = TestCase::new();
let instance = instance.as_ref();
instance.set_condition(true);
assert_eq!(instance.get_s1(), "abc");

View file

@ -27,7 +27,7 @@ assert(t.get_b1() != t.get_r5());
```rust
let t = Box::pin(Test::default());
let t = Test::new();
let t = t.as_ref();
assert_eq!(t.get_r1(), t.get_r2());
assert_eq!(t.get_r1(), t.get_r3());

View file

@ -58,7 +58,7 @@ assert(instance.get_t6() == true);
```rust
let instance = Box::pin(TestCase::default());
let instance = TestCase::new();
let instance = instance.as_ref();
assert_eq!(instance.get_t1(), true);

View file

@ -20,7 +20,7 @@ assert(instance.get_test_value2() == 3);
```rust
let instance = Box::pin(TestCase::default());
let instance = TestCase::new();
let instance = instance.as_ref();
instance.set_condition(true);
assert_eq!(instance.get_test_value(), 1);

View file

@ -14,7 +14,7 @@ assert(instance.get_signal_emission_count() == 1);
```rust
let instance = Box::pin(TestCase::default());
let instance = TestCase::new();
let instance = instance.as_ref();
instance.set_signal_emission_count(0);
assert_eq!(instance.get_signal_emission_count(), 0);

View file

@ -8,7 +8,7 @@ TestCase instance;
```
```rust
TestCase::default();
TestCase::new();
```
```js