mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 10:50:00 +00:00
Fix cross-compilation of C++ interpreter API to 32-bit architecture (#3810)
cbindgen doesn't reliably tranfser the 64-bit/32-bit #ifdefs around ValueOpaque. Instead, move Value onto the heap by using a Box. Fixes #3653
This commit is contained in:
parent
4b37d9a1f1
commit
1441719f61
4 changed files with 226 additions and 280 deletions
|
@ -151,30 +151,17 @@ public:
|
|||
|
||||
private:
|
||||
cbindgen_private::StructIteratorOpaque inner;
|
||||
const Value *v = nullptr;
|
||||
Value *v = nullptr;
|
||||
std::string_view k;
|
||||
friend Struct;
|
||||
explicit iterator(cbindgen_private::StructIteratorOpaque inner) : inner(inner) { next(); }
|
||||
// construct a end iterator
|
||||
iterator() = default;
|
||||
void next()
|
||||
{
|
||||
auto next = cbindgen_private::slint_interpreter_struct_iterator_next(&inner);
|
||||
v = reinterpret_cast<const Value *>(next.v);
|
||||
k = std::string_view(reinterpret_cast<char *>(next.k.ptr), next.k.len);
|
||||
if (!v) {
|
||||
cbindgen_private::slint_interpreter_struct_iterator_destructor(&inner);
|
||||
}
|
||||
}
|
||||
inline void next();
|
||||
|
||||
public:
|
||||
/// Destroys this field iterator.
|
||||
~iterator()
|
||||
{
|
||||
if (v) {
|
||||
cbindgen_private::slint_interpreter_struct_iterator_destructor(&inner);
|
||||
}
|
||||
}
|
||||
inline ~iterator();
|
||||
// FIXME I believe iterators are supposed to be copy constructible
|
||||
iterator(const iterator &) = delete;
|
||||
iterator &operator=(const iterator &) = delete;
|
||||
|
@ -256,23 +243,23 @@ class Value
|
|||
{
|
||||
public:
|
||||
/// Constructs a new value of type Value::Type::Void.
|
||||
Value() { cbindgen_private::slint_interpreter_value_new(&inner); }
|
||||
Value() : inner(cbindgen_private::slint_interpreter_value_new()) { }
|
||||
|
||||
/// Constructs a new value by copying \a other.
|
||||
Value(const Value &other) { slint_interpreter_value_clone(&other.inner, &inner); }
|
||||
Value(const Value &other) : inner(slint_interpreter_value_clone(other.inner)) { }
|
||||
/// Constructs a new value by moving \a other to this.
|
||||
Value(Value &&other)
|
||||
{
|
||||
inner = other.inner;
|
||||
cbindgen_private::slint_interpreter_value_new(&other.inner);
|
||||
other.inner = cbindgen_private::slint_interpreter_value_new();
|
||||
}
|
||||
/// Assigns the value \a other to this.
|
||||
Value &operator=(const Value &other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
cbindgen_private::slint_interpreter_value_destructor(&inner);
|
||||
slint_interpreter_value_clone(&other.inner, &inner);
|
||||
cbindgen_private::slint_interpreter_value_destructor(inner);
|
||||
inner = slint_interpreter_value_clone(other.inner);
|
||||
return *this;
|
||||
}
|
||||
/// Moves the value \a other to this.
|
||||
|
@ -280,13 +267,13 @@ public:
|
|||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
cbindgen_private::slint_interpreter_value_destructor(&inner);
|
||||
cbindgen_private::slint_interpreter_value_destructor(inner);
|
||||
inner = other.inner;
|
||||
cbindgen_private::slint_interpreter_value_new(&other.inner);
|
||||
other.inner = cbindgen_private::slint_interpreter_value_new();
|
||||
return *this;
|
||||
}
|
||||
/// Destroys the value.
|
||||
~Value() { cbindgen_private::slint_interpreter_value_destructor(&inner); }
|
||||
~Value() { cbindgen_private::slint_interpreter_value_destructor(inner); }
|
||||
|
||||
/// A convenience alias for the value type enum.
|
||||
using Type = ValueType;
|
||||
|
@ -297,7 +284,7 @@ public:
|
|||
/// Type::Double, otherwise an empty optional is returned.
|
||||
std::optional<double> to_number() const
|
||||
{
|
||||
if (auto *number = cbindgen_private::slint_interpreter_value_to_number(&inner)) {
|
||||
if (auto *number = cbindgen_private::slint_interpreter_value_to_number(inner)) {
|
||||
return *number;
|
||||
} else {
|
||||
return {};
|
||||
|
@ -308,7 +295,7 @@ public:
|
|||
/// Type::String, otherwise an empty optional is returned.
|
||||
std::optional<slint::SharedString> to_string() const
|
||||
{
|
||||
if (auto *str = cbindgen_private::slint_interpreter_value_to_string(&inner)) {
|
||||
if (auto *str = cbindgen_private::slint_interpreter_value_to_string(inner)) {
|
||||
return *str;
|
||||
} else {
|
||||
return {};
|
||||
|
@ -319,7 +306,7 @@ public:
|
|||
/// Type::Bool, otherwise an empty optional is returned.
|
||||
std::optional<bool> to_bool() const
|
||||
{
|
||||
if (auto *b = cbindgen_private::slint_interpreter_value_to_bool(&inner)) {
|
||||
if (auto *b = cbindgen_private::slint_interpreter_value_to_bool(inner)) {
|
||||
return *b;
|
||||
} else {
|
||||
return {};
|
||||
|
@ -336,7 +323,7 @@ public:
|
|||
/// Type::Brush, otherwise an empty optional is returned.
|
||||
std::optional<slint::Brush> to_brush() const
|
||||
{
|
||||
if (auto *brush = cbindgen_private::slint_interpreter_value_to_brush(&inner)) {
|
||||
if (auto *brush = cbindgen_private::slint_interpreter_value_to_brush(inner)) {
|
||||
return *brush;
|
||||
} else {
|
||||
return {};
|
||||
|
@ -347,7 +334,7 @@ public:
|
|||
/// Type::Struct, otherwise an empty optional is returned.
|
||||
std::optional<Struct> to_struct() const
|
||||
{
|
||||
if (auto *opaque_struct = cbindgen_private::slint_interpreter_value_to_struct(&inner)) {
|
||||
if (auto *opaque_struct = cbindgen_private::slint_interpreter_value_to_struct(inner)) {
|
||||
return Struct(*opaque_struct);
|
||||
} else {
|
||||
return {};
|
||||
|
@ -358,7 +345,7 @@ public:
|
|||
/// Type::Image, otherwise an empty optional is returned.
|
||||
std::optional<Image> to_image() const
|
||||
{
|
||||
if (auto *img = cbindgen_private::slint_interpreter_value_to_image(&inner)) {
|
||||
if (auto *img = cbindgen_private::slint_interpreter_value_to_image(inner)) {
|
||||
return *reinterpret_cast<const Image *>(img);
|
||||
} else {
|
||||
return {};
|
||||
|
@ -368,66 +355,68 @@ public:
|
|||
// template<typename T> std::optional<T> get() const;
|
||||
|
||||
/// Constructs a new Value that holds the double \a value.
|
||||
Value(double value) { cbindgen_private::slint_interpreter_value_new_double(value, &inner); }
|
||||
Value(double value) : inner(cbindgen_private::slint_interpreter_value_new_double(value)) { }
|
||||
/// Constructs a new Value that holds the int \a value.
|
||||
/// Internally this is stored as a double and Value::type() will return Value::Type::Number.
|
||||
Value(int value) : Value(static_cast<double>(value)) { }
|
||||
/// Constructs a new Value that holds the string \a str.
|
||||
Value(const SharedString &str)
|
||||
: inner(cbindgen_private::slint_interpreter_value_new_string(&str))
|
||||
{
|
||||
cbindgen_private::slint_interpreter_value_new_string(&str, &inner);
|
||||
}
|
||||
/// Constructs a new Value that holds the boolean \a b.
|
||||
Value(bool b) { cbindgen_private::slint_interpreter_value_new_bool(b, &inner); }
|
||||
Value(bool b) : inner(cbindgen_private::slint_interpreter_value_new_bool(b)) { }
|
||||
/// Constructs a new Value that holds the value vector \a v as a model.
|
||||
inline Value(const SharedVector<Value> &v);
|
||||
/// Constructs a new Value that holds the value model \a m.
|
||||
Value(const std::shared_ptr<slint::Model<Value>> &m);
|
||||
/// Constructs a new Value that holds the brush \a b.
|
||||
Value(const slint::Brush &brush)
|
||||
: inner(cbindgen_private::slint_interpreter_value_new_brush(&brush))
|
||||
{
|
||||
cbindgen_private::slint_interpreter_value_new_brush(&brush, &inner);
|
||||
}
|
||||
/// Constructs a new Value that holds the Struct \a struc.
|
||||
Value(const Struct &struc)
|
||||
: inner(cbindgen_private::slint_interpreter_value_new_struct(&struc.inner))
|
||||
{
|
||||
cbindgen_private::slint_interpreter_value_new_struct(&struc.inner, &inner);
|
||||
}
|
||||
|
||||
/// Constructs a new Value that holds the Image \a img.
|
||||
Value(const Image &img) { cbindgen_private::slint_interpreter_value_new_image(&img, &inner); }
|
||||
Value(const Image &img) : inner(cbindgen_private::slint_interpreter_value_new_image(&img)) { }
|
||||
|
||||
/// Returns the type the variant holds.
|
||||
Type type() const { return cbindgen_private::slint_interpreter_value_type(&inner); }
|
||||
Type type() const { return cbindgen_private::slint_interpreter_value_type(inner); }
|
||||
|
||||
/// Returns true if \a a and \a b hold values of the same type and the underlying vales are
|
||||
/// equal.
|
||||
friend bool operator==(const Value &a, const Value &b)
|
||||
{
|
||||
return cbindgen_private::slint_interpreter_value_eq(&a.inner, &b.inner);
|
||||
return cbindgen_private::slint_interpreter_value_eq(a.inner, b.inner);
|
||||
}
|
||||
|
||||
private:
|
||||
inline Value(const void *) = delete; // Avoid that for example Value("foo") turns to Value(bool)
|
||||
using ValueOpaque = slint::cbindgen_private::ValueOpaque;
|
||||
ValueOpaque inner;
|
||||
slint::cbindgen_private::Value *inner;
|
||||
friend struct Struct;
|
||||
friend class ComponentInstance;
|
||||
// Internal constructor that takes ownership of the value
|
||||
explicit Value(ValueOpaque &inner) : inner(inner) { }
|
||||
explicit Value(slint::cbindgen_private::Value *&&inner) : inner(inner) { }
|
||||
};
|
||||
|
||||
inline Value::Value(const slint::SharedVector<Value> &array)
|
||||
: inner(cbindgen_private::slint_interpreter_value_new_array_model(
|
||||
reinterpret_cast<const slint::SharedVector<slint::cbindgen_private::Value *> *>(
|
||||
&array)))
|
||||
{
|
||||
cbindgen_private::slint_interpreter_value_new_array_model(
|
||||
reinterpret_cast<const slint::SharedVector<ValueOpaque> *>(&array), &inner);
|
||||
}
|
||||
|
||||
inline std::optional<slint::SharedVector<Value>> Value::to_array() const
|
||||
{
|
||||
slint::SharedVector<Value> array;
|
||||
if (cbindgen_private::slint_interpreter_value_to_array(
|
||||
&inner, reinterpret_cast<slint::SharedVector<ValueOpaque> *>(&array))) {
|
||||
&inner,
|
||||
reinterpret_cast<slint::SharedVector<slint::cbindgen_private::Value *> *>(
|
||||
&array))) {
|
||||
return array;
|
||||
} else {
|
||||
return {};
|
||||
|
@ -470,18 +459,21 @@ inline Value::Value(const std::shared_ptr<slint::Model<Value>> &model)
|
|||
auto row_count = [](VRef<ModelAdaptorVTable> self) -> uintptr_t {
|
||||
return reinterpret_cast<ModelWrapper *>(self.instance)->model->row_count();
|
||||
};
|
||||
auto row_data = [](VRef<ModelAdaptorVTable> self, uintptr_t row, ValueOpaque *out) {
|
||||
auto row_data = [](VRef<ModelAdaptorVTable> self,
|
||||
uintptr_t row) -> slint::cbindgen_private::Value * {
|
||||
std::optional<Value> v =
|
||||
reinterpret_cast<ModelWrapper *>(self.instance)->model->row_data(int(row));
|
||||
if (v.has_value()) {
|
||||
*out = v->inner;
|
||||
cbindgen_private::slint_interpreter_value_new(&v->inner);
|
||||
return true;
|
||||
slint::cbindgen_private::Value *rval = v->inner;
|
||||
v->inner = cbindgen_private::slint_interpreter_value_new();
|
||||
return rval;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto set_row_data = [](VRef<ModelAdaptorVTable> self, uintptr_t row, const ValueOpaque *value) {
|
||||
Value v = *reinterpret_cast<const Value *>(value);
|
||||
auto set_row_data = [](VRef<ModelAdaptorVTable> self, uintptr_t row,
|
||||
slint::cbindgen_private::Value *value) {
|
||||
Value v(std::move(value));
|
||||
reinterpret_cast<ModelWrapper *>(self.instance)->model->set_row_data(int(row), v);
|
||||
};
|
||||
auto get_notify =
|
||||
|
@ -493,8 +485,8 @@ inline Value::Value(const std::shared_ptr<slint::Model<Value>> &model)
|
|||
};
|
||||
|
||||
static const ModelAdaptorVTable vt { row_count, row_data, set_row_data, get_notify, drop };
|
||||
cbindgen_private::slint_interpreter_value_new_model(reinterpret_cast<uint8_t *>(wrapper.get()),
|
||||
&vt, &inner);
|
||||
inner = cbindgen_private::slint_interpreter_value_new_model(
|
||||
reinterpret_cast<uint8_t *>(wrapper.get()), &vt);
|
||||
}
|
||||
|
||||
inline Struct::Struct(std::initializer_list<std::pair<std::string_view, Value>> args)
|
||||
|
@ -504,12 +496,14 @@ inline Struct::Struct(std::initializer_list<std::pair<std::string_view, Value>>
|
|||
|
||||
inline std::optional<Value> Struct::get_field(std::string_view name) const
|
||||
{
|
||||
using namespace cbindgen_private;
|
||||
cbindgen_private::Slice<uint8_t> name_view {
|
||||
const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(name.data())),
|
||||
name.size()
|
||||
};
|
||||
if (auto *value = cbindgen_private::slint_interpreter_struct_get_field(&inner, name_view)) {
|
||||
return *reinterpret_cast<const Value *>(value);
|
||||
if (cbindgen_private::Value *field_val =
|
||||
cbindgen_private::slint_interpreter_struct_get_field(&inner, name_view)) {
|
||||
return Value(std::move(field_val));
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
@ -520,7 +514,32 @@ inline void Struct::set_field(std::string_view name, const Value &value)
|
|||
const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(name.data())),
|
||||
name.size()
|
||||
};
|
||||
cbindgen_private::slint_interpreter_struct_set_field(&inner, name_view, &value.inner);
|
||||
cbindgen_private::slint_interpreter_struct_set_field(&inner, name_view, value.inner);
|
||||
}
|
||||
|
||||
inline void Struct::iterator::next()
|
||||
{
|
||||
cbindgen_private::Slice<uint8_t> name_slice;
|
||||
|
||||
if (cbindgen_private::Value *nextval_inner =
|
||||
cbindgen_private::slint_interpreter_struct_iterator_next(&inner, &name_slice)) {
|
||||
k = std::string_view(reinterpret_cast<char *>(name_slice.ptr), name_slice.len);
|
||||
if (!v)
|
||||
v = new Value();
|
||||
*v = Value(std::move(nextval_inner));
|
||||
} else {
|
||||
cbindgen_private::slint_interpreter_struct_iterator_destructor(&inner);
|
||||
delete v;
|
||||
v = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline Struct::iterator::~iterator()
|
||||
{
|
||||
if (v) {
|
||||
cbindgen_private::slint_interpreter_struct_iterator_destructor(&inner);
|
||||
delete v;
|
||||
}
|
||||
}
|
||||
|
||||
/// The ComponentInstance represents a running instance of a component.
|
||||
|
@ -606,16 +625,15 @@ public:
|
|||
{
|
||||
using namespace cbindgen_private;
|
||||
return slint_interpreter_component_instance_set_property(
|
||||
inner(), slint::private_api::string_to_slice(name), &value.inner);
|
||||
inner(), slint::private_api::string_to_slice(name), value.inner);
|
||||
}
|
||||
/// Returns the value behind a property declared in .slint.
|
||||
std::optional<Value> get_property(std::string_view name) const
|
||||
{
|
||||
using namespace cbindgen_private;
|
||||
ValueOpaque out;
|
||||
if (slint_interpreter_component_instance_get_property(
|
||||
inner(), slint::private_api::string_to_slice(name), &out)) {
|
||||
return Value(out);
|
||||
if (cbindgen_private::Value *prop_inner = slint_interpreter_component_instance_get_property(
|
||||
inner(), slint::private_api::string_to_slice(name))) {
|
||||
return Value(std::move(prop_inner));
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
@ -638,13 +656,14 @@ public:
|
|||
std::optional<Value> invoke(std::string_view name, std::span<const Value> args) const
|
||||
{
|
||||
using namespace cbindgen_private;
|
||||
Slice<ValueOpaque> args_view { const_cast<ValueOpaque *>(
|
||||
reinterpret_cast<const ValueOpaque *>(args.data())),
|
||||
args.size() };
|
||||
ValueOpaque out;
|
||||
if (slint_interpreter_component_instance_invoke(
|
||||
inner(), slint::private_api::string_to_slice(name), args_view, &out)) {
|
||||
return Value(out);
|
||||
Slice<Box<cbindgen_private::Value>> args_view {
|
||||
const_cast<Box<cbindgen_private::Value> *>(
|
||||
reinterpret_cast<const Box<cbindgen_private::Value> *>(args.data())),
|
||||
args.size()
|
||||
};
|
||||
if (cbindgen_private::Value *rval_inner = slint_interpreter_component_instance_invoke(
|
||||
inner(), slint::private_api::string_to_slice(name), args_view)) {
|
||||
return Value(std::move(rval_inner));
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
@ -677,12 +696,15 @@ public:
|
|||
auto set_callback(std::string_view name, F callback) const -> bool
|
||||
// clang-format on
|
||||
{
|
||||
using cbindgen_private::ValueOpaque;
|
||||
auto actual_cb = [](void *data, cbindgen_private::Slice<ValueOpaque> arg,
|
||||
ValueOpaque *ret) {
|
||||
using namespace cbindgen_private;
|
||||
auto actual_cb = [](void *data,
|
||||
cbindgen_private::Slice<cbindgen_private::Box<cbindgen_private::Value>>
|
||||
arg) {
|
||||
std::span<const Value> args_view { reinterpret_cast<const Value *>(arg.ptr), arg.len };
|
||||
Value r = (*reinterpret_cast<F *>(data))(args_view);
|
||||
new (ret) Value(std::move(r));
|
||||
auto inner = r.inner;
|
||||
r.inner = cbindgen_private::slint_interpreter_value_new();
|
||||
return inner;
|
||||
};
|
||||
return cbindgen_private::slint_interpreter_component_instance_set_callback(
|
||||
inner(), slint::private_api::string_to_slice(name), actual_cb,
|
||||
|
@ -709,18 +731,18 @@ public:
|
|||
using namespace cbindgen_private;
|
||||
return slint_interpreter_component_instance_set_global_property(
|
||||
inner(), slint::private_api::string_to_slice(global),
|
||||
slint::private_api::string_to_slice(prop_name), &value.inner);
|
||||
slint::private_api::string_to_slice(prop_name), value.inner);
|
||||
}
|
||||
/// Returns the value behind a property in an exported global singleton.
|
||||
std::optional<Value> get_global_property(std::string_view global,
|
||||
std::string_view prop_name) const
|
||||
{
|
||||
using namespace cbindgen_private;
|
||||
ValueOpaque out;
|
||||
if (slint_interpreter_component_instance_get_global_property(
|
||||
inner(), slint::private_api::string_to_slice(global),
|
||||
slint::private_api::string_to_slice(prop_name), &out)) {
|
||||
return Value(out);
|
||||
if (cbindgen_private::Value *rval_inner =
|
||||
slint_interpreter_component_instance_get_global_property(
|
||||
inner(), slint::private_api::string_to_slice(global),
|
||||
slint::private_api::string_to_slice(prop_name))) {
|
||||
return Value(std::move(rval_inner));
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
@ -748,12 +770,15 @@ public:
|
|||
template<std::invocable<std::span<const Value>> F>
|
||||
bool set_global_callback(std::string_view global, std::string_view name, F callback) const
|
||||
{
|
||||
using cbindgen_private::ValueOpaque;
|
||||
auto actual_cb = [](void *data, cbindgen_private::Slice<ValueOpaque> arg,
|
||||
ValueOpaque *ret) {
|
||||
using namespace cbindgen_private;
|
||||
auto actual_cb = [](void *data,
|
||||
cbindgen_private::Slice<cbindgen_private::Box<cbindgen_private::Value>>
|
||||
arg) {
|
||||
std::span<const Value> args_view { reinterpret_cast<const Value *>(arg.ptr), arg.len };
|
||||
Value r = (*reinterpret_cast<F *>(data))(args_view);
|
||||
new (ret) Value(std::move(r));
|
||||
auto inner = r.inner;
|
||||
r.inner = cbindgen_private::slint_interpreter_value_new();
|
||||
return inner;
|
||||
};
|
||||
return cbindgen_private::slint_interpreter_component_instance_set_global_callback(
|
||||
inner(), slint::private_api::string_to_slice(global),
|
||||
|
@ -766,14 +791,17 @@ public:
|
|||
std::span<const Value> args) const
|
||||
{
|
||||
using namespace cbindgen_private;
|
||||
Slice<ValueOpaque> args_view { const_cast<ValueOpaque *>(
|
||||
reinterpret_cast<const ValueOpaque *>(args.data())),
|
||||
args.size() };
|
||||
ValueOpaque out;
|
||||
if (slint_interpreter_component_instance_invoke_global(
|
||||
inner(), slint::private_api::string_to_slice(global),
|
||||
slint::private_api::string_to_slice(callable_name), args_view, &out)) {
|
||||
return Value(out);
|
||||
Slice<cbindgen_private::Box<cbindgen_private::Value>> args_view {
|
||||
const_cast<cbindgen_private::Box<cbindgen_private::Value> *>(
|
||||
reinterpret_cast<const cbindgen_private::Box<cbindgen_private::Value> *>(
|
||||
args.data())),
|
||||
args.size()
|
||||
};
|
||||
if (cbindgen_private::Value *rval_inner =
|
||||
slint_interpreter_component_instance_invoke_global(
|
||||
inner(), slint::private_api::string_to_slice(global),
|
||||
slint::private_api::string_to_slice(callable_name), args_view)) {
|
||||
return Value(std::move(rval_inner));
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
@ -1001,7 +1029,6 @@ public:
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace slint::testing {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue