Begin passing the VRC<ComponentVTable, Dyn> into the run-time library

First by changing the signature of run() and by adding a self_weak
to the C++ struct.
This commit is contained in:
Simon Hausmann 2020-11-11 17:47:18 +01:00
parent a9791c390d
commit 5d744c86c2
11 changed files with 97 additions and 56 deletions

View file

@ -72,8 +72,9 @@ using cbindgen_private::TraversalOrder;
namespace private_api { namespace private_api {
using ItemTreeNode = cbindgen_private::ItemTreeNode<uint8_t>; using ItemTreeNode = cbindgen_private::ItemTreeNode<uint8_t>;
struct ComponentWindow class ComponentWindow
{ {
public:
ComponentWindow() { cbindgen_private::sixtyfps_component_window_init(&inner); } ComponentWindow() { cbindgen_private::sixtyfps_component_window_init(&inner); }
~ComponentWindow() { cbindgen_private::sixtyfps_component_window_drop(&inner); } ~ComponentWindow() { cbindgen_private::sixtyfps_component_window_drop(&inner); }
ComponentWindow(const ComponentWindow &) = delete; ComponentWindow(const ComponentWindow &) = delete;
@ -83,8 +84,9 @@ struct ComponentWindow
template<typename Component> template<typename Component>
void run(const Component *c) const void run(const Component *c) const
{ {
sixtyfps_component_window_run( auto self_rc = c->self_weak.lock().value();
&inner, vtable::VRefMut<ComponentVTable> { &Component::component_type, const_cast<Component *>(c) }); sixtyfps_component_window_run(&inner,
reinterpret_cast<cbindgen_private::ComponentRc *>(&self_rc));
} }
float scale_factor() const { return sixtyfps_component_window_get_scale_factor(&inner); } float scale_factor() const { return sixtyfps_component_window_get_scale_factor(&inner); }
@ -129,6 +131,7 @@ using cbindgen_private::Window;
using cbindgen_private::NativeButton; using cbindgen_private::NativeButton;
using cbindgen_private::NativeCheckBox; using cbindgen_private::NativeCheckBox;
using cbindgen_private::NativeComboBox;
using cbindgen_private::NativeGroupBox; using cbindgen_private::NativeGroupBox;
using cbindgen_private::NativeLineEdit; using cbindgen_private::NativeLineEdit;
using cbindgen_private::NativeScrollView; using cbindgen_private::NativeScrollView;
@ -136,7 +139,6 @@ using cbindgen_private::NativeSlider;
using cbindgen_private::NativeSpinBox; using cbindgen_private::NativeSpinBox;
using cbindgen_private::NativeStandardListViewItem; using cbindgen_private::NativeStandardListViewItem;
using cbindgen_private::NativeStyleMetrics; using cbindgen_private::NativeStyleMetrics;
using cbindgen_private::NativeComboBox;
namespace private_api { namespace private_api {
constexpr inline ItemTreeNode make_item_node(std::uintptr_t offset, constexpr inline ItemTreeNode make_item_node(std::uintptr_t offset,
@ -153,9 +155,10 @@ constexpr inline ItemTreeNode make_dyn_node(std::uintptr_t offset)
offset } }; offset } };
} }
inline ItemRef get_item_ref(ComponentRef component, Slice<ItemTreeNode> item_tree, int index) { inline ItemRef get_item_ref(ComponentRef component, Slice<ItemTreeNode> item_tree, int index)
{
const auto &item = item_tree.ptr[index].item.item; const auto &item = item_tree.ptr[index].item.item;
return ItemRef { item.vtable, reinterpret_cast<char*>(component.instance) + item.offset }; return ItemRef { item.vtable, reinterpret_cast<char *>(component.instance) + item.offset };
} }
} }
@ -276,50 +279,55 @@ inline FocusEventResult process_focus_event(ComponentRef component, int64_t &foc
return FocusEventResult::FocusItemNotFound; return FocusEventResult::FocusItemNotFound;
} }
void dealloc(const ComponentVTable*, uint8_t *ptr, vtable::Layout layout) { void dealloc(const ComponentVTable *, uint8_t *ptr, vtable::Layout layout)
{
#ifdef __cpp_sized_deallocation #ifdef __cpp_sized_deallocation
::operator delete(reinterpret_cast<void*>(ptr), layout.size, static_cast<std::align_val_t>(layout.align)); ::operator delete(reinterpret_cast<void *>(ptr), layout.size,
static_cast<std::align_val_t>(layout.align));
#else #else
::operator delete(reinterpret_cast<void*>(ptr), static_cast<std::align_val_t>(layout.align)); ::operator delete(reinterpret_cast<void *>(ptr), static_cast<std::align_val_t>(layout.align));
#endif #endif
} }
template<typename T> vtable::Layout drop_in_place(ComponentRef component) { template<typename T>
reinterpret_cast<T*>(component.instance)->~T(); vtable::Layout drop_in_place(ComponentRef component)
{
reinterpret_cast<T *>(component.instance)->~T();
return vtable::Layout { sizeof(T), alignof(T) }; return vtable::Layout { sizeof(T), alignof(T) };
} }
} // namespace private_api } // namespace private_api
template<typename T> class ComponentWeakHandle; template<typename T>
class ComponentWeakHandle;
/// The component handle is like a shared pointer to a component in the generated code. /// The component handle is like a shared pointer to a component in the generated code.
/// In order to get a component, use `T::create()` where T is the name of the component /// In order to get a component, use `T::create()` where T is the name of the component
/// in the .60 file. This give you a `ComponentHandle<T>` /// in the .60 file. This give you a `ComponentHandle<T>`
template<typename T> template<typename T>
class ComponentHandle { class ComponentHandle
{
vtable::VRc<private_api::ComponentVTable, T> inner; vtable::VRc<private_api::ComponentVTable, T> inner;
friend class ComponentWeakHandle<T>; friend class ComponentWeakHandle<T>;
public: public:
/// internal constructor /// internal constructor
ComponentHandle(const vtable::VRc<private_api::ComponentVTable, T> &inner) : inner(inner) { } ComponentHandle(const vtable::VRc<private_api::ComponentVTable, T> &inner) : inner(inner) { }
const T* operator->() const { const T *operator->() const { return inner.operator->(); }
return inner.operator->(); const T &operator*() const { return inner.operator*(); }
}
const T& operator*() const {
return inner.operator*();
}
}; };
/// A weak reference to the component. Can be constructed from a `ComponentHandle<T>` /// A weak reference to the component. Can be constructed from a `ComponentHandle<T>`
template<typename T> template<typename T>
class ComponentWeakHandle { class ComponentWeakHandle
{
vtable::VWeak<private_api::ComponentVTable, T> inner; vtable::VWeak<private_api::ComponentVTable, T> inner;
public: public:
ComponentWeakHandle() = default; ComponentWeakHandle() = default;
ComponentWeakHandle(const ComponentHandle<T>&other) : inner(other.inner) {} ComponentWeakHandle(const ComponentHandle<T> &other) : inner(other.inner) { }
std::optional<ComponentHandle<T>> lock() const { std::optional<ComponentHandle<T>> lock() const
{
if (auto l = inner.lock()) { if (auto l = inner.lock()) {
return { ComponentHandle(*l) }; return { ComponentHandle(*l) };
} else { } else {
@ -329,32 +337,31 @@ public:
}; };
// layouts: // layouts:
using cbindgen_private::box_layout_info;
using cbindgen_private::BoxLayoutCellData;
using cbindgen_private::BoxLayoutData;
using cbindgen_private::grid_layout_info; using cbindgen_private::grid_layout_info;
using cbindgen_private::GridLayoutCellData; using cbindgen_private::GridLayoutCellData;
using cbindgen_private::GridLayoutData; using cbindgen_private::GridLayoutData;
using cbindgen_private::BoxLayoutData; using cbindgen_private::LayoutAlignment;
using cbindgen_private::BoxLayoutCellData;
using cbindgen_private::LayoutInfo; using cbindgen_private::LayoutInfo;
using cbindgen_private::Padding; using cbindgen_private::Padding;
using cbindgen_private::PathLayoutData; using cbindgen_private::PathLayoutData;
using cbindgen_private::PathLayoutItemData; using cbindgen_private::PathLayoutItemData;
using cbindgen_private::solve_grid_layout;
using cbindgen_private::solve_box_layout;
using cbindgen_private::box_layout_info;
using cbindgen_private::solve_path_layout;
using cbindgen_private::Rect; using cbindgen_private::Rect;
using cbindgen_private::LayoutAlignment; using cbindgen_private::solve_box_layout;
using cbindgen_private::solve_grid_layout;
using cbindgen_private::solve_path_layout;
inline LayoutInfo LayoutInfo::merge(const LayoutInfo &other) const { inline LayoutInfo LayoutInfo::merge(const LayoutInfo &other) const
{
// Note: This "logic" is duplicated from LayoutInfo::merge in layout.rs. // Note: This "logic" is duplicated from LayoutInfo::merge in layout.rs.
return LayoutInfo { return LayoutInfo { std::max(min_width, other.min_width),
std::max(min_width, other.min_width),
std::min(max_width, other.max_width), std::min(max_width, other.max_width),
std::max(min_height, other.min_height), std::max(min_height, other.min_height),
std::min(max_height, other.max_height), std::min(max_height, other.max_height),
std::min(horizontal_stretch, other.horizontal_stretch), std::min(horizontal_stretch, other.horizontal_stretch),
std::min(vertical_stretch, other.vertical_stretch) std::min(vertical_stretch, other.vertical_stretch) };
};
} }
// models // models
@ -591,7 +598,7 @@ public:
vtable::VRef<private_api::ComponentVTable> item_at(int i) const vtable::VRef<private_api::ComponentVTable> item_at(int i) const
{ {
const auto &x = inner->data.at(i); const auto &x = inner->data.at(i);
return { &C::component_type, const_cast<C*>(&(**x.ptr)) }; return { &C::component_type, const_cast<C *>(&(**x.ptr)) };
} }
void compute_layout(cbindgen_private::Rect parent_rect) const void compute_layout(cbindgen_private::Rect parent_rect) const
@ -599,7 +606,8 @@ public:
if (!inner) if (!inner)
return; return;
for (auto &x : inner->data) { for (auto &x : inner->data) {
(*x.ptr)->apply_layout({ &C::component_type, const_cast<C*>(&(**x.ptr)) }, parent_rect); (*x.ptr)->apply_layout({ &C::component_type, const_cast<C *>(&(**x.ptr)) },
parent_rect);
} }
} }
@ -641,17 +649,21 @@ Flickable::~Flickable()
sixtyfps_flickable_data_free(&data); sixtyfps_flickable_data_free(&data);
} }
NativeStyleMetrics::NativeStyleMetrics() { NativeStyleMetrics::NativeStyleMetrics()
{
sixtyfps_init_native_style_metrics(this); sixtyfps_init_native_style_metrics(this);
} }
using cbindgen_private::StandardListViewItem; using cbindgen_private::StandardListViewItem;
namespace cbindgen_private { namespace cbindgen_private {
bool operator==(const StandardListViewItem &a, const StandardListViewItem &b) { bool operator==(const StandardListViewItem &a, const StandardListViewItem &b)
static_assert(sizeof(StandardListViewItem) == sizeof(std::tuple<SharedString>), "must update to cover all fields"); {
static_assert(sizeof(StandardListViewItem) == sizeof(std::tuple<SharedString>),
"must update to cover all fields");
return a.text == b.text; return a.text == b.text;
} }
bool operator!=(const StandardListViewItem &a, const StandardListViewItem &b) { bool operator!=(const StandardListViewItem &a, const StandardListViewItem &b)
{
return !(a == b); return !(a == b);
} }
} }

