1pub 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}