reval/value/
mod.rs

1//! The `Value` type encodes data that can be passed in or out from expressions
2pub mod convert;
3pub mod ser;
4
5use chrono::{prelude::*, TimeDelta};
6use itertools::Itertools;
7use rust_decimal::Decimal;
8use std::{collections::BTreeMap, fmt::Display};
9
10#[derive(Clone, Debug, PartialEq)]
11pub enum Value {
12    String(String),
13    Int(i128),
14    Float(f64),
15    Decimal(Decimal),
16    Bool(bool),
17    DateTime(DateTime<Utc>),
18    Duration(TimeDelta),
19    Vec(Vec<Value>),
20    Map(BTreeMap<String, Value>),
21    None,
22}
23
24impl Display for Value {
25    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        match self {
27            Value::String(value) => write!(formatter, "\"{value}\""),
28            Value::Int(value) => write!(formatter, "i{value}"),
29            Value::Float(value) => write!(formatter, "f{value}"),
30            Value::Decimal(value) => write!(formatter, "d{value}"),
31            Value::Bool(value) => write!(formatter, "{value}"),
32            Value::DateTime(value) => write!(formatter, "{value}"),
33            Value::Duration(value) => write!(formatter, "{value}"),
34            Value::Vec(values) => {
35                write!(
36                    formatter,
37                    "[{}]",
38                    values.iter().map(ToString::to_string).join(", ")
39                )
40            }
41            Value::Map(map) => write!(
42                formatter,
43                "{{{}}}",
44                map.iter()
45                    .map(|(key, value)| format!("{key}: {value}"))
46                    .join(", ")
47            ),
48            Value::None => write!(formatter, "none"),
49        }
50    }
51}
52
53#[cfg(test)]
54mod when_displaying_value {
55    use super::*;
56
57    #[test]
58    fn should_display_string() {
59        assert_eq!(Value::String("test".to_string()).to_string(), "\"test\"")
60    }
61
62    #[test]
63    fn should_display_escaped_string() {
64        assert_eq!(
65            Value::String("test\n\ttest".to_string()).to_string(),
66            "\"test\n\ttest\""
67        );
68    }
69
70    #[test]
71    fn should_display_int() {
72        assert_eq!(Value::Int(5).to_string(), "i5");
73    }
74
75    #[test]
76    fn should_display_float() {
77        assert_eq!(Value::Float(5.4).to_string(), "f5.4");
78    }
79
80    #[test]
81    fn should_display_decimal() {
82        assert_eq!(Value::Decimal(Decimal::new(53, 1)).to_string(), "d5.3");
83    }
84
85    #[test]
86    fn should_display_bool() {
87        assert_eq!(Value::Bool(true).to_string(), "true");
88        assert_eq!(Value::Bool(false).to_string(), "false");
89    }
90
91    #[test]
92    fn should_display_none() {
93        assert_eq!(Value::None.to_string(), "none");
94    }
95
96    #[test]
97    fn should_display_datetime() {
98        assert_eq!(
99            Value::DateTime(Utc.with_ymd_and_hms(2015, 7, 30, 3, 26, 13).unwrap()).to_string(),
100            "2015-07-30 03:26:13 UTC"
101        );
102    }
103
104    #[test]
105    fn should_display_duration() {
106        assert_eq!(Value::Duration(TimeDelta::days(4)).to_string(), "PT345600S");
107    }
108}