C++ interpreter: do the renaming invoke_callback -> invoke

This commit is contained in:
Olivier Goffart 2022-12-23 11:20:57 +01:00 committed by Olivier Goffart
parent 16fdd0595b
commit 629a64ba89
4 changed files with 66 additions and 29 deletions

View file

@ -619,7 +619,7 @@ public:
return {}; return {};
} }
} }
/// Invoke the specified callback declared in .slint with the given arguments /// Invoke the specified callback or function declared in .slint with the given arguments
/// ///
/// Example: imagine the .slint file contains the given callback declaration: /// Example: imagine the .slint file contains the given callback declaration:
/// ``` /// ```
@ -628,20 +628,20 @@ public:
/// Then one can call it with this function /// Then one can call it with this function
/// ``` /// ```
/// slint::Value args[] = { SharedString("Hello"), 42. }; /// slint::Value args[] = { SharedString("Hello"), 42. };
/// instance->invoke_callback("foo", { args, 2 }); /// instance->invoke("foo", { args, 2 });
/// ``` /// ```
/// ///
/// Returns an null optional if the callback don't exist or if the argument don't match /// Returns an null optional if the callback don't exist or if the argument don't match
/// Otherwise return the returned value from the callback, which may be an empty Value if /// Otherwise return the returned value from the callback, which may be an empty Value if
/// the callback did not return a value. /// the callback did not return a value.
std::optional<Value> invoke_callback(std::string_view name, std::span<const Value> args) const std::optional<Value> invoke(std::string_view name, std::span<const Value> args) const
{ {
using namespace cbindgen_private; using namespace cbindgen_private;
Slice<ValueOpaque> args_view { const_cast<ValueOpaque *>( Slice<ValueOpaque> args_view { const_cast<ValueOpaque *>(
reinterpret_cast<const ValueOpaque *>(args.data())), reinterpret_cast<const ValueOpaque *>(args.data())),
args.size() }; args.size() };
ValueOpaque out; ValueOpaque out;
if (slint_interpreter_component_instance_invoke_callback( if (slint_interpreter_component_instance_invoke(
inner(), slint::private_api::string_to_slice(name), args_view, &out)) { inner(), slint::private_api::string_to_slice(name), args_view, &out)) {
return Value(out); return Value(out);
} else { } else {
@ -649,6 +649,13 @@ public:
} }
} }
/// \deprecated rename to invoke()
[[deprecated("renamed to invoke()")]] std::optional<Value>
invoke_callback(std::string_view name, std::span<const Value> args) const
{
return invoke(name, args);
}
/// Set a handler for the callback with the given name. /// Set a handler for the callback with the given name.
/// ///
/// A callback with that name must be defined in the document otherwise the function /// A callback with that name must be defined in the document otherwise the function
@ -757,24 +764,31 @@ public:
[](void *data) { delete reinterpret_cast<F *>(data); }); [](void *data) { delete reinterpret_cast<F *>(data); });
} }
/// Invoke the specified callback declared in an exported global singleton /// Invoke the specified callback or function declared in an exported global singleton
std::optional<Value> invoke_global_callback(std::string_view global, std::optional<Value> invoke_global(std::string_view global, std::string_view callable_name,
std::string_view callback_name, std::span<const Value> args) const
std::span<const Value> args) const
{ {
using namespace cbindgen_private; using namespace cbindgen_private;
Slice<ValueOpaque> args_view { const_cast<ValueOpaque *>( Slice<ValueOpaque> args_view { const_cast<ValueOpaque *>(
reinterpret_cast<const ValueOpaque *>(args.data())), reinterpret_cast<const ValueOpaque *>(args.data())),
args.size() }; args.size() };
ValueOpaque out; ValueOpaque out;
if (slint_interpreter_component_instance_invoke_global_callback( if (slint_interpreter_component_instance_invoke_global(
inner(), slint::private_api::string_to_slice(global), inner(), slint::private_api::string_to_slice(global),
slint::private_api::string_to_slice(callback_name), args_view, &out)) { slint::private_api::string_to_slice(callable_name), args_view, &out)) {
return Value(out); return Value(out);
} else { } else {
return {}; return {};
} }
} }
/// \deprecated renamed to invoke_global
[[deprecated("renamed to invoke_global()")]] std::optional<Value>
invoke_global_callback(std::string_view global, std::string_view callback_name,
std::span<const Value> args) const
{
return invoke_global(global, callback_name, args);
}
}; };
/// ComponentDefinition is a representation of a compiled component from .slint markup. /// ComponentDefinition is a representation of a compiled component from .slint markup.
@ -841,7 +855,7 @@ public:
} }
/// Returns a vector of strings that describe the list of public callbacks that can be invoked /// Returns a vector of strings that describe the list of public callbacks that can be invoked
/// using ComponentInstance::invoke_callback and set using ComponentInstance::set_callback. /// using ComponentInstance::invoke and set using ComponentInstance::set_callback.
slint::SharedVector<slint::SharedString> callbacks() const slint::SharedVector<slint::SharedString> callbacks() const
{ {
slint::SharedVector<slint::SharedString> callbacks; slint::SharedVector<slint::SharedString> callbacks;

View file

@ -369,7 +369,7 @@ SCENARIO("Invoke callback")
return Value(SharedString(res)); return Value(SharedString(res));
})); }));
Value args[] = { SharedString("Hello"), 42. }; Value args[] = { SharedString("Hello"), 42. };
auto res = instance->invoke_callback("some_callback", args); auto res = instance->invoke("some_callback", args);
REQUIRE(res.has_value()); REQUIRE(res.has_value());
REQUIRE(*res->to_string() == SharedString("Hello:42_string_on_the_stack_")); REQUIRE(*res->to_string() == SharedString("Hello:42_string_on_the_stack_"));
} }
@ -382,7 +382,7 @@ SCENARIO("Invoke callback")
auto instance = result->create(); auto instance = result->create();
REQUIRE(!instance->set_callback("bar", [](auto) { return Value(); })); REQUIRE(!instance->set_callback("bar", [](auto) { return Value(); }));
Value args[] = { SharedString("Hello"), 42. }; Value args[] = { SharedString("Hello"), 42. };
auto res = instance->invoke_callback("bar", args); auto res = instance->invoke("bar", args);
REQUIRE(!res.has_value()); REQUIRE(!res.has_value());
} }
} }
@ -505,6 +505,7 @@ SCENARIO("Global properties")
export global The-Global := { export global The-Global := {
property <string> the-property: "€€€"; property <string> the-property: "€€€";
callback to_uppercase(string)->string; callback to_uppercase(string)->string;
public function ff() -> string { return the-property; }
} }
export Dummy := Rectangle { export Dummy := Rectangle {
property <string> result: The-Global.to_uppercase("abc"); property <string> result: The-Global.to_uppercase("abc");
@ -578,7 +579,7 @@ SCENARIO("Global properties")
REQUIRE(result->to_string().value() == "ABC"); REQUIRE(result->to_string().value() == "ABC");
Value args[] = { SharedString("Hello") }; Value args[] = { SharedString("Hello") };
auto res = instance->invoke_global_callback("The_Global", "to-uppercase", args); auto res = instance->invoke_global("The_Global", "to-uppercase", args);
REQUIRE(res.has_value()); REQUIRE(res.has_value());
REQUIRE(*res->to_string() == SharedString("HELLO")); REQUIRE(*res->to_string() == SharedString("HELLO"));
} }
@ -588,7 +589,14 @@ SCENARIO("Global properties")
[](auto) { return Value {}; })); [](auto) { return Value {}; }));
REQUIRE(!instance->set_global_callback("The-Global", "touppercase", REQUIRE(!instance->set_global_callback("The-Global", "touppercase",
[](auto) { return Value {}; })); [](auto) { return Value {}; }));
REQUIRE(!instance->invoke_global_callback("TheGlobal", "touppercase", {})); REQUIRE(!instance->invoke_global("TheGlobal", "touppercase", {}));
REQUIRE(!instance->invoke_global_callback("The-Global", "touppercase", {})); REQUIRE(!instance->invoke_global("The-Global", "touppercase", {}));
}
SECTION("invoke function")
{
REQUIRE(instance->set_global_property("The-Global", "the-property", SharedString("&&&")));
auto res = instance->invoke_global("The_Global", "ff", {});
REQUIRE(res.has_value());
REQUIRE(*res->to_string() == SharedString("&&&"));
} }
} }

