ComponentDefinition::create in C++

Note thate there is a hack so `ComponentHandle<ComponentInstance>` (which is
binary compatible with `VRc<ComponentVTable, ErasedComponentBox>` works
This commit is contained in:
Olivier Goffart 2021-03-19 18:06:51 +01:00
parent 3ad41a551b
commit f2ffc0ebf6
2 changed files with 85 additions and 19 deletions

View file

@ -15,6 +15,15 @@ LICENSE END */
#include <optional> #include <optional>
namespace sixtyfps::cbindgen_private {
// This has to stay opaque, but VRc don't compile if it is just forward declared
struct ErasedComponentBox : vtable::Dyn {
~ErasedComponentBox() = delete;
ErasedComponentBox() = delete;
ErasedComponentBox(ErasedComponentBox&) = delete;
};
}
namespace sixtyfps::interpreter { namespace sixtyfps::interpreter {
class Value; class Value;
@ -349,21 +358,25 @@ inline void Struct::set_field(std::string_view name, const Value &value)
cbindgen_private::sixtyfps_interpreter_struct_set_field(&inner, name_view, &value.inner); cbindgen_private::sixtyfps_interpreter_struct_set_field(&inner, name_view, &value.inner);
} }
class ComponentInstance class ComponentInstance : vtable::Dyn
{ {
cbindgen_private::ComponentInstance inner;
ComponentInstance() = delete; ComponentInstance() = delete;
ComponentInstance(ComponentInstance &) = delete; ComponentInstance(ComponentInstance &) = delete;
ComponentInstance &operator=(ComponentInstance &) = delete; ComponentInstance &operator=(ComponentInstance &) = delete;
friend class ComponentDefinition;
// ComponentHandle<ComponentInstance> is in fact a VRc<ComponentVTable, ErasedComponentBox>
const cbindgen_private::ErasedComponentBox *inner() const
{ return reinterpret_cast<const cbindgen_private::ErasedComponentBox *>(this); }
public: public:
void show() const void show() const
{ {
cbindgen_private::sixtyfps_interpreter_component_instance_show(&inner, true); cbindgen_private::sixtyfps_interpreter_component_instance_show(inner(), true);
} }
void hide() const void hide() const
{ {
cbindgen_private::sixtyfps_interpreter_component_instance_show(&inner, false); cbindgen_private::sixtyfps_interpreter_component_instance_show(inner(), false);
} }
void run() const void run() const
{ {
@ -376,14 +389,14 @@ public:
{ {
using namespace cbindgen_private; using namespace cbindgen_private;
return sixtyfps_interpreter_component_instance_set_property( return sixtyfps_interpreter_component_instance_set_property(
&inner, sixtyfps::private_api::string_to_slice(name), &value.inner); inner(), sixtyfps::private_api::string_to_slice(name), &value.inner);
} }
std::optional<Value> get_property(std::string_view name) const std::optional<Value> get_property(std::string_view name) const
{ {
using namespace cbindgen_private; using namespace cbindgen_private;
ValueOpaque out; ValueOpaque out;
if (sixtyfps_interpreter_component_instance_get_property( if (sixtyfps_interpreter_component_instance_get_property(
&inner, sixtyfps::private_api::string_to_slice(name), &out)) { inner(), sixtyfps::private_api::string_to_slice(name), &out)) {
return Value(out); return Value(out);
} else { } else {
return {}; return {};
@ -396,7 +409,7 @@ public:
Slice<ValueOpaque> args_view { reinterpret_cast<ValueOpaque *>(args.ptr), args.len }; Slice<ValueOpaque> args_view { reinterpret_cast<ValueOpaque *>(args.ptr), args.len };
ValueOpaque out; ValueOpaque out;
if (sixtyfps_interpreter_component_instance_invoke_callback( if (sixtyfps_interpreter_component_instance_invoke_callback(
&inner, sixtyfps::private_api::string_to_slice(name), args_view, &out)) { inner(), sixtyfps::private_api::string_to_slice(name), args_view, &out)) {
return Value(out); return Value(out);
} else { } else {
return {}; return {};
@ -413,7 +426,7 @@ public:
new (ret) Value(std::move(r)); new (ret) Value(std::move(r));
}; };
return cbindgen_private::sixtyfps_interpreter_component_instance_set_callback( return cbindgen_private::sixtyfps_interpreter_component_instance_set_callback(
&inner, sixtyfps::private_api::string_to_slice(name), actual_cb, inner(), sixtyfps::private_api::string_to_slice(name), actual_cb,
new F(std::move(callback)), [](void *data) { delete reinterpret_cast<F *>(data); }); new F(std::move(callback)), [](void *data) { delete reinterpret_cast<F *>(data); });
} }
}; };
@ -447,6 +460,19 @@ public:
return *this; return *this;
} }
~ComponentDefinition() { sixtyfps_interpreter_component_definition_destructor(&inner); } ~ComponentDefinition() { sixtyfps_interpreter_component_definition_destructor(&inner); }
}
ComponentHandle<ComponentInstance> create() const {
union CI {
cbindgen_private::ComponentInstance i;
~CI() {
i.~ComponentInstance();
}
CI() {}
} u;
cbindgen_private::sixtyfps_interpreter_component_instance_create(&inner, &u.i);
return *reinterpret_cast<ComponentHandle<ComponentInstance> *>(&u.i);
}; };
class ComponentCompiler class ComponentCompiler

View file

@ -765,6 +765,8 @@ pub mod testing {
#[cfg(feature = "ffi")] #[cfg(feature = "ffi")]
#[allow(missing_docs)] #[allow(missing_docs)]
pub(crate) mod ffi { pub(crate) mod ffi {
use crate::dynamic_component::ErasedComponentBox;
use super::*; use super::*;
use sixtyfps_corelib::model::{Model, ModelNotify, ModelPeer}; use sixtyfps_corelib::model::{Model, ModelNotify, ModelPeer};
use sixtyfps_corelib::slice::Slice; use sixtyfps_corelib::slice::Slice;
@ -1073,11 +1075,13 @@ pub(crate) mod ffi {
/// to the resulting value. If this function returns false, out is unchanged /// to the resulting value. If this function returns false, out is unchanged
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_get_property( pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_get_property(
inst: &ComponentInstance, inst: &ErasedComponentBox,
name: Slice<u8>, name: Slice<u8>,
out: *mut ValueOpaque, out: *mut ValueOpaque,
) -> bool { ) -> bool {
match inst.get_property(std::str::from_utf8(&name).unwrap()) { generativity::make_guard!(guard);
let comp = inst.unerase(guard);
match comp.description().get_property(comp.borrow(), std::str::from_utf8(&name).unwrap()) {
Ok(val) => { Ok(val) => {
std::ptr::write(out as *mut Value, val); std::ptr::write(out as *mut Value, val);
true true
@ -1088,11 +1092,19 @@ pub(crate) mod ffi {
#[no_mangle] #[no_mangle]
pub extern "C" fn sixtyfps_interpreter_component_instance_set_property( pub extern "C" fn sixtyfps_interpreter_component_instance_set_property(
inst: &ComponentInstance, inst: &ErasedComponentBox,
name: Slice<u8>, name: Slice<u8>,
val: &ValueOpaque, val: &ValueOpaque,
) -> bool { ) -> bool {
inst.set_property(std::str::from_utf8(&name).unwrap(), val.as_value().clone()).is_ok() generativity::make_guard!(guard);
let comp = inst.unerase(guard);
comp.description()
.set_property(
comp.borrow(),
std::str::from_utf8(&name).unwrap(),
val.as_value().clone(),
)
.is_ok()
} }
/// Invoke a callback. /// Invoke a callback.
@ -1100,13 +1112,19 @@ pub(crate) mod ffi {
/// to the resulting value. If this function returns false, out is unchanged /// to the resulting value. If this function returns false, out is unchanged
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_invoke_callback( pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_invoke_callback(
inst: &ComponentInstance, inst: &ErasedComponentBox,
name: Slice<u8>, name: Slice<u8>,
args: Slice<ValueOpaque>, args: Slice<ValueOpaque>,
out: *mut ValueOpaque, out: *mut ValueOpaque,
) -> bool { ) -> bool {
let args = std::mem::transmute::<Slice<ValueOpaque>, Slice<Value>>(args); let args = std::mem::transmute::<Slice<ValueOpaque>, Slice<Value>>(args);
match inst.invoke_callback(std::str::from_utf8(&name).unwrap(), args.as_slice()) { generativity::make_guard!(guard);
let comp = inst.unerase(guard);
match comp.description().invoke_callback(
comp.borrow(),
std::str::from_utf8(&name).unwrap(),
args.as_slice(),
) {
Ok(val) => { Ok(val) => {
std::ptr::write(out as *mut Value, val); std::ptr::write(out as *mut Value, val);
true true
@ -1119,7 +1137,7 @@ pub(crate) mod ffi {
/// The `callback` function must initialize the `ret` (the `ret` passed to the callback is initialized and is assumed initialized after the function) /// The `callback` function must initialize the `ret` (the `ret` passed to the callback is initialized and is assumed initialized after the function)
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_set_callback( pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_set_callback(
inst: &ComponentInstance, inst: &ErasedComponentBox,
name: Slice<u8>, name: Slice<u8>,
callback: extern "C" fn( callback: extern "C" fn(
user_data: *mut c_void, user_data: *mut c_void,
@ -1150,22 +1168,44 @@ pub(crate) mod ffi {
ret.assume_init() ret.assume_init()
}; };
inst.set_callback(std::str::from_utf8(&name).unwrap(), callback).is_ok() generativity::make_guard!(guard);
let comp = inst.unerase(guard);
comp.description()
.set_callback_handler(
comp.borrow(),
std::str::from_utf8(&name).unwrap(),
Box::new(callback),
)
.is_ok()
} }
/// Show or hide /// Show or hide
#[no_mangle] #[no_mangle]
pub extern "C" fn sixtyfps_interpreter_component_instance_show( pub extern "C" fn sixtyfps_interpreter_component_instance_show(
inst: &ComponentInstance, inst: &ErasedComponentBox,
is_visible: bool, is_visible: bool,
) { ) {
generativity::make_guard!(guard);
let comp = inst.unerase(guard);
if is_visible { if is_visible {
inst.show(); comp.window().show();
} else { } else {
inst.hide(); comp.window().hide();
} }
} }
/// Instantiate an instance from a definition.
///
/// The `out` must be uninitialized and is going to be initialized after the call
/// and need to be destroyed with sixtyfps_interpreter_component_instance_destructor
#[no_mangle]
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_create(
def: &ComponentDefinitionOpaque,
out: *mut ComponentInstance,
) {
std::ptr::write(out, def.as_component_definition().create())
}
#[vtable::vtable] #[vtable::vtable]
#[repr(C)] #[repr(C)]
pub struct ModelAdaptorVTable { pub struct ModelAdaptorVTable {