Revert "Deduplicate use of ptr_eq for Models"

This was not intended to get uploaded without review!

This reverts commit d678f4b1da.
This commit is contained in:
Tobias Hunger 2022-01-03 17:10:27 +01:00
parent ee3d51ce54
commit 6d69c343dc
No known key found for this signature in database
GPG key ID: 60874021D2F23F91
6 changed files with 18 additions and 54 deletions

View file

@ -9,8 +9,6 @@ All notable changes to this project will be documented in this file.
has changed. This was undocumented, but if one was handling this in the has changed. This was undocumented, but if one was handling this in the
`FocusScope` event, these keys will now be ignored. Use the `Keys.LeftArrow` `FocusScope` event, these keys will now be ignored. Use the `Keys.LeftArrow`
and other code exposed in the `Keys` namespace instead and other code exposed in the `Keys` namespace instead
- **Breaking:** Changed the base class of `ModelHandle` to be a `SharedModel` which wraps the
`Rc<dyn Model>` that was used before.
### Added ### Added

View file

@ -188,7 +188,7 @@ fn to_eval_value<'cx>(
obj.get(cx, "rowCount")?.downcast_or_throw::<JsFunction, _>(cx)?; obj.get(cx, "rowCount")?.downcast_or_throw::<JsFunction, _>(cx)?;
obj.get(cx, "rowData")?.downcast_or_throw::<JsFunction, _>(cx)?; obj.get(cx, "rowData")?.downcast_or_throw::<JsFunction, _>(cx)?;
let m = js_model::JsModel::new(obj, *a, cx, persistent_context)?; let m = js_model::JsModel::new(obj, *a, cx, persistent_context)?;
Ok(Value::Model(sixtyfps_corelib::model::SharedModel(m))) Ok(Value::Model(m))
} }
}, },
Type::Image => { Type::Image => {

View file

@ -291,7 +291,7 @@ impl<T: 'static> VecModel<T> {
where where
T: Clone, T: Clone,
{ {
ModelHandle::new(Rc::<Self>::new(slice.to_vec().into())) ModelHandle(Some(Rc::<Self>::new(slice.to_vec().into())))
} }
/// Add a row at the end of the model /// Add a row at the end of the model
@ -372,49 +372,14 @@ impl Model for bool {
} }
} }
/// A shared model
#[repr(transparent)]
#[derive(derive_more::Deref, derive_more::DerefMut)]
pub struct SharedModel<T>(pub Rc<dyn Model<Data = T>>);
impl<T> std::fmt::Debug for SharedModel<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SharedModel(dyn Model)")
}
}
impl<T> Clone for SharedModel<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> core::cmp::PartialEq for SharedModel<T> {
#[allow(clippy::vtable_address_comparisons)]
// We think vtable_address_comparisons are safe here!
// Rc::ptr_eq will compare a fat pointer consisting of a `vtable` and a `self` pointer.
//
// We can get:
// * false positives: Two different `Model`s get considered the same, even though they are not.
// For this the `self` pointer need to point to the same place. That can not happen here
// since `Rc` will allocate for the refcounts, even if `T` is `()`.
// * false negatives: The same `Model` gets considered to be two different `Model`s.
// In this case the `vtable` pointer must differ, e.g. because two crates created separate
// instances of the vtable for the `Model` trait.
// This will trigger some unnecessary rendering, but is benign otherwise.
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
}
/// Properties of type array in the .60 language are represented as /// Properties of type array in the .60 language are represented as
/// an [`Option`] of an [`SharedModel`] /// an [`Option`] of an [`Rc`] of something implemented the [`Model`] trait
#[derive(derive_more::Deref, derive_more::DerefMut, derive_more::From, derive_more::Into)] #[derive(derive_more::Deref, derive_more::DerefMut, derive_more::From, derive_more::Into)]
pub struct ModelHandle<T>(pub Option<SharedModel<T>>); pub struct ModelHandle<T>(pub Option<Rc<dyn Model<Data = T>>>);
impl<T> core::fmt::Debug for ModelHandle<T> { impl<T> core::fmt::Debug for ModelHandle<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "ModelHandle({:?})", self.0.as_ref()) write!(f, "ModelHandle({:?})", self.0.as_ref().map(|_| "dyn Model"))
} }
} }
@ -433,22 +398,26 @@ impl<T> core::cmp::PartialEq for ModelHandle<T> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
match (&self.0, &other.0) { match (&self.0, &other.0) {
(None, None) => true, (None, None) => true,
(Some(a), Some(b)) => a == b, (None, Some(_)) => false,
_ => false, (Some(_), None) => false,
(Some(a), Some(b)) => core::ptr::eq(
(&**a) as *const dyn Model<Data = T> as *const u8,
(&**b) as *const dyn Model<Data = T> as *const u8,
),
} }
} }
} }
impl<T> From<Rc<dyn Model<Data = T>>> for ModelHandle<T> { impl<T> From<Rc<dyn Model<Data = T>>> for ModelHandle<T> {
fn from(x: Rc<dyn Model<Data = T>>) -> Self { fn from(x: Rc<dyn Model<Data = T>>) -> Self {
Self(Some(SharedModel(x))) Self(Some(x))
} }
} }
impl<T> ModelHandle<T> { impl<T> ModelHandle<T> {
/// Create a new handle wrapping the given model /// Create a new handle wrapping the given model
pub fn new(model: Rc<dyn Model<Data = T>>) -> Self { pub fn new(model: Rc<dyn Model<Data = T>>) -> Self {
Self(Some(SharedModel(model))) Self(Some(model))
} }
} }