View file

@ -1006,7 +1006,7 @@ impl ComponentInstance {
.borrow() .borrow()
.lookup_property(callable_name) .lookup_property(callable_name)
.property_type, .property_type,
i_slint_compiler::langtype::Type::Function { .. } LangType::Function { .. }
) { ) {
g.as_ref() g.as_ref()
.eval_function(callable_name, args.iter().cloned().collect()) .eval_function(callable_name, args.iter().cloned().collect())
@ -1126,12 +1126,14 @@ pub enum InvokeError {
#[error("no such callback or function")] #[error("no such callback or function")]
NoSuchCallable, NoSuchCallable,
} }
/// deprecated alias to [`InvokeError`]
#[deprecated(note = "Renamed to InvokeError")] #[deprecated(note = "Renamed to InvokeError")]
type InvokeCallbackError = InvokeError; pub type InvokeCallbackError = InvokeError;
impl InvokeError { impl InvokeError {
/// deprecated alias to [`InvokeCallbackError::NoSuchCallback`]
#[deprecated(note = "Renamed NoSuchCallable")] #[deprecated(note = "Renamed NoSuchCallable")]
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
const NoSuchCallback: Self = Self::NoSuchCallable; pub const NoSuchCallback: Self = Self::NoSuchCallable;
} }
/// Enters the main event loop. This is necessary in order to receive /// Enters the main event loop. This is necessary in order to receive

