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>
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 {
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);
}
class ComponentInstance
class ComponentInstance : vtable::Dyn
{
cbindgen_private::ComponentInstance inner;
ComponentInstance() = delete;
ComponentInstance(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:
void show() const
{
cbindgen_private::sixtyfps_interpreter_component_instance_show(&inner, true);
cbindgen_private::sixtyfps_interpreter_component_instance_show(inner(), true);
}
void hide() const
{
cbindgen_private::sixtyfps_interpreter_component_instance_show(&inner, false);
cbindgen_private::sixtyfps_interpreter_component_instance_show(inner(), false);
}
void run() const
{
@ -376,14 +389,14 @@ public:
{
using namespace cbindgen_private;
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
{
using namespace cbindgen_private;
ValueOpaque out;
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);
} else {
return {};
@ -396,7 +409,7 @@ public:
Slice<ValueOpaque> args_view { reinterpret_cast<ValueOpaque *>(args.ptr), args.len };
ValueOpaque out;
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);
} else {
return {};
@ -413,7 +426,7 @@ public:
new (ret) Value(std::move(r));
};
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); });
}
};
@ -447,6 +460,19 @@ public:
return *this;
}
~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

View file

@ -765,6 +765,8 @@ pub mod testing {
#[cfg(feature = "ffi")]
#[allow(missing_docs)]
pub(crate) mod ffi {
use crate::dynamic_component::ErasedComponentBox;
use super::*;
use sixtyfps_corelib::model::{Model, ModelNotify, ModelPeer};
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
#[no_mangle]
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_get_property(
inst: &ComponentInstance,
inst: &ErasedComponentBox,
name: Slice<u8>,
out: *mut ValueOpaque,
) -> 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) => {
std::ptr::write(out as *mut Value, val);
true
@ -1088,11 +1092,19 @@ pub(crate) mod ffi {
#[no_mangle]
pub extern "C" fn sixtyfps_interpreter_component_instance_set_property(
inst: &ComponentInstance,
inst: &ErasedComponentBox,
name: Slice<u8>,
val: &ValueOpaque,
) -> 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.
@ -1100,13 +1112,19 @@ pub(crate) mod ffi {
/// to the resulting value. If this function returns false, out is unchanged
#[no_mangle]
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_invoke_callback(
inst: &ComponentInstance,
inst: &ErasedComponentBox,
name: Slice<u8>,
args: Slice<ValueOpaque>,
out: *mut ValueOpaque,
) -> bool {
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) => {
std::ptr::write(out as *mut Value, val);
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)
#[no_mangle]
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_set_callback(
inst: &ComponentInstance,
inst: &ErasedComponentBox,
name: Slice<u8>,
callback: extern "C" fn(
user_data: *mut c_void,
@ -1150,22 +1168,44 @@ pub(crate) mod ffi {
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
#[no_mangle]
pub extern "C" fn sixtyfps_interpreter_component_instance_show(
inst: &ComponentInstance,
inst: &ErasedComponentBox,
is_visible: bool,
) {
generativity::make_guard!(guard);
let comp = inst.unerase(guard);
if is_visible {
inst.show();
comp.window().show();
} 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]
#[repr(C)]
pub struct ModelAdaptorVTable {