commit 9c9a3c80e25da686f32079ed6bd05177ad8b14fd
parent a0834cedcdba2804b546c803fe9c6b90b095556c
Author: triesap <triesap@radroots.dev>
Date: Mon, 19 Jan 2026 07:07:43 +0000
app-utils: add object helpers
- add obj_en mapping helper
- add truthy and result helpers
- export object helpers from utils crate
- add unit tests for object helpers
Diffstat:
4 files changed, 84 insertions(+), 0 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -1568,6 +1568,7 @@ dependencies = [
"getrandom 0.2.17",
"js-sys",
"radroots-types",
+ "serde_json",
"web-sys",
]
diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml
@@ -14,3 +14,4 @@ radroots-types = { workspace = true }
getrandom = { workspace = true }
js-sys = { workspace = true }
web-sys = { workspace = true }
+serde_json = { workspace = true }
diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs
@@ -4,6 +4,7 @@ pub mod error;
pub mod errors;
pub mod binary;
pub mod numbers;
+pub mod object;
pub mod path;
pub mod text;
pub mod time;
@@ -12,6 +13,7 @@ pub mod types;
pub use binary::{as_array_buffer, RadrootsAppArrayBuffer};
pub use errors::{err_msg, handle_err, throw_err, ERR_PREFIX_APP, ERR_PREFIX_UTILS};
pub use numbers::{num_interval_range, num_str, parse_float, parse_int};
+pub use object::{obj_en, obj_result, obj_results_str, obj_truthy_fields};
pub use path::{
parse_route_path,
resolve_route_path,
diff --git a/crates/utils/src/object/mod.rs b/crates/utils/src/object/mod.rs
@@ -0,0 +1,80 @@
+#![forbid(unsafe_code)]
+
+pub fn obj_en<K, V, F, I>(object: I, parse_function: F) -> Vec<(K, V)>
+where
+ I: IntoIterator<Item = (String, V)>,
+ F: Fn(&str) -> K,
+{
+ object
+ .into_iter()
+ .map(|(key, value)| (parse_function(&key), value))
+ .collect()
+}
+
+pub fn obj_truthy_fields<I, V>(values: I) -> bool
+where
+ I: IntoIterator<Item = V>,
+ V: AsRef<str>,
+{
+ values.into_iter().all(|value| !value.as_ref().is_empty())
+}
+
+pub fn obj_result(value: &serde_json::Value) -> Option<String> {
+ let obj = value.as_object()?;
+ let result = obj.get("result")?.as_str()?;
+ Some(result.to_string())
+}
+
+pub fn obj_results_str(value: &serde_json::Value) -> Option<Vec<String>> {
+ let obj = value.as_object()?;
+ let results = obj.get("results")?.as_array()?;
+ Some(
+ results
+ .iter()
+ .map(|entry| {
+ entry
+ .as_str()
+ .map(ToString::to_string)
+ .unwrap_or_else(|| entry.to_string())
+ })
+ .collect(),
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{obj_en, obj_result, obj_results_str, obj_truthy_fields};
+ use serde_json::json;
+ use std::collections::BTreeMap;
+
+ #[test]
+ fn obj_en_maps_entries() {
+ let mut map = BTreeMap::new();
+ map.insert("one".to_string(), 1);
+ let entries = obj_en(map.into_iter(), |key| format!("key:{key}"));
+ assert_eq!(entries, vec![("key:one".to_string(), 1)]);
+ }
+
+ #[test]
+ fn obj_truthy_fields_checks_values() {
+ let values = vec!["one", "two"];
+ assert!(obj_truthy_fields(values));
+ let values = vec!["one", ""];
+ assert!(!obj_truthy_fields(values));
+ }
+
+ #[test]
+ fn obj_result_reads_result_field() {
+ let value = json!({ "result": "ok" });
+ assert_eq!(obj_result(&value), Some("ok".to_string()));
+ }
+
+ #[test]
+ fn obj_results_str_reads_results_list() {
+ let value = json!({ "results": ["a", "b"] });
+ assert_eq!(
+ obj_results_str(&value),
+ Some(vec!["a".to_string(), "b".to_string()])
+ );
+ }
+}