View file

@ -351,11 +351,11 @@ pub extern "C" fn slint_interpreter_component_instance_set_property(
.is_ok() .is_ok()
} }
/// Invoke a callback. /// Invoke a callback or function
/// The `out` parameter must be uninitialized. If this function returns true, the out will be initialized /// The `out` parameter must be uninitialized. If this function returns true, the out will be initialized
/// 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 slint_interpreter_component_instance_invoke_callback( pub unsafe extern "C" fn slint_interpreter_component_instance_invoke(
inst: &ErasedComponentBox, inst: &ErasedComponentBox,
name: Slice<u8>, name: Slice<u8>,
args: Slice<ValueOpaque>, args: Slice<ValueOpaque>,
@ -364,7 +364,7 @@ pub unsafe extern "C" fn slint_interpreter_component_instance_invoke_callback(
let args = std::mem::transmute::<Slice<ValueOpaque>, Slice<Value>>(args); let args = std::mem::transmute::<Slice<ValueOpaque>, Slice<Value>>(args);
generativity::make_guard!(guard); generativity::make_guard!(guard);
let comp = inst.unerase(guard); let comp = inst.unerase(guard);
match comp.description().invoke_callback( match comp.description().invoke(
comp.borrow(), comp.borrow(),
&normalize_identifier(std::str::from_utf8(&name).unwrap()), &normalize_identifier(std::str::from_utf8(&name).unwrap()),
args.as_slice(), args.as_slice(),
@ -507,28 +507,41 @@ pub unsafe extern "C" fn slint_interpreter_component_instance_set_global_callbac
.is_ok() .is_ok()
} }
/// Invoke a global callback. /// Invoke a global callback or function.
/// The `out` parameter must be uninitialized. If this function returns true, the out will be initialized /// The `out` parameter must be uninitialized. If this function returns true, the out will be initialized
/// 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 slint_interpreter_component_instance_invoke_global_callback( pub unsafe extern "C" fn slint_interpreter_component_instance_invoke_global(
inst: &ErasedComponentBox, inst: &ErasedComponentBox,
global: Slice<u8>, global: Slice<u8>,
callback_name: Slice<u8>, callable_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);
generativity::make_guard!(guard); generativity::make_guard!(guard);
let comp = inst.unerase(guard); let comp = inst.unerase(guard);
let callable_name = std::str::from_utf8(&callable_name).unwrap();
match comp match comp
.description() .description()
.get_global(comp.borrow(), &normalize_identifier(std::str::from_utf8(&global).unwrap())) .get_global(comp.borrow(), &normalize_identifier(std::str::from_utf8(&global).unwrap()))
.and_then(|g| { .and_then(|g| {
g.as_ref().invoke_callback( if matches!(
&normalize_identifier(std::str::from_utf8(&callback_name).unwrap()), comp.description()
args.as_slice(), .original
) .root_element
.borrow()
.lookup_property(callable_name)
.property_type,
i_slint_compiler::langtype::Type::Function { .. }
) {
g.as_ref().eval_function(
&normalize_identifier(callable_name),
args.as_slice().iter().cloned().collect(),
)
} else {
g.as_ref().invoke_callback(&normalize_identifier(callable_name), args.as_slice())
}
}) { }) {
Ok(val) => { Ok(val) => {
std::ptr::write(out as *mut Value, val); std::ptr::write(out as *mut Value, val);