Two ways binding with optimized public property in the interpreter

This commit is contained in:
Olivier Goffart 2020-09-24 14:10:52 +02:00
parent b5d7adef7d
commit 0cb827a901
5 changed files with 104 additions and 34 deletions

View file

@ -746,7 +746,7 @@ pub unsafe extern "C" fn sixtyfps_flickable_data_free(data: *mut FlickableDataBo
/// The implementation of the `PropertyAnimation` element /// The implementation of the `PropertyAnimation` element
#[repr(C)] #[repr(C)]
#[derive(FieldOffsets, Default, BuiltinItem, Clone)] #[derive(FieldOffsets, Default, BuiltinItem, Clone, Debug)]
#[pin] #[pin]
pub struct PropertyAnimation { pub struct PropertyAnimation {
#[rtti_field] #[rtti_field]

View file

@ -512,6 +512,9 @@ fn generate_component<'id>(
} }
for (name, decl) in &root_component.root_element.borrow().property_declarations { for (name, decl) in &root_component.root_element.borrow().property_declarations {
if decl.is_alias.is_some() {
continue;
}
let (prop, type_info) = match decl.property_type { let (prop, type_info) = match decl.property_type {
Type::Float32 => animated_property_info::<f32>(), Type::Float32 => animated_property_info::<f32>(),
Type::Int32 => animated_property_info::<i32>(), Type::Int32 => animated_property_info::<i32>(),

View file

@ -194,18 +194,20 @@ pub fn eval_expression(
"naked builtin function reference not allowed, should be handled by function call" "naked builtin function reference not allowed, should be handled by function call"
), ),
Expression::PropertyReference(NamedReference { element, name }) => { Expression::PropertyReference(NamedReference { element, name }) => {
load_property(component, &element.upgrade().unwrap(), name.as_ref()) load_property(component, &element.upgrade().unwrap(), name.as_ref()).unwrap()
} }
Expression::RepeaterIndexReference { element } => load_property( Expression::RepeaterIndexReference { element } => load_property(
component, component,
&element.upgrade().unwrap().borrow().base_type.as_component().root_element, &element.upgrade().unwrap().borrow().base_type.as_component().root_element,
"index", "index",
), )
.unwrap(),
Expression::RepeaterModelReference { element } => load_property( Expression::RepeaterModelReference { element } => load_property(
component, component,
&element.upgrade().unwrap().borrow().base_type.as_component().root_element, &element.upgrade().unwrap().borrow().base_type.as_component().root_element,
"model_data", "model_data",
), )
.unwrap(),
Expression::FunctionParameterReference { index, .. } => { Expression::FunctionParameterReference { index, .. } => {
local_context.function_arguments[*index].clone() local_context.function_arguments[*index].clone()
} }
@ -275,18 +277,19 @@ pub fn eval_expression(
} }
Expression::SelfAssignment { lhs, rhs, op } => match &**lhs { Expression::SelfAssignment { lhs, rhs, op } => match &**lhs {
Expression::PropertyReference(NamedReference { element, name }) => { Expression::PropertyReference(NamedReference { element, name }) => {
let mut eval = |lhs| { let rhs = eval_expression(&**rhs, component, local_context);
let rhs = eval_expression(&**rhs, component, local_context); if *op == '=' {
match (lhs, rhs, op) { store_property(component, &element.upgrade().unwrap(), name.as_ref(), rhs)
(_, rhs, '=') => rhs, .unwrap();
(Value::Number(a), Value::Number(b), '+') => Value::Number(a + b), return Value::Void;
(Value::Number(a), Value::Number(b), '-') => Value::Number(a - b), }
(Value::Number(a), Value::Number(b), '/') => Value::Number(a / b), let eval = |lhs| match (lhs, rhs, op) {
(Value::Number(a), Value::Number(b), '*') => Value::Number(a * b), (Value::Number(a), Value::Number(b), '+') => Value::Number(a + b),
(lhs, rhs, op) => panic!("unsupported {:?} {} {:?}", lhs, op, rhs), (Value::Number(a), Value::Number(b), '-') => Value::Number(a - b),
} (Value::Number(a), Value::Number(b), '/') => Value::Number(a / b),
(Value::Number(a), Value::Number(b), '*') => Value::Number(a * b),
(lhs, rhs, op) => panic!("unsupported {:?} {} {:?}", lhs, op, rhs),
}; };
let element = element.upgrade().unwrap(); let element = element.upgrade().unwrap();
generativity::make_guard!(guard); generativity::make_guard!(guard);
let enclosing_component = let enclosing_component =
@ -386,16 +389,14 @@ pub fn eval_expression(
} }
} }
fn load_property(component: InstanceRef, element: &ElementRc, name: &str) -> Value { pub fn load_property(component: InstanceRef, element: &ElementRc, name: &str) -> Result<Value, ()> {
generativity::make_guard!(guard); generativity::make_guard!(guard);
let enclosing_component = enclosing_component_for_element(&element, component, guard); let enclosing_component = enclosing_component_for_element(&element, component, guard);
let element = element.borrow(); let element = element.borrow();
if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id { if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id {
if let Some(x) = enclosing_component.component_type.custom_properties.get(name) { if let Some(x) = enclosing_component.component_type.custom_properties.get(name) {
return unsafe { return unsafe {
x.prop x.prop.get(Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset)))
.get(Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset)))
.unwrap()
}; };
} }
}; };
@ -406,7 +407,37 @@ fn load_property(component: InstanceRef, element: &ElementRc, name: &str) -> Val
.unwrap_or_else(|| panic!("Unkown element for {}.{}", element.id, name)); .unwrap_or_else(|| panic!("Unkown element for {}.{}", element.id, name));
core::mem::drop(element); core::mem::drop(element);
let item = unsafe { item_info.item_from_component(enclosing_component.as_ptr()) }; let item = unsafe { item_info.item_from_component(enclosing_component.as_ptr()) };
item_info.rtti.properties[name].get(item) Ok(item_info.rtti.properties.get(name).ok_or(())?.get(item))
}
pub fn store_property(
component_instance: InstanceRef,
element: &ElementRc,
name: &str,
value: Value,
) -> Result<(), ()> {
generativity::make_guard!(guard);
let enclosing_component = enclosing_component_for_element(&element, component_instance, guard);
let maybe_animation = crate::dynamic_component::animation_for_property(
enclosing_component,
&element.borrow().property_animations,
name,
);
let component = element.borrow().enclosing_component.upgrade().unwrap();
if element.borrow().id == component.root_element.borrow().id {
if let Some(x) = enclosing_component.component_type.custom_properties.get(name) {
unsafe {
let p = Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset));
return x.prop.set(p, value, maybe_animation);
}
}
};
let item_info = &enclosing_component.component_type.items[element.borrow().id.as_str()];
let item = unsafe { item_info.item_from_component(enclosing_component.as_ptr()) };
let p = &item_info.rtti.properties.get(name).ok_or(())?;
p.set(item, value, maybe_animation);
Ok(())
} }
pub fn window_ref(component: InstanceRef) -> Option<sixtyfps_corelib::eventloop::ComponentWindow> { pub fn window_ref(component: InstanceRef) -> Option<sixtyfps_corelib::eventloop::ComponentWindow> {

View file

@ -68,19 +68,19 @@ impl<'id> dynamic_component::ComponentDescription<'id> {
if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) { if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {
return Err(()); return Err(());
} }
let x = self.custom_properties.get(name).ok_or(())?;
generativity::make_guard!(guard); generativity::make_guard!(guard);
let maybe_animation = dynamic_component::animation_for_property( let c = unsafe { InstanceRef::from_pin_ref(component, guard) };
unsafe { InstanceRef::from_pin_ref(component, guard) }, if let Some(alias) = self
&self.original.root_element.borrow().property_animations, .original
name, .root_element
); .borrow()
unsafe { .property_declarations
x.prop.set( .get(name)
Pin::new_unchecked(&*component.as_ptr().add(x.offset)), .and_then(|d| d.is_alias.as_ref())
value, {
maybe_animation, eval::store_property(c, &alias.element.upgrade().unwrap(), &alias.name, value)
) } else {
eval::store_property(c, &self.original.root_element, name, value)
} }
} }
@ -114,8 +114,21 @@ impl<'id> dynamic_component::ComponentDescription<'id> {
if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) { if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {
return Err(()); return Err(());
} }
let x = self.custom_properties.get(name).ok_or(())?; if let Some(alias) = self
unsafe { x.prop.get(Pin::new_unchecked(&*component.as_ptr().add(x.offset))) } .original
.root_element
.borrow()
.property_declarations
.get(name)
.and_then(|d| d.is_alias.as_ref())
{
generativity::make_guard!(guard);
let c = unsafe { InstanceRef::from_pin_ref(component, guard) };
eval::load_property(c, &alias.element.upgrade().unwrap(), &alias.name)
} else {
let x = self.custom_properties.get(name).ok_or(())?;
unsafe { x.prop.get(Pin::new_unchecked(&*component.as_ptr().add(x.offset))) }
}
} }
/// Sets an handler for a signal /// Sets an handler for a signal

View file

@ -76,5 +76,28 @@ assert_eq(instance.get_sub_foo1(), 15);
assert_eq(instance.get_sub_foo2(), 15); assert_eq(instance.get_sub_foo2(), 15);
``` ```
```js
var instance = new sixtyfps.TestCase({});
assert.equal(instance.sub_width1, 80.);
assert.equal(instance.sub_width2, 80.);
instance.sub_width1 = (99.);
assert.equal(instance.sub_width1, 99.);
assert.equal(instance.sub_width2, 99.);
// breaks the binding
instance.sub_width2 = (23.);
assert.equal(instance.sub_width1, 99.);
assert.equal(instance.sub_width2, 23.);
instance.sub_width1 = (88.);
assert.equal(instance.sub_width1, 88.);
assert.equal(instance.sub_width2, 23.);
assert.equal(instance.sub_foo1, 44);
assert.equal(instance.sub_foo2, 44);
instance.sub_foo1 = (15);
assert.equal(instance.sub_foo1, 15);
assert.equal(instance.sub_foo2, 15);
```
*/ */