View file

@ -329,7 +329,7 @@ declare_types! {
let component = cx.borrow(&mut this, |x| x.0.clone()); let component = cx.borrow(&mut this, |x| x.0.clone());
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?; let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
run_scoped(&mut cx,this.downcast().unwrap(), || { run_scoped(&mut cx,this.downcast().unwrap(), || {
component.window().run(component.borrow()); component.window().run(&vtable::VRc::into_dyn(component));
Ok(()) Ok(())
})?; })?;
Ok(JsUndefined::new().as_value(&mut cx)) Ok(JsUndefined::new().as_value(&mut cx))

View file

@ -19,6 +19,7 @@ wasm-bindgen-futures = { version = "0.4.18" }
js-sys = "0.3.44" js-sys = "0.3.44"
console_error_panic_hook = { version = "0.1.6", optional = true } console_error_panic_hook = { version = "0.1.6", optional = true }
wee_alloc = { version = "0.4.5", optional = true } wee_alloc = { version = "0.4.5", optional = true }
vtable = { version = "0.1.1", path="../../helper_crates/vtable" }
#[dev-dependencies] #[dev-dependencies]
#wasm-bindgen-test = "0.3.13" #wasm-bindgen-test = "0.3.13"

View file

@ -127,6 +127,6 @@ impl WrappedCompiledComp {
#[wasm_bindgen] #[wasm_bindgen]
pub fn run(&self, canvas_id: String) { pub fn run(&self, canvas_id: String) {
let component = self.0.clone().create(canvas_id); let component = self.0.clone().create(canvas_id);
component.window().run(component.borrow()); component.window().run(&vtable::VRc::into_dyn(component));
} }
} }

