use serde_value::Value;
pub trait ValueExt {
fn get_field(&self, key: &str) -> Option<&Value>;
fn as_string(&self) -> Option<&str>;
fn as_i64(&self) -> Option<i64>;
fn as_u64(&self) -> Option<u64>;
fn as_f64(&self) -> Option<f64>;
fn as_bool(&self) -> Option<bool>;
}
impl ValueExt for Value {
fn get_field(&self, key: &str) -> Option<&Value> {
match self {
Value::Map(map) => {
map.iter()
.find(|(k, _)| {
if let Value::String(s) = k {
s == key
} else {
false
}
})
.map(|(_, v)| v)
}
_ => None,
}
}
fn as_string(&self) -> Option<&str> {
match self {
Value::String(s) => Some(s),
_ => None,
}
}
fn as_i64(&self) -> Option<i64> {
match self {
Value::I8(n) => Some(*n as i64),
Value::I16(n) => Some(*n as i64),
Value::I32(n) => Some(*n as i64),
Value::I64(n) => Some(*n),
_ => None,
}
}
fn as_u64(&self) -> Option<u64> {
match self {
Value::U8(n) => Some(*n as u64),
Value::U16(n) => Some(*n as u64),
Value::U32(n) => Some(*n as u64),
Value::U64(n) => Some(*n),
_ => None,
}
}
fn as_f64(&self) -> Option<f64> {
match self {
Value::F32(f) => Some(*f as f64),
Value::F64(f) => Some(*f),
_ => None,
}
}
fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(b) => Some(*b),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeMap;
#[test]
fn test_get_field() {
let mut map = BTreeMap::new();
map.insert(Value::String("name".into()), Value::String("Alice".into()));
map.insert(Value::String("id".into()), Value::I64(42));
let value = Value::Map(map);
assert_eq!(value.get_field("name").unwrap().as_string(), Some("Alice"));
assert_eq!(value.get_field("id").unwrap().as_i64(), Some(42));
assert!(value.get_field("missing").is_none());
}
#[test]
fn test_as_string() {
let value = Value::String("hello".into());
assert_eq!(value.as_string(), Some("hello"));
let value = Value::I64(42);
assert_eq!(value.as_string(), None);
}
#[test]
fn test_as_i64() {
assert_eq!(Value::I8(10).as_i64(), Some(10));
assert_eq!(Value::I16(100).as_i64(), Some(100));
assert_eq!(Value::I32(1000).as_i64(), Some(1000));
assert_eq!(Value::I64(10000).as_i64(), Some(10000));
assert_eq!(Value::String("nope".into()).as_i64(), None);
}
#[test]
fn test_as_u64() {
assert_eq!(Value::U8(10).as_u64(), Some(10));
assert_eq!(Value::U16(100).as_u64(), Some(100));
assert_eq!(Value::U32(1000).as_u64(), Some(1000));
assert_eq!(Value::U64(10000).as_u64(), Some(10000));
assert_eq!(Value::String("nope".into()).as_u64(), None);
}
#[test]
fn test_as_f64() {
assert_eq!(Value::F32(3.14).as_f64(), Some(3.14f32 as f64));
assert_eq!(Value::F64(2.718).as_f64(), Some(2.718));
assert_eq!(Value::I64(42).as_f64(), None);
}
#[test]
fn test_as_bool() {
assert_eq!(Value::Bool(true).as_bool(), Some(true));
assert_eq!(Value::Bool(false).as_bool(), Some(false));
assert_eq!(Value::I64(1).as_bool(), None);
}
#[test]
fn test_get_field_not_a_map() {
let value = Value::String("not a map".into());
assert!(value.get_field("anything").is_none());
}
}