Rename ModelHandle to SharedModel

This patch is mostly a rename now, but also contains a few small
cleanups.

SharedModel implements the Model trait itself and gracefully falls back
to an empty model is no Model was provided. This allows for some small
simplifications.

Also make sure to use the same comparision for SharedModels everywhere.
This fixes the last remaining clippy errors we had.
This commit is contained in:
Tobias Hunger 2022-01-27 19:10:16 +01:00 committed by Tobias Hunger
parent afb3f269c1
commit 018c1a6666
22 changed files with 88 additions and 112 deletions

View file

@ -21,6 +21,7 @@ as well as the [Rust migration guide for the `sixtyfps` crate](api/sixtyfps-rs/m
- In Rust and C++, `sixtyfps::Image::size()` now returns an integer size type.
- `sixtyfps::interpreter::CallCallbackError` was renamed to `sixtyfps::interpreter::InvokeCallbackError`
- Some deprecation warning in .60 became hard errors
- Replace `ModelHandle` with `ModelRc`
### Added

View file

@ -5,7 +5,7 @@ use core::cell::RefCell;
use neon::prelude::*;
use rand::RngCore;
use sixtyfps_compilerlib::langtype::Type;
use sixtyfps_corelib::model::{Model, ModelHandle};
use sixtyfps_corelib::model::{Model, ModelRc};
use sixtyfps_corelib::window::WindowHandleAccess;
use sixtyfps_corelib::{ImageInner, SharedVector};
use std::rc::Rc;
@ -182,21 +182,20 @@ fn to_eval_value<'cx>(
Type::Array(a) => match val.downcast::<JsArray>() {
Ok(arr) => {
let vec = arr.to_vec(cx)?;
Ok(Value::Model(ModelHandle::new(Rc::new(
Ok(Value::Model(ModelRc::new(Rc::new(
sixtyfps_corelib::model::SharedVectorModel::from(
vec.into_iter()
.map(|i| to_eval_value(i, (*a).clone(), cx, persistent_context))
.collect::<Result<SharedVector<_>, _>>()?,
),
)
as Rc<dyn sixtyfps_corelib::model::Model<Data = Value>>)))
))))
}
Err(_) => {
let obj = val.downcast_or_throw::<JsObject, _>(cx)?;
obj.get(cx, "rowCount")?.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)?;
Ok(Value::Model(ModelHandle::new(m)))
Ok(Value::Model(ModelRc::new(m)))
}
},
Type::Image => {

View file

@ -181,7 +181,7 @@ The follow table summarizes the entire mapping:
| `duration` | `i64` | At run-time, durations are always represented as signed 64-bit integers with millisecond precision. |
| `angle` | `f32` | The value in degrees |
| structure | `struct` of the same name | |
| array | [`ModelHandle`] | |
| array | [`ModelRc`] | |
For user defined structures in the .60, an extra struct is generated.
For example, if the `.60` contains
@ -233,7 +233,7 @@ pub use sixtyfps_corelib::graphics::{
Brush, Color, Image, LoadImageError, Rgb8Pixel, Rgba8Pixel, RgbaColor, SharedPixelBuffer,
};
pub use sixtyfps_corelib::model::{
Model, ModelHandle, ModelNotify, ModelPeer, ModelTracker, StandardListViewItem, VecModel,
Model, ModelNotify, ModelPeer, ModelRc, ModelTracker, StandardListViewItem, VecModel,
};
pub use sixtyfps_corelib::sharedvector::SharedVector;
pub use sixtyfps_corelib::string::SharedString;

View file

@ -62,3 +62,6 @@ fn model_tracker(&self) -> &dyn ModelTracker {
}
```
#### Minor changes to `Model`
`ModelRc` replaces `ModelHandle`.

View file

@ -20,7 +20,7 @@ fn main() {
// ANCHOR: game_logic
// Assign the shuffled Vec to the model property
let tiles_model = std::rc::Rc::new(sixtyfps::VecModel::from(tiles));
main_window.set_memory_tiles(sixtyfps::ModelHandle::new(tiles_model.clone()));
main_window.set_memory_tiles(sixtyfps::ModelRc::new(tiles_model.clone()));
let main_window_weak = main_window.as_weak();
main_window.on_check_if_pair_solved(move || {

View file

@ -20,7 +20,7 @@ fn main() {
// Assign the shuffled Vec to the model property
let tiles_model = std::rc::Rc::new(sixtyfps::VecModel::from(tiles));
main_window.set_memory_tiles(sixtyfps::ModelHandle::new(tiles_model));
main_window.set_memory_tiles(sixtyfps::ModelRc::new(tiles_model));
main_window.run();
}

View file

@ -140,7 +140,7 @@ pub fn main() {
]);
let filters = Rc::new(filters);
main_window.set_filters(sixtyfps::ModelHandle::new(filters.clone()));
main_window.set_filters(sixtyfps::ModelRc::new(filters.clone()));
main_window.on_filter_image(move |filter_index| {
let filter_fn = filters.0[filter_index as usize].apply_function;

View file

@ -1,7 +1,7 @@
// Copyright © SixtyFPS GmbH <info@sixtyfps.io>
// SPDX-License-Identifier: (GPL-3.0-only OR LicenseRef-SixtyFPS-commercial)
use sixtyfps::{Model, ModelHandle, Timer, VecModel};
use sixtyfps::{Model, ModelRc, Timer, VecModel};
use std::rc::Rc;
use std::time::Duration;
@ -30,7 +30,7 @@ pub fn main() {
let tiles_model = Rc::new(VecModel::from(tiles));
main_window.set_memory_tiles(ModelHandle::new(tiles_model.clone()));
main_window.set_memory_tiles(ModelRc::new(tiles_model.clone()));
let main_window_weak = main_window.as_weak();

View file

@ -59,7 +59,7 @@ pub fn main() {
});
main_window
.global::<PrinterQueue>()
.set_printer_queue(sixtyfps::ModelHandle::new(printer_queue.data.clone()));
.set_printer_queue(sixtyfps::ModelRc::new(printer_queue.data.clone()));
main_window.on_quit(move || {
#[cfg(not(target_arch = "wasm32"))]

View file

@ -180,7 +180,7 @@ pub fn main() {
finished: false,
}));
state.borrow_mut().randomize();
main_window.set_pieces(sixtyfps::ModelHandle::new(state.borrow().pieces.clone()));
main_window.set_pieces(sixtyfps::ModelRc::new(state.borrow().pieces.clone()));
let state_copy = state.clone();
main_window.on_piece_clicked(move |p| {

View file

@ -45,7 +45,7 @@ pub fn main() {
}
});
main_window.set_todo_model(sixtyfps::ModelHandle::new(todo_model));
main_window.set_todo_model(sixtyfps::ModelRc::new(todo_model));
main_window.run();
}

View file

@ -78,7 +78,7 @@ fn rust_type(ty: &Type) -> Option<proc_macro2::TokenStream> {
Type::Struct { name: Some(name), .. } => Some(struct_name_to_tokens(name)),
Type::Array(o) => {
let inner = rust_type(o)?;
Some(quote!(sixtyfps::re_exports::ModelHandle<#inner>))
Some(quote!(sixtyfps::re_exports::ModelRc<#inner>))
}
Type::Enumeration(e) => {
let e = ident(&e.name);
@ -536,7 +536,7 @@ fn generate_sub_component(
let mut model = compile_expression(&repeated.model, &ctx);
if repeated.model.ty(&ctx) == Type::Bool {
model = quote!(sixtyfps::re_exports::ModelHandle::new(sixtyfps::re_exports::Rc::<bool>::new(#model)))
model = quote!(sixtyfps::re_exports::ModelRc::new(sixtyfps::re_exports::Rc::<bool>::new(#model)))
}
init.push(quote! {
@ -1273,7 +1273,7 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
))
}
(Type::Float32, Type::Model) | (Type::Int32, Type::Model) => {
quote!(sixtyfps::re_exports::ModelHandle::new(sixtyfps::re_exports::Rc::<usize>::new(#f as usize)))
quote!(sixtyfps::re_exports::ModelRc::new(sixtyfps::re_exports::Rc::<usize>::new(#f as usize)))
}
(Type::Float32, Type::Color) => {
quote!(sixtyfps::re_exports::Color::from_argb_encoded(#f as u32))
@ -1446,7 +1446,7 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
let base_e = compile_expression(array, ctx);
let index_e = compile_expression(index, ctx);
let value_e = compile_expression(value, ctx);
quote!((#base_e).set_row_data(#index_e as usize, #value_e as _);)
quote!((#base_e).set_row_data(#index_e as usize, #value_e as _))
}
Expression::BinaryExpression { lhs, rhs, op } => {
let (conv1, conv2) = match crate::expression_tree::operator_class(*op) {
@ -1536,7 +1536,7 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
let val = values.iter().map(|e| compile_expression(e, ctx));
if *as_model {
let rust_element_ty = rust_type(element_ty).unwrap();
quote!(sixtyfps::re_exports::ModelHandle::new(
quote!(sixtyfps::re_exports::ModelRc::new(
sixtyfps::re_exports::Rc::new(sixtyfps::re_exports::VecModel::<#rust_element_ty>::from(
sixtyfps::re_exports::vec![#(#val as _),*]
))

View file

@ -239,14 +239,14 @@ pub trait Model {
/// Return something that can be downcast'ed (typically self)
///
/// This is useful to get back to the actual model from a ModelHandle stored
/// This is useful to get back to the actual model from a `ModelRc` stored
/// in a component.
///
/// ```
/// # use sixtyfps_corelib::model::*;
/// # use std::rc::Rc;
/// let vec_model = Rc::new(VecModel::from(vec![1i32, 2, 3]));
/// let handle = ModelHandle::from(vec_model as Rc<dyn Model<Data = i32>>);
/// let handle = ModelRc::new(vec_model as Rc<dyn Model<Data = i32>>);
/// // later:
/// handle.as_any().downcast_ref::<VecModel<i32>>().unwrap().push(4);
/// assert_eq!(handle.row_data(3).unwrap(), 4);
@ -305,11 +305,11 @@ pub struct VecModel<T> {
impl<T: 'static> VecModel<T> {
/// Allocate a new model from a slice
pub fn from_slice(slice: &[T]) -> ModelHandle<T>
pub fn from_slice(slice: &[T]) -> ModelRc<T>
where
T: Clone,
{
ModelHandle(Some(Rc::<Self>::new(slice.to_vec().into())))
ModelRc::new(Rc::<Self>::new(slice.to_vec().into()))
}
/// Add a row at the end of the model
@ -462,56 +462,49 @@ impl Model for bool {
}
}
/// Properties of type array in the .60 language are represented as
/// an [`Option`] of an [`Rc`] of something implemented the [`Model`] trait
/// Properties of type Array in the .60 language are represented as
/// a `ModelRc` that implements the `Model` trait.
#[derive(derive_more::Deref, derive_more::DerefMut, derive_more::From, derive_more::Into)]
pub struct ModelHandle<T>(pub Option<Rc<dyn Model<Data = T>>>);
pub struct ModelRc<T>(Option<Rc<dyn Model<Data = T>>>);
impl<T> core::fmt::Debug for ModelHandle<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "ModelHandle({:?})", self.0.as_ref().map(|_| "dyn Model"))
impl<T> core::fmt::Debug for ModelRc<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ModelRc(dyn Model)")
}
}
impl<T> Clone for ModelHandle<T> {
impl<T> Clone for ModelRc<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> Default for ModelHandle<T> {
impl<T> Default for ModelRc<T> {
fn default() -> Self {
Self(None)
}
}
impl<T> core::cmp::PartialEq for ModelHandle<T> {
impl<T> core::cmp::PartialEq for ModelRc<T> {
fn eq(&self, other: &Self) -> bool {
match (&self.0, &other.0) {
(None, None) => true,
(None, Some(_)) => 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,
),
_ => false,
}
}
}
impl<T> From<Rc<dyn Model<Data = T>>> for ModelHandle<T> {
fn from(x: Rc<dyn Model<Data = T>>) -> Self {
Self(Some(x))
}
}
impl<T> ModelHandle<T> {
/// Create a new handle wrapping the given model
impl<T> ModelRc<T> {
pub fn new(model: Rc<dyn Model<Data = T>>) -> Self {
Self(Some(model))
}
}
impl<T> Model for ModelHandle<T> {
impl<T> Model for ModelRc<T> {
type Data = T;
fn row_count(&self) -> usize {
@ -524,7 +517,7 @@ impl<T> Model for ModelHandle<T> {
fn set_row_data(&self, row: usize, data: Self::Data) {
if let Some(model) = self.0.as_ref() {
model.set_row_data(row, data)
model.set_row_data(row, data);
}
}
@ -656,7 +649,7 @@ impl<C: RepeatedComponent> ErasedRepeater for Repeater<C> {
pub struct Repeater<C: RepeatedComponent> {
inner: RefCell<RepeaterInner<C>>,
#[pin]
model: Property<ModelHandle<C::Data>>,
model: Property<ModelRc<C::Data>>,
#[pin]
is_dirty: Property<bool>,
/// Only used for the list view to track if the scrollbar has changed and item needs to be layed out again.
@ -694,24 +687,22 @@ impl<C: RepeatedComponent> PinnedDrop for Repeater<C> {
}
impl<C: RepeatedComponent + 'static> Repeater<C> {
fn model(self: Pin<&Self>) -> ModelHandle<C::Data> {
// Safety: Repeater does not implement drop and never let access model as mutable
fn model(self: Pin<&Self>) -> ModelRc<C::Data> {
// Safety: Repeater does not implement drop and never allows access to model as mutable
let model = self.project_ref().model;
if model.is_dirty() {
*self.inner.borrow_mut() = RepeaterInner::default();
self.is_dirty.set(true);
if let ModelHandle(Some(m)) = model.get() {
let peer = self.peer.get_or_init(|| {
//Safety: we will reset it when we Drop the Repeater
Rc::pin(DependencyNode::new(
self.get_ref() as &dyn ErasedRepeater as *const dyn ErasedRepeater
))
});
let m = model.get();
let peer = self.peer.get_or_init(|| {
//Safety: we will reset it when we Drop the Repeater
Rc::pin(DependencyNode::new(
self.get_ref() as &dyn ErasedRepeater as *const dyn ErasedRepeater
))
});
m.model_tracker()
.attach_peer(ModelPeer { inner: PinWeak::downgrade(peer.clone()) });
}
m.model_tracker().attach_peer(ModelPeer { inner: PinWeak::downgrade(peer.clone()) });
}
model.get()
}
@ -719,12 +710,9 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
/// Call this function to make sure that the model is updated.
/// The init function is the function to create a component
pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ComponentRc<C>) {
if let ModelHandle(Some(model)) = self.model() {
if self.project_ref().is_dirty.get() {
self.ensure_updated_impl(init, &model, model.row_count());
}
} else {
self.inner.borrow_mut().components.clear();
let model = self.model();
if self.project_ref().is_dirty.get() {
self.ensure_updated_impl(init, &model, model.row_count());
}
}
@ -732,7 +720,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
fn ensure_updated_impl(
self: Pin<&Self>,
init: impl Fn() -> ComponentRc<C>,
model: &Rc<dyn Model<Data = C::Data>>,
model: &ModelRc<C::Data>,
count: usize,
) -> bool {
let mut inner = self.inner.borrow_mut();
@ -769,11 +757,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
viewport_y.set(0.);
};
let model = if let ModelHandle(Some(model)) = self.model() {
model
} else {
return empty_model();
};
let model = self.model();
let row_count = model.row_count();
if row_count == 0 {
return empty_model();
@ -785,8 +769,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
let geometry_updated = listview_geometry_tracker
.evaluate_if_dirty(|| {
// Fetch the model again to make sure that it is a dependency of this geometry tracker.
// invariant: model existence was checked earlier, so unwrap() should be safe.
let model = self.model().0.unwrap();
let model = self.model();
// Also register a dependency to "is_dirty"
let _ = self.project_ref().is_dirty.get();
@ -904,14 +887,13 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
/// Sets the data directly in the model
pub fn model_set_row_data(self: Pin<&Self>, row: usize, data: C::Data) {
if let ModelHandle(Some(model)) = self.model() {
model.set_row_data(row, data);
if let Some(c) = self.inner.borrow_mut().components.get_mut(row) {
if c.0 == RepeatedComponentState::Dirty {
if let Some(comp) = c.1.as_ref() {
comp.update(row, model.row_data(row).unwrap());
c.0 = RepeatedComponentState::Clean;
}
let model = self.model();
model.set_row_data(row, data);
if let Some(c) = self.inner.borrow_mut().components.get_mut(row) {
if c.0 == RepeatedComponentState::Dirty {
if let Some(comp) = c.1.as_ref() {
comp.update(row, model.row_data(row).unwrap());
c.0 = RepeatedComponentState::Clean;
}
}
}
@ -920,7 +902,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
impl<C: RepeatedComponent> Repeater<C> {
/// Set the model binding
pub fn set_model_binding(&self, binding: impl Fn() -> ModelHandle<C::Data> + 'static) {
pub fn set_model_binding(&self, binding: impl Fn() -> ModelRc<C::Data> + 'static) {
self.model.set_binding(binding);
}
@ -991,7 +973,7 @@ pub struct StandardListViewItem {
#[test]
fn test_tracking_model_handle() {
let model: Rc<VecModel<u8>> = Rc::new(Default::default());
let handle = ModelHandle::new(model.clone());
let handle = ModelRc::new(model.clone());
let tracker = Box::pin(crate::properties::PropertyTracker::default());
assert_eq!(
tracker.as_ref().evaluate(|| {
@ -1028,7 +1010,7 @@ fn test_tracking_model_handle() {
#[test]
fn test_data_tracking() {
let model: Rc<VecModel<u8>> = Rc::new(VecModel::from(vec![0, 1, 2, 3, 4]));
let handle = ModelHandle::new(model.clone());
let handle = ModelRc::new(model.clone());
let tracker = Box::pin(crate::properties::PropertyTracker::default());
assert_eq!(
tracker.as_ref().evaluate(|| {

View file

@ -4,7 +4,7 @@
use core::convert::TryInto;
use sixtyfps_compilerlib::langtype::Type as LangType;
use sixtyfps_corelib::graphics::Image;
use sixtyfps_corelib::model::{Model, ModelHandle};
use sixtyfps_corelib::model::{Model, ModelRc};
use sixtyfps_corelib::{Brush, PathData, SharedString, SharedVector};
use std::borrow::Cow;
use std::collections::HashMap;
@ -92,7 +92,7 @@ pub enum Value {
/// Correspond to the `image` type in .60
Image(Image),
/// A model (that includes array in .60)
Model(ModelHandle<Value>),
Model(ModelRc<Value>),
/// An object
Struct(Struct),
/// Correspond to `brush` or `color` type in .60. For color, this is then a [`Brush::SolidColor`]
@ -144,11 +144,7 @@ impl PartialEq for Value {
Value::Image(lhs) => matches!(other, Value::Image(rhs) if lhs == rhs),
Value::Model(lhs) => {
if let Value::Model(rhs) = other {
match (&lhs.0, &rhs.0) {
(None, None) => true,
(None, Some(_)) | (Some(_), None) => false,
(Some(a), Some(b)) => Rc::ptr_eq(a, b),
}
lhs == rhs
} else {
false
}
@ -1364,13 +1360,13 @@ fn component_definition_model_properties() {
let instance = comp_def.create();
let int_model = Value::Model(ModelHandle::new(Rc::new(VecModel::from_slice(&[
let int_model = Value::Model(ModelRc::new(Rc::new(VecModel::from_slice(&[
Value::Number(14.),
Value::Number(15.),
Value::Number(16.),
]))));
let empty_model = Value::Model(ModelHandle::new(Rc::new(VecModel::<Value>::default())));
let model_with_string = Value::Model(ModelHandle::new(Rc::new(VecModel::from_slice(&[
let empty_model = Value::Model(ModelRc::new(Rc::new(VecModel::<Value>::default())));
let model_with_string = Value::Model(ModelRc::new(Rc::new(VecModel::from_slice(&[
Value::Number(1000.),
Value::String("foo".into()),
Value::Number(1111.),

View file

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

View file

@ -7,7 +7,7 @@ use core::convert::TryInto;
use core::pin::Pin;
use corelib::graphics::{GradientStop, LinearGradientBrush, PathElement};
use corelib::items::{ItemRef, PropertyAnimation};
use corelib::model::{Model, ModelHandle};
use corelib::model::{Model, ModelRc};
use corelib::rtti::AnimatedBindingKind;
use corelib::window::{WindowHandleAccess, WindowRc};
use corelib::{Brush, Color, PathData, SharedString, SharedVector};
@ -568,10 +568,10 @@ pub fn eval_expression(expression: &Expression, local_context: &mut EvalLocalCon
}
}
Expression::Array { values, .. } => Value::Model(
ModelHandle::new(Rc::new(corelib::model::SharedVectorModel::from(
ModelRc::new(Rc::new(corelib::model::SharedVectorModel::from(
values.iter().map(|e| eval_expression(e, local_context)).collect::<SharedVector<_>>()
)) as Rc<dyn corelib::model::Model<Data = Value>>)
),
)
))),
Expression::Struct { values, .. } => Value::Struct(
values
.iter()

View file

@ -85,7 +85,7 @@ pub unsafe extern "C" fn sixtyfps_interpreter_value_new_array_model(
let vec = std::mem::transmute::<SharedVector<ValueOpaque>, SharedVector<Value>>(a.clone());
std::ptr::write(
val as *mut Value,
Value::Model(ModelHandle::new(Rc::new(SharedVectorModel::<Value>::from(vec)))),
Value::Model(ModelRc::new(Rc::new(SharedVectorModel::<Value>::from(vec)))),
)
}
@ -121,7 +121,7 @@ pub unsafe extern "C" fn sixtyfps_interpreter_value_new_model(
) {
std::ptr::write(
val as *mut Value,
Value::Model(ModelHandle::new(Rc::new(ModelAdaptorWrapper(model)))),
Value::Model(ModelRc::new(Rc::new(ModelAdaptorWrapper(model)))),
)
}

View file

@ -52,7 +52,7 @@ assert(!instance.get_hover());
use sixtyfps::Model;
let instance = TestCase::new();
let vec_model = std::rc::Rc::new(sixtyfps::VecModel::from(vec![1i32, 2i32]));
instance.set_model(sixtyfps::ModelHandle::from(vec_model.clone() as std::rc::Rc<dyn Model<Data = i32>>));
instance.set_model(sixtyfps::ModelRc::new(vec_model.clone() as std::rc::Rc<dyn Model<Data = i32>>));
instance.on_clicked(move || dbg!(vec_model.remove(vec_model.row_count() - 1)));
sixtyfps::testing::send_mouse_click(&instance, 95., 5.);
assert_eq!(instance.get_model().row_count(), 1);

View file

@ -43,7 +43,7 @@ assert_eq!(instance.get_n(), 4);
assert_eq!(instance.get_third_int(), 3);
let model: std::rc::Rc<sixtyfps::VecModel<i32>> = std::rc::Rc::new(vec![1, 2, 3, 4, 5, 6, 7].into());
instance.set_ints(sixtyfps::ModelHandle::new(model.clone()));
instance.set_ints(sixtyfps::ModelRc::new(model.clone()));
assert_eq!(instance.get_num_ints(), 7);
assert_eq!(instance.get_third_int(), 3);
model.push(8);

View file

@ -62,7 +62,7 @@ let another_model = std::rc::Rc::new(sixtyfps::VecModel::<ModelData>::from(
("a3".into(), "world".into(), 333.),
]));
instance.set_model(sixtyfps::ModelHandle::new(another_model.clone()));
instance.set_model(sixtyfps::ModelRc::new(another_model.clone()));
sixtyfps::testing::send_mouse_click(&instance, 25., 5.);
assert_eq!(instance.get_clicked_score(), 333000);

View file

@ -61,7 +61,7 @@ let another_model = std::rc::Rc::new(sixtyfps::VecModel::<ModelData>::from(
("a3".into(), "world".into(), 333.),
]));
instance.set_model(sixtyfps::ModelHandle::new(another_model.clone()));
instance.set_model(sixtyfps::ModelRc::new(another_model.clone()));
sixtyfps::testing::send_mouse_click(&instance, 25., 5.);
assert_eq!(instance.get_clicked_score(), 336);

View file

@ -3,7 +3,7 @@
#![doc = include_str!("README.md")]
use sixtyfps_corelib::model::{Model, ModelHandle};
use sixtyfps_corelib::model::{Model, ModelRc};
use sixtyfps_corelib::SharedVector;
use sixtyfps_interpreter::{ComponentInstance, SharedString, Value};
use std::future::Future;
@ -268,12 +268,9 @@ fn load_data(instance: &ComponentInstance, data_path: &std::path::Path) -> Resul
}
serde_json::Value::String(s) => SharedString::from(s.as_str()).into(),
serde_json::Value::Array(array) => sixtyfps_interpreter::Value::Model(
ModelHandle::new(Rc::new(sixtyfps_corelib::model::SharedVectorModel::from(
ModelRc::new(Rc::new(sixtyfps_corelib::model::SharedVectorModel::from(
array.iter().map(from_json).collect::<SharedVector<Value>>(),
))
as Rc<
dyn sixtyfps_corelib::model::Model<Data = sixtyfps_interpreter::Value>,
>),
))),
),
serde_json::Value::Object(obj) => obj
.iter()