Skip to content

Commit

Permalink
String: Add .is_empty() and .length() Methods
Browse files Browse the repository at this point in the history
Introduce two new methods for string properties in .slint:
- .is_empty(): Checks if a string is empty.
- .length(): Retrieves the length of the string.

These additions enhance functionality and improve convenience when working with string properties.
  • Loading branch information
task-jp committed Dec 21, 2024
1 parent 9db8027 commit aea12f3
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 0 deletions.
10 changes: 10 additions & 0 deletions api/cpp/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,16 @@ pub extern "C" fn slint_string_to_float(string: &SharedString, value: &mut f32)
}
}

#[no_mangle]
pub extern "C" fn slint_string_is_empty(string: &SharedString) -> bool {
string.is_empty()
}

#[no_mangle]
pub extern "C" fn slint_string_length(string: &SharedString) -> usize {
string.len()
}

#[no_mangle]
pub extern "C" fn slint_string_to_usize(string: &SharedString, value: &mut usize) -> bool {
match string.as_str().parse::<usize>() {
Expand Down
8 changes: 8 additions & 0 deletions internal/compiler/expression_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ pub enum BuiltinFunction {
StringToFloat,
/// the "42".is_float()
StringIsFloat,
/// the "42".is_empty()
StringIsEmpty,
/// the "42".length()
StringLength,
ColorRgbaStruct,
ColorHsvaStruct,
ColorBrighter,
Expand Down Expand Up @@ -164,6 +168,8 @@ declare_builtin_function_types!(
ItemFontMetrics: (Type::ElementReference) -> crate::typeregister::font_metrics_type(),
StringToFloat: (Type::String) -> Type::Float32,
StringIsFloat: (Type::String) -> Type::Bool,
StringIsEmpty: (Type::String) -> Type::Bool,
StringLength: (Type::String) -> Type::Int32,
ImplicitLayoutInfo(..): (Type::ElementReference) -> crate::typeregister::layout_info_type(),
ColorRgbaStruct: (Type::Color) -> Type::Struct(Rc::new(Struct {
fields: IntoIterator::into_iter([
Expand Down Expand Up @@ -274,6 +280,7 @@ impl BuiltinFunction {
BuiltinFunction::ItemMemberFunction(..) => false,
BuiltinFunction::ItemFontMetrics => false, // depends also on Window's font properties
BuiltinFunction::StringToFloat | BuiltinFunction::StringIsFloat => true,
BuiltinFunction::StringIsEmpty | BuiltinFunction::StringLength => true,
BuiltinFunction::ColorRgbaStruct
| BuiltinFunction::ColorHsvaStruct
| BuiltinFunction::ColorBrighter
Expand Down Expand Up @@ -343,6 +350,7 @@ impl BuiltinFunction {
BuiltinFunction::ItemMemberFunction(..) => false,
BuiltinFunction::ItemFontMetrics => true,
BuiltinFunction::StringToFloat | BuiltinFunction::StringIsFloat => true,
BuiltinFunction::StringIsEmpty | BuiltinFunction::StringLength => true,
BuiltinFunction::ColorRgbaStruct
| BuiltinFunction::ColorHsvaStruct
| BuiltinFunction::ColorBrighter
Expand Down
8 changes: 8 additions & 0 deletions internal/compiler/generator/cpp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3553,6 +3553,14 @@ fn compile_builtin_function_call(
ctx.generator_state.conditional_includes.cstdlib.set(true);
format!("[](const auto &a){{ float res = 0; slint::cbindgen_private::slint_string_to_float(&a, &res); return res; }}({})", a.next().unwrap())
}
BuiltinFunction::StringIsEmpty => {
ctx.generator_state.conditional_includes.cstdlib.set(true);
format!("[](const auto &a){{ return slint::cbindgen_private::slint_string_is_empty(&a); }}({})", a.next().unwrap())
}
BuiltinFunction::StringLength => {
ctx.generator_state.conditional_includes.cstdlib.set(true);
format!("[](const auto &a){{ return slint::cbindgen_private::slint_string_length(&a); }}({})", a.next().unwrap())
}
BuiltinFunction::ColorRgbaStruct => {
format!("{}.to_argb_uint()", a.next().unwrap())
}
Expand Down
2 changes: 2 additions & 0 deletions internal/compiler/generator/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2929,6 +2929,8 @@ fn compile_builtin_function_call(
quote!(#(#a)*.as_str().parse::<f64>().unwrap_or_default())
}
BuiltinFunction::StringIsFloat => quote!(#(#a)*.as_str().parse::<f64>().is_ok()),
BuiltinFunction::StringIsEmpty => quote!(#(#a)*.as_str().is_empty()),
BuiltinFunction::StringLength => quote!(#(#a)*.as_str().len() as i32),
BuiltinFunction::ColorRgbaStruct => quote!( #(#a)*.to_argb_u8()),
BuiltinFunction::ColorHsvaStruct => quote!( #(#a)*.to_hsva()),
BuiltinFunction::ColorBrighter => {
Expand Down
2 changes: 2 additions & 0 deletions internal/compiler/llr/optim_passes/inline_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ fn builtin_function_cost(function: &BuiltinFunction) -> isize {
BuiltinFunction::ItemFontMetrics => PROPERTY_ACCESS_COST,
BuiltinFunction::StringToFloat => 50,
BuiltinFunction::StringIsFloat => 50,
BuiltinFunction::StringIsEmpty => 50,
BuiltinFunction::StringLength => 50,
BuiltinFunction::ColorRgbaStruct => 50,
BuiltinFunction::ColorHsvaStruct => 50,
BuiltinFunction::ColorBrighter => 50,
Expand Down
2 changes: 2 additions & 0 deletions internal/compiler/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,8 @@ impl<'a> LookupObject for StringExpression<'a> {
let mut f = |s, res| f(&SmolStr::new_static(s), res);
None.or_else(|| f("is-float", member_function(BuiltinFunction::StringIsFloat)))
.or_else(|| f("to-float", member_function(BuiltinFunction::StringToFloat)))
.or_else(|| f("is-empty", member_function(BuiltinFunction::StringIsEmpty)))
.or_else(|| f("length", member_function(BuiltinFunction::StringLength)))
}
}
struct ColorExpression<'a>(&'a Expression);
Expand Down
20 changes: 20 additions & 0 deletions internal/interpreter/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,26 @@ fn call_builtin_function(
panic!("Argument not a string");
}
}
BuiltinFunction::StringIsEmpty => {
if arguments.len() != 1 {
panic!("internal error: incorrect argument count to StringIsEmpty")
}
if let Value::String(s) = eval_expression(&arguments[0], local_context) {
Value::Bool(s.as_str().is_empty())
} else {
panic!("Argument not a string");
}
}
BuiltinFunction::StringLength => {
if arguments.len() != 1 {
panic!("internal error: incorrect argument count to StringLength")
}
if let Value::String(s) = eval_expression(&arguments[0], local_context) {
Value::Number(s.as_str().len() as f64)
} else {
panic!("Argument not a string");
}
}
BuiltinFunction::ColorRgbaStruct => {
if arguments.len() != 1 {
panic!("internal error: incorrect argument count to ColorRGBAComponents")
Expand Down
38 changes: 38 additions & 0 deletions tests/cases/types/string_length.slint
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright © SixtyFPS GmbH <[email protected]>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

export component TestCase {
in property<string> hello: "hello";
in property<string> empty;

out property<bool> empty_is_empty: empty.is-empty();
out property<bool> hello_is_not_empty: !hello.is-empty();
out property<bool> test_is_empty: empty_is_empty && hello_is_not_empty;
out property<int> hello_length: hello.length();
out property<int> empty_length: empty.length();
out property<bool> hello_length_is_5: hello_length == 5;
out property<bool> empty_length_is_0: empty_length == 0;
out property<bool> test_length: hello_length_is_5 && empty_length_is_0;
out property<bool> test: test_is_empty && test_length;
}


/*
```cpp
auto handle = TestCase::create();
const TestCase &instance = *handle;
assert(instance.get_test());
```
```rust
let instance = TestCase::new().unwrap();
assert!(instance.get_test());
```
```js
var instance = new slint.TestCase({});
assert(instance.test);
```
*/

0 comments on commit aea12f3

Please sign in to comment.