use crate::device::common::{DeviceError, DeviceResult};
use serde::de::DeserializeOwned;
use serde_json::Value;
pub fn parse_csv_line(line: &str) -> Vec<String> {
line.split(',')
.map(|s| s.trim().to_string())
.collect::<Vec<_>>()
}
#[allow(dead_code)]
pub fn parse_u64(s: &str) -> DeviceResult<u64> {
s.trim()
.parse::<u64>()
.map_err(|e| DeviceError::ParseError(format!("Failed to parse u64 from '{s}': {e}")))
}
#[allow(dead_code)]
pub fn parse_u32(s: &str) -> DeviceResult<u32> {
s.trim()
.parse::<u32>()
.map_err(|e| DeviceError::ParseError(format!("Failed to parse u32 from '{s}': {e}")))
}
#[allow(dead_code)]
pub fn parse_f64(s: &str) -> DeviceResult<f64> {
s.trim()
.parse::<f64>()
.map_err(|e| DeviceError::ParseError(format!("Failed to parse f64 from '{s}': {e}")))
}
#[allow(dead_code)]
pub fn json_get<'a>(v: &'a Value, key: &str) -> DeviceResult<&'a Value> {
v.get(key)
.ok_or_else(|| DeviceError::ParseError(format!("Missing JSON key '{key}'")))
}
#[allow(dead_code)]
pub fn json_parse<T: DeserializeOwned>(v: &Value, key: &str) -> DeviceResult<T> {
let field = json_get(v, key)?;
serde_json::from_value(field.clone()).map_err(|e| {
DeviceError::ParseError(format!(
"Failed to deserialize JSON key '{key}' into target type: {e}"
))
})
}
#[allow(dead_code)]
pub fn json_string(v: &Value, key: &str) -> DeviceResult<String> {
match json_get(v, key)? {
Value::String(s) => Ok(s.clone()),
other => Err(DeviceError::ParseError(format!(
"Expected string at key '{key}', found: {other}"
))),
}
}
#[allow(dead_code)]
pub fn json_u64(v: &Value, key: &str) -> DeviceResult<u64> {
match json_get(v, key)? {
Value::Number(n) => n
.as_u64()
.ok_or_else(|| DeviceError::ParseError(format!("JSON number at '{key}' not u64"))),
Value::String(s) => parse_u64(s),
other => Err(DeviceError::ParseError(format!(
"Expected u64 (number/string) at key '{key}', found: {other}"
))),
}
}
#[allow(dead_code)]
pub fn json_f64(v: &Value, key: &str) -> DeviceResult<f64> {
match json_get(v, key)? {
Value::Number(n) => n
.as_f64()
.ok_or_else(|| DeviceError::ParseError(format!("JSON number at '{key}' not f64"))),
Value::String(s) => parse_f64(s),
other => Err(DeviceError::ParseError(format!(
"Expected f64 (number/string) at key '{key}', found: {other}"
))),
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_parse_csv_line() {
let line = " 1, 2 ,3 , four ";
let parts = parse_csv_line(line);
assert_eq!(parts, vec!["1", "2", "3", "four"]);
}
#[test]
fn test_parse_numbers() {
assert_eq!(parse_u64("42").unwrap(), 42);
assert!(parse_u64("x").is_err());
assert_eq!(parse_u32("7").unwrap(), 7);
assert!(parse_u32("7.2").is_err());
assert!((parse_f64("2.34").unwrap() - 2.34).abs() < 1e-9);
assert!(parse_f64("pi").is_err());
}
#[test]
fn test_json_extractors() {
let v = json!({
"a": "hello",
"b": 123,
"c": "456",
"d": 1.5,
"e": "2.5"
});
assert_eq!(json_string(&v, "a").unwrap(), "hello");
assert_eq!(json_u64(&v, "b").unwrap(), 123);
assert_eq!(json_u64(&v, "c").unwrap(), 456);
assert!((json_f64(&v, "d").unwrap() - 1.5).abs() < 1e-9);
assert!((json_f64(&v, "e").unwrap() - 2.5).abs() < 1e-9);
assert!(json_get(&v, "missing").is_err());
}
#[test]
fn test_json_parse_generic() {
let v = json!({ "obj": { "x": 1, "y": 2 } });
#[derive(serde::Deserialize, Debug, PartialEq)]
struct Obj {
x: u32,
y: u32,
}
let obj: Obj = json_parse(&v, "obj").unwrap();
assert_eq!(obj, Obj { x: 1, y: 2 });
}
}