ferroui_base/data/converters/
string_converters.rs1use super::{FuncValueConverter, IValueConverter};
2use std::rc::Rc;
3
4pub struct StringConverters;
7
8impl StringConverters {
9 pub fn is_null_or_empty() -> Rc<dyn IValueConverter> {
12 crate::ferro_thread_local! {
13 static IS_NULL_OR_EMPTY: Rc<dyn IValueConverter> =
14 Rc::new(FuncValueConverter::<Option<String>, bool>::new(|x| x.is_none_or(|x| x.is_empty())));
15 }
16 IS_NULL_OR_EMPTY.with(Rc::clone)
17 }
18
19 pub fn is_not_null_or_empty() -> Rc<dyn IValueConverter> {
22 crate::ferro_thread_local! {
23 static IS_NOT_NULL_OR_EMPTY: Rc<dyn IValueConverter> =
24 Rc::new(FuncValueConverter::<Option<String>, bool>::new(|x| !x.is_none_or(|x| x.is_empty())));
25 }
26 IS_NOT_NULL_OR_EMPTY.with(Rc::clone)
27 }
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33 use crate::data::core::ValueType;
34 use crate::data::{BindingError, BindingOperations};
35 use crate::BoxedValue;
36
37 fn boxed(input: Option<&str>) -> Option<BoxedValue> {
38 input.map(|s| Rc::new(s.to_string()) as BoxedValue)
39 }
40
41 fn as_bool(result: Result<Option<BoxedValue>, BindingError>) -> bool {
42 let value = result.expect("no error").expect("not null");
43 *value.downcast_ref::<bool>().expect("a bool")
44 }
45
46 #[test]
47 fn string_converters_is_null_or_empty_works() {
48 for (input, expected) in [(Some("hello"), false), (Some(""), true), (None, true)] {
49 let converter = StringConverters::is_null_or_empty();
50 let result = converter.convert(boxed(input).as_ref(), ValueType::of::<bool>(), None, &crate::utilities::CultureInfo::current_culture());
51 assert_eq!(as_bool(result), expected, "{input:?}");
52 }
53 }
54
55 #[test]
56 fn string_converters_is_not_null_or_empty_works() {
57 for (input, expected) in [(Some("hello"), true), (Some(""), false), (None, false)] {
58 let converter = StringConverters::is_not_null_or_empty();
59 let result = converter.convert(boxed(input).as_ref(), ValueType::of::<bool>(), None, &crate::utilities::CultureInfo::current_culture());
60 assert_eq!(as_bool(result), expected, "{input:?}");
61 }
62 }
63
64 #[test]
67 fn returns_unset_for_input_that_is_not_a_string() {
68 let converter = StringConverters::is_null_or_empty();
69 let input: BoxedValue = Rc::new(5i32);
70 let result = converter.convert(Some(&input), ValueType::of::<bool>(), None, &crate::utilities::CultureInfo::current_culture());
71 assert!(BindingOperations::is_unset(result.expect("no error").as_ref()));
72 }
73
74 #[test]
75 fn accepts_string_literals_and_nullable_strings() {
76 let converter = StringConverters::is_null_or_empty();
77 let literal: BoxedValue = Rc::new("hello");
78 let nullable: BoxedValue = Rc::new(Option::<String>::None);
79 assert!(!as_bool(converter.convert(Some(&literal), ValueType::of::<bool>(), None, &crate::utilities::CultureInfo::current_culture())));
80 assert!(as_bool(converter.convert(Some(&nullable), ValueType::of::<bool>(), None, &crate::utilities::CultureInfo::current_culture())));
81 }
82}