View file

@ -97,7 +97,7 @@ pub enum Value {
/// An Array in the .60 language. /// An Array in the .60 language.
Array(SharedVector<Value>), Array(SharedVector<Value>),
/// A more complex model which is not created by the interpreter itself (Value::Array can also be used for models) /// A more complex model which is not created by the interpreter itself (Value::Array can also be used for models)
Model(sixtyfps_corelib::model::SharedModel<Value>), Model(Rc<dyn sixtyfps_corelib::model::Model<Data = Value>>),
/// An object /// An object
Struct(Struct), Struct(Struct),
/// Correspond to `brush` or `color` type in .60. For color, this is then a [`Brush::SolidColor`] /// Correspond to `brush` or `color` type in .60. For color, this is then a [`Brush::SolidColor`]
@ -149,7 +149,7 @@ impl PartialEq for Value {
Value::Bool(lhs) => matches!(other, Value::Bool(rhs) if lhs == rhs), Value::Bool(lhs) => matches!(other, Value::Bool(rhs) if lhs == rhs),
Value::Image(lhs) => matches!(other, Value::Image(rhs) if lhs == rhs), Value::Image(lhs) => matches!(other, Value::Image(rhs) if lhs == rhs),
Value::Array(lhs) => matches!(other, Value::Array(rhs) if lhs == rhs), Value::Array(lhs) => matches!(other, Value::Array(rhs) if lhs == rhs),
Value::Model(lhs) => matches!(other, Value::Model(rhs) if lhs == rhs), Value::Model(lhs) => matches!(other, Value::Model(rhs) if Rc::ptr_eq(lhs, rhs)),
Value::Struct(lhs) => matches!(other, Value::Struct(rhs) if lhs == rhs), Value::Struct(lhs) => matches!(other, Value::Struct(rhs) if lhs == rhs),
Value::Brush(lhs) => matches!(other, Value::Brush(rhs) if lhs == rhs), Value::Brush(lhs) => matches!(other, Value::Brush(rhs) if lhs == rhs),
Value::PathElements(lhs) => matches!(other, Value::PathElements(rhs) if lhs == rhs), Value::PathElements(lhs) => matches!(other, Value::PathElements(rhs) if lhs == rhs),

View file

@ -1365,8 +1365,8 @@ pub fn instantiate(
InstanceRef::from_pin_ref(c, guard) InstanceRef::from_pin_ref(c, guard)
}), }),
); );
sixtyfps_corelib::model::ModelHandle::new(Rc::new(crate::value_model::ValueModel::new( sixtyfps_corelib::model::ModelHandle(Some(Rc::new(
m, crate::value_model::ValueModel::new(m),
))) )))
}); });
} }

View file

@ -123,10 +123,7 @@ pub unsafe extern "C" fn sixtyfps_interpreter_value_new_model(
model: vtable::VBox<ModelAdaptorVTable>, model: vtable::VBox<ModelAdaptorVTable>,
val: *mut ValueOpaque, val: *mut ValueOpaque,
) { ) {
std::ptr::write( std::ptr::write(val as *mut Value, Value::Model(Rc::new(ModelAdaptorWrapper(model))))
val as *mut Value,
Value::Model(sixtyfps_corelib::model::SharedModel(Rc::new(ModelAdaptorWrapper(model)))),
)
} }
#[no_mangle] #[no_mangle]