structmap/
value.rs

1use std::any::Any;
2
3/// Represents primitive types that are supported for conversion into a BTreeMap that can support
4/// heterogeneous values. Inspired by `serde_json::Value`s.
5#[derive(Debug, Clone)]
6pub enum Value {
7    Null,
8    Bool(bool),
9    Num(Num),
10    String(String),
11    Array(Vec<Value>),
12    // TODO: Map
13}
14
15/// Represents the numeric primitive types that are supported for conversion.
16#[derive(Debug, Clone)]
17pub enum Num {
18    I64(i64),
19    U64(u64),
20    F64(f64),
21}
22
23impl Value {
24    /// Given a genericized input type, encapsulate it as a Value that can be used in a map
25    /// container type when converting to and from a struct.
26    pub fn new<T: Any>(value: T) -> Value {
27        let any_val = &value as &dyn Any;
28        if let Some(val) = any_val.downcast_ref::<bool>() {
29            Value::Bool(*val)
30        } else if let Some(val) = any_val.downcast_ref::<i64>() {
31            Value::Num(Num::I64(*val))
32        } else if let Some(val) = any_val.downcast_ref::<u64>() {
33            Value::Num(Num::U64(*val))
34        } else if let Some(val) = any_val.downcast_ref::<f64>() {
35            Value::Num(Num::F64(*val))
36        } else if let Some(val) = any_val.downcast_ref::<&'static str>() {
37            Value::String(val.to_string())
38        } else if let Some(val) = any_val.downcast_ref::<String>() {
39            Value::String(val.to_string())
40        } else if let Some(val) = any_val.downcast_ref::<Vec<Value>>() {
41            Value::Array(val.to_vec())
42        } else {
43            Value::Null
44        }
45    }
46
47    pub fn bool(&self) -> Option<bool> {
48        if let Value::Bool(val) = self {
49            Some(*val)
50        } else {
51            None
52        }
53    }
54
55    pub fn i64(&self) -> Option<i64> {
56        if let Value::Num(Num::I64(val)) = self {
57            Some(*val)
58        } else {
59            None
60        }
61    }
62
63    pub fn u64(&self) -> Option<u64> {
64        if let Value::Num(Num::U64(val)) = self {
65            Some(*val)
66        } else {
67            None
68        }
69    }
70
71    pub fn f64(&self) -> Option<f64> {
72        if let Value::Num(Num::F64(val)) = self {
73            Some(*val)
74        } else {
75            None
76        }
77    }
78
79    #[allow(non_snake_case)]
80    pub fn String(&self) -> Option<String> {
81        if let Value::String(string) = self {
82            Some(string.to_string())
83        } else {
84            None
85        }
86    }
87}