influxdb2_structmap/
value.rs

1use std::any::Any;
2use std::fmt;
3
4use chrono::{DateTime, FixedOffset};
5use num_traits::cast::ToPrimitive;
6use ordered_float::OrderedFloat;
7
8/// Represents primitive types that are supported for conversion into a BTreeMap that can support
9/// heterogeneous values. Inspired by `serde_json::Value`s.
10#[derive(Debug, Clone, Eq, Hash, PartialEq)]
11pub enum Value {
12    Unknown,
13    String(String),
14    Double(OrderedFloat<f64>),
15    Bool(bool),
16    Long(i64),
17    UnsignedLong(u64),
18    Duration(chrono::Duration),
19    Base64Binary(Vec<u8>),
20    TimeRFC(DateTime<FixedOffset>),
21}
22
23impl fmt::Display for Value {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        write!(f, "{}", self)
26    }
27}
28
29impl Value {
30    /// Given a genericized input type, encapsulate it as a Value that can be used in a map
31    /// container type when converting to and from a struct.
32    pub fn new<T: Any>(value: T) -> Value {
33        let any_val = &value as &dyn Any;
34        if let Some(val) = any_val.downcast_ref::<f64>() {
35            Value::Double(OrderedFloat::from(*val))
36        } else if let Some(val) = any_val.downcast_ref::<bool>() {
37            Value::Bool(*val)
38        } else if let Some(val) = any_val.downcast_ref::<i64>() {
39            Value::Long(*val)
40        } else if let Some(val) = any_val.downcast_ref::<u64>() {
41            Value::UnsignedLong(*val)
42        } else if let Some(val) = any_val.downcast_ref::<chrono::Duration>() {
43            Value::Duration(*val)
44        } else if let Some(val) = any_val.downcast_ref::<Vec<u8>>() {
45            Value::Base64Binary(val.clone())
46        } else if let Some(val) = any_val.downcast_ref::<DateTime<FixedOffset>>() {
47            Value::TimeRFC(*val)
48        } else if let Some(val) = any_val.downcast_ref::<String>() {
49            Value::String(val.to_string())
50        } else {
51            Value::Unknown
52        }
53    }
54
55    pub fn downcast<T>(&self) -> Option<T> {
56        None
57    }
58
59    pub fn bool(&self) -> Option<bool> {
60        if let Value::Bool(val) = self {
61            Some(*val)
62        } else {
63            None
64        }
65    }
66
67    pub fn i64(&self) -> Option<i64> {
68        if let Value::Long(val) = self {
69            Some(*val)
70        } else {
71            None
72        }
73    }
74
75    pub fn u64(&self) -> Option<u64> {
76        if let Value::UnsignedLong(val) = self {
77            Some(*val)
78        } else {
79            None
80        }
81    }
82
83    pub fn f64(&self) -> Option<f64> {
84        if let Value::Double(val) = self {
85            val.to_f64()
86        } else {
87            None
88        }
89    }
90
91    pub fn string(&self) -> Option<String> {
92        if let Value::String(string) = self {
93            Some(string.to_string())
94        } else {
95            None
96        }
97    }
98}
99