mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00
Fix read-access through C++ interpreter to models declared as arrays
Arrays declared in .60 are mapped to a SharedVectorModel<Value> in order to permit for write access. They can also be turned intoValue::Array / SharedVector<Value> very cheaply, when reading from C++.
This commit is contained in:
parent
99644a741a
commit
b6492b02e8
5 changed files with 132 additions and 14 deletions
|
@ -419,8 +419,10 @@ inline Value::Value(const sixtyfps::SharedVector<Value> &array)
|
||||||
|
|
||||||
inline std::optional<sixtyfps::SharedVector<Value>> Value::to_array() const
|
inline std::optional<sixtyfps::SharedVector<Value>> Value::to_array() const
|
||||||
{
|
{
|
||||||
if (auto *array = cbindgen_private::sixtyfps_interpreter_value_to_array(&inner)) {
|
sixtyfps::SharedVector<Value> array;
|
||||||
return *reinterpret_cast<const sixtyfps::SharedVector<Value> *>(array);
|
if (cbindgen_private::sixtyfps_interpreter_value_to_array(
|
||||||
|
&inner, &reinterpret_cast<sixtyfps::SharedVector<ValueOpaque> &>(array))) {
|
||||||
|
return array;
|
||||||
} else {
|
} else {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::item_tree::TraversalOrder;
|
||||||
use crate::items::ItemRef;
|
use crate::items::ItemRef;
|
||||||
use crate::layout::Orientation;
|
use crate::layout::Orientation;
|
||||||
use crate::properties::dependency_tracker::DependencyNode;
|
use crate::properties::dependency_tracker::DependencyNode;
|
||||||
use crate::Property;
|
use crate::{Property, SharedVector};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::cell::{Cell, RefCell};
|
use core::cell::{Cell, RefCell};
|
||||||
|
@ -369,6 +369,59 @@ impl<T: Clone + 'static> Model for VecModel<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A model backed by a `SharedVector<T>`
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SharedVectorModel<T> {
|
||||||
|
array: RefCell<SharedVector<T>>,
|
||||||
|
notify: ModelNotify,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + 'static> SharedVectorModel<T> {
|
||||||
|
/// Add a row at the end of the model
|
||||||
|
pub fn push(&self, value: T) {
|
||||||
|
self.array.borrow_mut().push(value);
|
||||||
|
self.notify.row_added(self.array.borrow().len() - 1, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> SharedVectorModel<T> {
|
||||||
|
/// Returns a clone of the model's backing shared vector.
|
||||||
|
pub fn shared_vector(&self) -> SharedVector<T> {
|
||||||
|
self.array.borrow_mut().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<SharedVector<T>> for SharedVectorModel<T> {
|
||||||
|
fn from(array: SharedVector<T>) -> Self {
|
||||||
|
SharedVectorModel { array: RefCell::new(array), notify: Default::default() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + 'static> Model for SharedVectorModel<T> {
|
||||||
|
type Data = T;
|
||||||
|
|
||||||
|
fn row_count(&self) -> usize {
|
||||||
|
self.array.borrow().len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn row_data(&self, row: usize) -> Option<Self::Data> {
|
||||||
|
self.array.borrow().get(row).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_row_data(&self, row: usize, data: Self::Data) {
|
||||||
|
self.array.borrow_mut().make_mut_slice()[row] = data;
|
||||||
|
self.notify.row_changed(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn model_tracker(&self) -> &dyn ModelTracker {
|
||||||
|
&self.notify
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn core::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Model for usize {
|
impl Model for usize {
|
||||||
type Data = i32;
|
type Data = i32;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use sixtyfps_compilerlib::langtype::Type as LangType;
|
use sixtyfps_compilerlib::langtype::Type as LangType;
|
||||||
use sixtyfps_corelib::graphics::Image;
|
use sixtyfps_corelib::graphics::Image;
|
||||||
|
use sixtyfps_corelib::model::SharedVectorModel;
|
||||||
use sixtyfps_corelib::{Brush, PathData, SharedString, SharedVector};
|
use sixtyfps_corelib::{Brush, PathData, SharedString, SharedVector};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -123,7 +124,17 @@ impl Value {
|
||||||
Value::String(_) => ValueType::String,
|
Value::String(_) => ValueType::String,
|
||||||
Value::Bool(_) => ValueType::Bool,
|
Value::Bool(_) => ValueType::Bool,
|
||||||
Value::Array(_) => ValueType::Array,
|
Value::Array(_) => ValueType::Array,
|
||||||
Value::Model(_) => ValueType::Model,
|
Value::Model(model) => {
|
||||||
|
if model
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<sixtyfps_corelib::model::SharedVectorModel<Value>>()
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
ValueType::Array
|
||||||
|
} else {
|
||||||
|
ValueType::Model
|
||||||
|
}
|
||||||
|
}
|
||||||
Value::Struct(_) => ValueType::Struct,
|
Value::Struct(_) => ValueType::Struct,
|
||||||
Value::Brush(_) => ValueType::Brush,
|
Value::Brush(_) => ValueType::Brush,
|
||||||
Value::Image(_) => ValueType::Image,
|
Value::Image(_) => ValueType::Image,
|
||||||
|
@ -146,8 +157,34 @@ impl PartialEq for Value {
|
||||||
Value::String(lhs) => matches!(other, Value::String(rhs) if lhs == rhs),
|
Value::String(lhs) => matches!(other, Value::String(rhs) if lhs == rhs),
|
||||||
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) => {
|
||||||
Value::Model(lhs) => matches!(other, Value::Model(rhs) if Rc::ptr_eq(lhs, rhs)),
|
match other {
|
||||||
|
Value::Array(rhs) => return lhs == rhs,
|
||||||
|
Value::Model(model) => {
|
||||||
|
if let Some(rhs_array) =
|
||||||
|
model.as_any().downcast_ref::<SharedVectorModel<Value>>()
|
||||||
|
{
|
||||||
|
return lhs == &rhs_array.shared_vector();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Value::Model(lhs) => {
|
||||||
|
match other {
|
||||||
|
Value::Model(rhs) => return Rc::ptr_eq(lhs, rhs),
|
||||||
|
Value::Array(rhs_array) => {
|
||||||
|
if let Some(lhs_array) =
|
||||||
|
lhs.as_any().downcast_ref::<SharedVectorModel<Value>>()
|
||||||
|
{
|
||||||
|
return &lhs_array.shared_vector() == rhs_array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
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::PathData(lhs) => matches!(other, Value::PathData(rhs) if lhs == rhs),
|
Value::PathData(lhs) => matches!(other, Value::PathData(rhs) if lhs == rhs),
|
||||||
|
|
|
@ -573,8 +573,8 @@ pub fn eval_expression(expression: &Expression, local_context: &mut EvalLocalCon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Array { values, .. } => Value::Model(
|
Expression::Array { values, .. } => Value::Model(
|
||||||
Rc::new(corelib::model::VecModel::from(
|
Rc::new(corelib::model::SharedVectorModel::from(
|
||||||
values.iter().map(|e| eval_expression(e, local_context)).collect::<Vec<_>>()
|
values.iter().map(|e| eval_expression(e, local_context)).collect::<SharedVector<_>>()
|
||||||
)) as Rc<dyn corelib::model::Model<Data = Value>>
|
)) as Rc<dyn corelib::model::Model<Data = Value>>
|
||||||
),
|
),
|
||||||
Expression::Struct { values, .. } => Value::Struct(
|
Expression::Struct { values, .. } => Value::Struct(
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
use crate::dynamic_component::ErasedComponentBox;
|
use crate::dynamic_component::ErasedComponentBox;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use sixtyfps_corelib::model::{Model, ModelNotify};
|
use sixtyfps_corelib::model::{Model, ModelNotify, SharedVectorModel};
|
||||||
use sixtyfps_corelib::slice::Slice;
|
use sixtyfps_corelib::slice::Slice;
|
||||||
use sixtyfps_corelib::window::{WindowHandleAccess, WindowRc};
|
use sixtyfps_corelib::window::{WindowHandleAccess, WindowRc};
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
|
@ -155,16 +155,42 @@ pub extern "C" fn sixtyfps_interpreter_value_to_bool(val: &ValueOpaque) -> Optio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts a SharedVector<ValueOpaque> out of the given value `val`, writes that into the
|
||||||
|
/// `out` parameter and returns true; returns false if the value does not hold an extractable
|
||||||
|
/// array.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn sixtyfps_interpreter_value_to_array(
|
pub extern "C" fn sixtyfps_interpreter_value_to_array(
|
||||||
val: &ValueOpaque,
|
val: &ValueOpaque,
|
||||||
) -> Option<&SharedVector<ValueOpaque>> {
|
out: *mut SharedVector<ValueOpaque>,
|
||||||
|
) -> bool {
|
||||||
match val.as_value() {
|
match val.as_value() {
|
||||||
Value::Array(v) => Some(unsafe {
|
Value::Array(v) => unsafe {
|
||||||
// Safety: We assert that Value and ValueOpaque have the same size and alignment
|
// Safety: We assert that Value and ValueOpaque have the same size and alignment
|
||||||
std::mem::transmute::<&SharedVector<Value>, &SharedVector<ValueOpaque>>(v)
|
std::ptr::write(
|
||||||
}),
|
out,
|
||||||
_ => None,
|
std::mem::transmute::<&SharedVector<Value>, &SharedVector<ValueOpaque>>(v).clone(),
|
||||||
|
);
|
||||||
|
true
|
||||||
|
},
|
||||||
|
Value::Model(m) => {
|
||||||
|
if let Some(model) = m.as_any().downcast_ref::<SharedVectorModel<Value>>() {
|
||||||
|
let vec = model.shared_vector();
|
||||||
|
// Safety: We assert that Value and ValueOpaque have the same size and alignment
|
||||||
|
unsafe {
|
||||||
|
std::ptr::write(
|
||||||
|
out,
|
||||||
|
std::mem::transmute::<&SharedVector<Value>, &SharedVector<ValueOpaque>>(
|
||||||
|
&vec,
|
||||||
|
)
|
||||||
|
.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue