Add public API in the interpreter (Rust/C++) to obtain the list of functions

This commit is contained in:
Simon Hausmann 2024-06-05 20:17:57 +02:00 committed by Simon Hausmann
parent 6f2a6c3f09
commit 37b63e4bd4
4 changed files with 100 additions and 4 deletions

View file

@ -886,6 +886,15 @@ public:
return callbacks;
}
/// Returns a vector of strings that describe the list of public functions that can be invoked
/// using ComponentInstance::invoke.
slint::SharedVector<slint::SharedString> functions() const
{
slint::SharedVector<slint::SharedString> functions;
cbindgen_private::slint_interpreter_component_definition_functions(&inner, &functions);
return functions;
}
/// Returns the name of this Component as written in the .slint file
slint::SharedString name() const
{
@ -929,6 +938,20 @@ public:
}
return {};
}
/// Returns a vector of the names of the functions of the specified publicly exported global
/// singleton. An empty optional is returned if there exists no exported global singleton
/// under the specified name.
std::optional<slint::SharedVector<slint::SharedString>>
global_functions(std::string_view global_name) const
{
slint::SharedVector<slint::SharedString> names;
if (cbindgen_private::slint_interpreter_component_definition_global_functions(
&inner, slint::private_api::string_to_slice(global_name), &names)) {
return names;
}
return {};
}
};
inline ComponentDefinition ComponentInstance::definition() const

View file

@ -327,8 +327,10 @@ SCENARIO("Component Definition Properties")
using namespace slint;
ComponentCompiler compiler;
auto comp_def = *compiler.build_from_source(
"export component Dummy { in property <string> test; callback dummy; }", "");
auto comp_def =
*compiler.build_from_source("export component Dummy { in property <string> test; "
"callback dummy; public function my-fun() {} }",
"");
auto properties = comp_def.properties();
REQUIRE(properties.size() == 1);
REQUIRE(properties[0].property_name == "test");
@ -338,6 +340,10 @@ SCENARIO("Component Definition Properties")
REQUIRE(callback_names.size() == 1);
REQUIRE(callback_names[0] == "dummy");
auto function_names = comp_def.functions();
REQUIRE(function_names.size() == 1);
REQUIRE(function_names[0] == "my-fun");
auto instance = comp_def.create();
ComponentDefinition new_comp_def = instance->definition();
auto new_props = new_comp_def.properties();
@ -551,6 +557,10 @@ SCENARIO("Global properties")
auto callbacks = *component_definition.global_callbacks("The-Global");
REQUIRE(callbacks.size() == 1);
REQUIRE(callbacks[0] == "to_uppercase");
auto functions = *component_definition.global_functions("The-Global");
REQUIRE(functions.size() == 1);
REQUIRE(functions[0] == "ff");
}
auto instance = component_definition.create();

View file

@ -812,6 +812,20 @@ impl ComponentDefinition {
})
}
/// Returns the names of all publicly declared functions.
pub fn functions(&self) -> impl Iterator<Item = String> + '_ {
// We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime
// which is not required, but this is safe because there is only one instance of the unerased type
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
self.inner.unerase(guard).properties().filter_map(|(prop_name, prop_type)| {
if matches!(prop_type, LangType::Function { .. }) {
Some(prop_name)
} else {
None
}
})
}
/// Returns the names of all exported global singletons
///
/// **Note:** Only globals that are exported or re-exported from the main .slint file will
@ -873,6 +887,22 @@ impl ComponentDefinition {
})
}
/// List of publicly declared functions in the exported global singleton specified by its name.
pub fn global_functions(&self, global_name: &str) -> Option<impl Iterator<Item = String> + '_> {
// We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime
// which is not required, but this is safe because there is only one instance of the unerased type
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
self.inner.unerase(guard).global_properties(global_name).map(|iter| {
iter.filter_map(|(prop_name, prop_type)| {
if matches!(prop_type, LangType::Function { .. }) {
Some(prop_name)
} else {
None
}
})
})
}
/// The name of this Component as written in the .slint file
pub fn name(&self) -> &str {
// We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime
@ -1627,8 +1657,13 @@ fn call_functions() {
.into(),
"".into(),
),
);
let instance = definition.unwrap().create().unwrap();
)
.unwrap();
assert_eq!(definition.functions().collect::<Vec<_>>(), ["foo-bar"]);
assert_eq!(definition.global_functions("Gl").unwrap().collect::<Vec<_>>(), ["foo-bar"]);
let instance = definition.create().unwrap();
assert_eq!(
instance.invoke("foo_bar", &[Value::Number(3.), Value::Number(4.)]),

View file

@ -869,6 +869,15 @@ pub unsafe extern "C" fn slint_interpreter_component_definition_callbacks(
callbacks.extend((&*def).as_component_definition().callbacks().map(|name| name.into()))
}
/// Returns the list of function names of the component the component definition describes
#[no_mangle]
pub unsafe extern "C" fn slint_interpreter_component_definition_functions(
def: &ComponentDefinitionOpaque,
functions: &mut SharedVector<SharedString>,
) {
functions.extend((&*def).as_component_definition().functions().map(|name| name.into()))
}
/// Return the name of the component definition
#[no_mangle]
pub unsafe extern "C" fn slint_interpreter_component_definition_name(
@ -927,3 +936,22 @@ pub unsafe extern "C" fn slint_interpreter_component_definition_global_callbacks
false
}
}
/// Returns a vector of the names of the functions of the specified publicly exported global
/// singleton. Returns true if a global exists under the specified name; false otherwise.
#[no_mangle]
pub unsafe extern "C" fn slint_interpreter_component_definition_global_functions(
def: &ComponentDefinitionOpaque,
global_name: Slice<u8>,
names: &mut SharedVector<SharedString>,
) -> bool {
if let Some(name_it) = (&*def)
.as_component_definition()
.global_functions(std::str::from_utf8(&global_name).unwrap())
{
names.extend(name_it.map(|name| name.into()));
true
} else {
false
}
}