tracing_formatters/
value.rs

1use crate::index::Index;
2use alloc::string::String;
3use alloc::vec::Vec;
4use core::fmt::{self, Debug};
5use core::mem;
6use core::str;
7use std::collections::BTreeMap;
8use std::f32;
9
10#[derive(Clone)]
11pub enum Value {
12    Null,
13
14    Bool(bool),
15
16    Int(i64),
17    UInt(u64),
18    Float(f64),
19
20    String(String),
21
22    Array(Vec<Value>),
23
24    Map(BTreeMap<String, Value>),
25}
26impl Eq for Value {}
27
28impl PartialEq for Value {
29    fn eq(&self, other: &Self) -> bool {
30        match (self, other) {
31            (Self::Null, Self::Null) => true,
32            (Self::Bool(f1), Self::Bool(f2)) => f1 == f2,
33            (Self::Int(f1), Self::Int(f2)) => f1 == f2,
34            (Self::UInt(f1), Self::UInt(f2)) => f1 == f2,
35            (Self::Float(f1), Self::Float(f2)) => f1.to_string() == f2.to_string(),
36            (Self::String(f1), Self::String(f2)) => f1 == f2,
37            (Self::Array(f1), Self::Array(f2)) => f1 == f2,
38            (Self::Map(f1), Self::Map(f2)) => f1 == f2,
39            _ => false,
40        }
41    }
42}
43
44impl Debug for Value {
45    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
46        match self {
47            Value::Null => formatter.write_str("Null"),
48            Value::Bool(boolean) => write!(formatter, "Bool({})", boolean),
49            Value::String(string) => write!(formatter, "String({:?})", string),
50            Value::Array(vec) => {
51                formatter.write_str("Array ")?;
52                Debug::fmt(vec, formatter)
53            }
54            Value::Map(map) => {
55                formatter.write_str("Map ")?;
56                Debug::fmt(map, formatter)
57            }
58            Value::Int(i) => Debug::fmt(i, formatter),
59            Value::UInt(u) => Debug::fmt(u, formatter),
60            Value::Float(f) => Debug::fmt(f, formatter),
61        }
62    }
63}
64
65impl From<&str> for Value {
66    fn from(s: &str) -> Self {
67        Value::String(s.to_string())
68    }
69}
70impl From<bool> for Value {
71    fn from(b: bool) -> Self {
72        Value::Bool(b)
73    }
74}
75impl From<BTreeMap<String, Value>> for Value {
76    fn from(t: BTreeMap<String, Value>) -> Self {
77        Value::Map(t)
78    }
79}
80
81fn parse_index(s: &str) -> Option<usize> {
82    if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
83        return None;
84    }
85    s.parse().ok()
86}
87
88impl Value {
89    pub fn get<I: Index>(&self, index: I) -> Option<&Value> {
90        index.index_into(self)
91    }
92
93    pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut Value> {
94        index.index_into_mut(self)
95    }
96
97    pub fn is_object(&self) -> bool {
98        self.as_object().is_some()
99    }
100
101    pub fn as_object(&self) -> Option<&BTreeMap<String, Value>> {
102        match self {
103            Value::Map(map) => Some(map),
104            _ => None,
105        }
106    }
107
108    pub fn as_object_mut(&mut self) -> Option<&mut BTreeMap<String, Value>> {
109        match self {
110            Value::Map(map) => Some(map),
111            _ => None,
112        }
113    }
114
115    pub fn is_array(&self) -> bool {
116        self.as_array().is_some()
117    }
118
119    pub fn as_array(&self) -> Option<&Vec<Value>> {
120        match self {
121            Value::Array(array) => Some(array),
122            _ => None,
123        }
124    }
125
126    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
127        match self {
128            Value::Array(list) => Some(list),
129            _ => None,
130        }
131    }
132
133    pub fn is_string(&self) -> bool {
134        self.as_str().is_some()
135    }
136
137    pub fn as_str(&self) -> Option<&str> {
138        match self {
139            Value::String(s) => Some(s),
140            _ => None,
141        }
142    }
143
144    pub fn is_number(&self) -> bool {
145        match *self {
146            Value::Int(_) => true,
147            Value::UInt(_) => true,
148            Value::Float(_) => true,
149            _ => false,
150        }
151    }
152
153    pub fn is_i64(&self) -> bool {
154        match self {
155            Value::Int(_) => true,
156            _ => false,
157        }
158    }
159
160    pub fn is_u64(&self) -> bool {
161        match self {
162            Value::UInt(_) => true,
163            _ => false,
164        }
165    }
166
167    pub fn is_f64(&self) -> bool {
168        match self {
169            Value::Float(_) => true,
170            _ => false,
171        }
172    }
173
174    pub fn as_i64(&self) -> Option<i64> {
175        match self {
176            Value::Int(n) => Some(*n),
177            Value::UInt(n) => {
178                if n <= &(i64::MAX as u64) {
179                    Some(*n as i64)
180                } else {
181                    None
182                }
183            }
184            Value::Float(n) => None,
185            _ => None,
186        }
187    }
188
189    pub fn as_u64(&self) -> Option<u64> {
190        match self {
191            Value::Int(n) => {
192                if n.is_negative() {
193                    None
194                } else {
195                    Some(*n as u64)
196                }
197            }
198            Value::UInt(n) => Some(*n),
199            Value::Float(n) => None,
200            _ => None,
201        }
202    }
203
204    pub fn as_f64(&self) -> Option<f64> {
205        match self {
206            Value::Int(n) => Some(*n as f64),
207            Value::UInt(n) => Some(*n as f64),
208            Value::Float(n) => Some(*n),
209            _ => None,
210        }
211    }
212
213    pub fn is_boolean(&self) -> bool {
214        self.as_bool().is_some()
215    }
216
217    pub fn as_bool(&self) -> Option<bool> {
218        match *self {
219            Value::Bool(b) => Some(b),
220            _ => None,
221        }
222    }
223
224    pub fn is_null(&self) -> bool {
225        self.as_null().is_some()
226    }
227
228    /// If the `Value` is a Null, returns (). Returns None otherwise.
229    ///
230    /// ```
231    /// # use std::collections::BTreeMap;
232    /// # use tracing_formatters::value::Value;
233    /// #
234    /// let mut t = BTreeMap::new();
235    /// t.insert("a".into(), Value::Null);
236    /// t.insert("b".into(), false.into());
237    /// let v: Value = t.into();
238    ///
239    /// assert_eq!(v["a"].as_null(), Some(()));
240    ///
241    /// // The boolean `false` is not null.
242    /// assert_eq!(v["b"].as_null(), None);
243    /// ```
244    pub fn as_null(&self) -> Option<()> {
245        match *self {
246            Value::Null => Some(()),
247            _ => None,
248        }
249    }
250    /// Looks up a value by Pointer.
251    ///
252    /// Pointer defines a string syntax for identifying a specific value
253    ///
254    /// A Pointer is a Unicode string with the reference tokens separated by `/`.
255    /// Inside tokens `/` is replaced by `~1` and `~` is replaced by `~0`. The
256    /// addressed value is returned and if there is no such value `None` is
257    /// returned.
258    ///
259    /// For more information read [RFC6901](https://tools.ietf.org/html/rfc6901).
260    ///
261    /// # Examples
262    ///
263    /// ```
264    /// use std::collections::BTreeMap;
265    /// use tracing_formatters::value::Value;
266    ///
267    /// let mut tree2 = BTreeMap::new();
268    /// tree2.insert("y".to_string(),Value::Array(vec!["z".into(), "zz".into()]));
269    ///
270    /// let mut tree1 = BTreeMap::new();
271    /// tree1.insert("x".to_string(),Value::Map(tree2));
272    /// let data = Value::Map(tree1);
273    ///
274    ///
275    /// assert_eq!(data.pointer("/x/y/1").unwrap(), &Value::from("zz"));
276    /// assert_eq!(data.pointer("/a/b/c"), None);
277    /// ```
278    pub fn pointer(&self, pointer: &str) -> Option<&Value> {
279        if pointer.is_empty() {
280            return Some(self);
281        }
282        if !pointer.starts_with('/') {
283            return None;
284        }
285        pointer
286            .split('/')
287            .skip(1)
288            .map(|x| x.replace("~1", "/").replace("~0", "~"))
289            .try_fold(self, |target, token| match target {
290                Value::Map(map) => map.get(&token),
291                Value::Array(list) => parse_index(&token).and_then(|x| list.get(x)),
292                _ => None,
293            })
294    }
295    /// Looks up a value by a Pointer and returns a mutable reference to
296    /// that value.
297    ///
298    /// the Pointer defines a string syntax for identifying a specific value
299    ///
300    /// A Pointer is a Unicode string with the reference tokens separated by `/`.
301    /// Inside tokens `/` is replaced by `~1` and `~` is replaced by `~0`. The
302    /// addressed value is returned and if there is no such value `None` is
303    /// returned.
304    ///
305    /// # Example of Use
306    ///
307    /// ```
308    ///
309    /// use std::collections::BTreeMap;
310    /// use tracing_formatters::value::Value;
311    ///
312    /// let mut tree = BTreeMap::new();
313    /// tree.insert("x".to_string(), Value::Float(1.0));
314    /// tree.insert("y".to_string(), Value::Float(2.0));
315    /// let mut value: Value = Value::Map(tree);
316    ///
317    /// // Check value using read-only pointer
318    /// assert_eq!(value.pointer("/x"), Some(&Value::Float(1.0)));
319    /// // Change value with direct assignment
320    ///  *value.pointer_mut("/x").unwrap() = Value::Float(1.5);
321    /// // Check that new value was written
322    /// assert_eq!(value.pointer("/x"), Some(&Value::Float(1.5)));
323    /// // Or change the value only if it exists
324    /// value.pointer_mut("/x").map(|v| *v = Value::Float(1.5));
325    ///
326    /// // "Steal" ownership of a value. Can replace with any valid Value.
327    /// let old_x = value.pointer_mut("/x").map(Value::take).unwrap();
328    /// assert_eq!(old_x, Value::Float(1.5));
329    /// assert_eq!(value.pointer("/x").unwrap(), &Value::Null);
330    /// ```
331    pub fn pointer_mut(&mut self, pointer: &str) -> Option<&mut Value> {
332        if pointer.is_empty() {
333            return Some(self);
334        }
335        if !pointer.starts_with('/') {
336            return None;
337        }
338        pointer
339            .split('/')
340            .skip(1)
341            .map(|x| x.replace("~1", "/").replace("~0", "~"))
342            .try_fold(self, |target, token| match target {
343                Value::Map(map) => map.get_mut(&token),
344                Value::Array(list) => parse_index(&token).and_then(move |x| list.get_mut(x)),
345                _ => None,
346            })
347    }
348
349    pub fn take(&mut self) -> Value {
350        mem::replace(self, Value::Null)
351    }
352}
353
354impl Default for Value {
355    fn default() -> Value {
356        Value::Null
357    }
358}
359
360#[cfg(test)]
361pub mod tests {
362    use crate::value::Value;
363    use std::collections::BTreeMap;
364
365    #[test]
366    fn confirm_values() {
367        let mut v = Value::Int(9);
368        assert!(v.is_i64());
369        assert!(!v.is_f64());
370        assert!(!v.is_u64());
371        let mut v = Value::UInt(9);
372        assert!(v.is_u64());
373        assert!(!v.is_i64());
374        assert!(!v.is_f64());
375        let mut v = Value::Float(9.0);
376        assert!(!v.is_u64());
377        assert!(!v.is_i64());
378        assert!(v.is_f64());
379        v = Value::Array(Vec::new());
380        assert!(v.is_array());
381        v = Value::Bool(false);
382        assert!(v.is_boolean());
383        v = Value::Null;
384        assert!(v.is_null());
385        v = Value::String("".to_string());
386        assert!(v.is_string());
387    }
388
389    #[test]
390    fn pointer_mut_test() {
391        let mut tree = BTreeMap::new();
392        tree.insert("x".to_string(), Value::Float(1.0));
393        tree.insert("y".to_string(), Value::Float(2.0));
394        let mut value: Value = Value::Map(tree);
395
396        // Check value using read-only pointer
397        assert_eq!(value.pointer("/x"), Some(&Value::Float(1.0)));
398        // Change value with direct assignment
399        *value.pointer_mut("/x").unwrap() = Value::Float(1.5);
400        // Check that new value was written
401        assert_eq!(value.pointer("/x"), Some(&Value::Float(1.5)));
402        // Or change the value only if it exists
403        value.pointer_mut("/x").map(|v| *v = Value::Float(1.5));
404
405        // "Steal" ownership of a value. Can replace with any valid Value.
406        let old_x = value.pointer_mut("/x").map(Value::take).unwrap();
407        assert_eq!(old_x, Value::Float(1.5));
408        assert_eq!(value.pointer("/x").unwrap(), &Value::Null);
409    }
410}