View file

@ -830,6 +830,18 @@ fn generate_component(
}), }),
)); ));
component_struct.members.push((
Access::Private,
Declaration::Var(Var {
ty: format!(
"vtable::VWeak<sixtyfps::private_api::ComponentVTable, {}>",
component_id
),
name: "self_weak".into(),
..Var::default()
}),
));
component_struct.members.push(( component_struct.members.push((
Access::Public, Access::Public,
Declaration::Function(Function { Declaration::Function(Function {
@ -845,13 +857,18 @@ fn generate_component(
window = window_ref_expression(component) window = window_ref_expression(component)
)); ));
component_struct.friends.push("sixtyfps::private_api::ComponentWindow".into());
component_struct.members.push(( component_struct.members.push((
Access::Public, Access::Public,
Declaration::Function(Function { Declaration::Function(Function {
name: "create".into(), name: "create".into(),
signature: format!("() -> sixtyfps::ComponentHandle<{}>", component_id), signature: format!("() -> sixtyfps::ComponentHandle<{}>", component_id),
statements: Some(vec![format!( statements: Some(vec![
"return sixtyfps::ComponentHandle<{0}>{{ vtable::VRc<sixtyfps::private_api::ComponentVTable, {0}>::make() }};", format!("auto self_rc = vtable::VRc<sixtyfps::private_api::ComponentVTable, {0}>::make();", component_id),
format!("const_cast<{0} *>(&*self_rc)->self_weak = vtable::VWeak(self_rc);", component_id),
format!(
"return sixtyfps::ComponentHandle<{0}>{{ self_rc }};",
component_id, component_id,
)]), )]),
is_static: true, is_static: true,

View file

@ -583,7 +583,7 @@ fn generate_component(
impl sixtyfps::Component for #component_id { impl sixtyfps::Component for #component_id {
fn run(self: ::core::pin::Pin<&Self>) { fn run(self: ::core::pin::Pin<&Self>) {
use sixtyfps::re_exports::*; use sixtyfps::re_exports::*;
self.as_ref().window.run(VRef::new_pin(self.as_ref())); self.as_ref().window.run(&VRc::into_dyn(self.as_ref().self_weak.get().unwrap().upgrade().unwrap()));
} }
} }
)) ))

View file

@ -79,9 +79,12 @@ pub struct ComponentVTable {
/// the associated vtable /// the associated vtable
pub type ComponentRef<'a> = vtable::VRef<'a, ComponentVTable>; pub type ComponentRef<'a> = vtable::VRef<'a, ComponentVTable>;
/// Type alias to the commonly use `Pin<VRef<ComponentVTable>>>` /// Type alias to the commonly used `Pin<VRef<ComponentVTable>>>`
pub type ComponentRefPin<'a> = core::pin::Pin<ComponentRef<'a>>; pub type ComponentRefPin<'a> = core::pin::Pin<ComponentRef<'a>>;
/// Type alias to the commonly used VRc<ComponentVTable, Dyn>>
pub type ComponentRc = vtable::VRc<ComponentVTable, Dyn>;
/// Call init() on the ItemVTable for each item of the component. /// Call init() on the ItemVTable for each item of the component.
pub fn init_component_items<Base>( pub fn init_component_items<Base>(
base: core::pin::Pin<&Base>, base: core::pin::Pin<&Base>,

View file

@ -13,7 +13,7 @@ LICENSE END */
[GenericWindow] trait used by the generated code and the run-time to change [GenericWindow] trait used by the generated code and the run-time to change
aspects of windows on the screen. aspects of windows on the screen.
*/ */
use crate::component::ComponentVTable; use crate::component::{ComponentRc, ComponentVTable};
use std::cell::RefCell; use std::cell::RefCell;
use std::{ use std::{
convert::TryInto, convert::TryInto,
@ -143,9 +143,11 @@ impl ComponentWindow {
Self(window_impl) Self(window_impl)
} }
/// Spins an event loop and renders the items of the provided component in this window. /// Spins an event loop and renders the items of the provided component in this window.
pub fn run(&self, component: Pin<VRef<ComponentVTable>>) { pub fn run(&self, component: &ComponentRc) {
let event_loop = crate::eventloop::EventLoop::new(); let event_loop = crate::eventloop::EventLoop::new();
let component = ComponentRc::borrow_pin(component);
self.0.clone().map_window(&event_loop, component); self.0.clone().map_window(&event_loop, component);
event_loop.run(component); event_loop.run(component);
@ -583,7 +585,7 @@ pub mod ffi {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sixtyfps_component_window_run( pub unsafe extern "C" fn sixtyfps_component_window_run(
handle: *const ComponentWindowOpaque, handle: *const ComponentWindowOpaque,
component: Pin<VRef<ComponentVTable>>, component: &ComponentRc,
) { ) {
let window = &*(handle as *const ComponentWindow); let window = &*(handle as *const ComponentWindow);
window.run(component); window.run(component);

View file

@ -68,6 +68,12 @@ impl<'id> ComponentBox<'id> {
.unwrap() .unwrap()
.clone() .clone()
} }
pub fn run(self) {
let rc_box = vtable::VRc::new(ErasedComponentBox::from(self));
let window = rc_box.0.window();
window.run(&vtable::VRc::into_dyn(rc_box));
}
} }
impl<'id> Drop for ComponentBox<'id> { impl<'id> Drop for ComponentBox<'id> {

View file

@ -217,7 +217,7 @@ fn gen_corelib(include_dir: &Path) -> anyhow::Result<()> {
.with_after_include(format!( .with_after_include(format!(
r" r"
namespace sixtyfps {{ namespace sixtyfps {{
namespace private_api {{ enum class VersionCheck {{ Major = {}, Minor = {}, Patch = {} }}; struct ComponentWindow; }} namespace private_api {{ enum class VersionCheck {{ Major = {}, Minor = {}, Patch = {} }}; class ComponentWindow; }}
namespace cbindgen_private {{ using sixtyfps::private_api::ComponentWindow; using namespace vtable; }} namespace cbindgen_private {{ using sixtyfps::private_api::ComponentWindow; using namespace vtable; }}
}}", }}",
0, 0, 2, 0, 0, 2,

View file

@ -44,6 +44,6 @@ fn main() -> std::io::Result<()> {
}; };
let component = c.create(); let component = c.create();
component.window().run(component.borrow()); component.window().run(&vtable::VRc::into_dyn(component));
Ok(()) Ok(())
} }