vrl/value/value/
display.rs1use std::{fmt, string::ToString};
2
3use chrono::SecondsFormat;
4
5use super::Value;
6
7impl fmt::Display for Value {
8 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
9 match self {
10 Self::Bytes(val) => write!(
11 f,
12 r#""{}""#,
13 String::from_utf8_lossy(val)
14 .replace('\\', r"\\")
15 .replace('"', r#"\""#)
16 .replace('\n', r"\n")
17 ),
18 Self::Integer(val) => write!(f, "{val}"),
19 Self::Float(val) => write!(f, "{val}"),
20 Self::Boolean(val) => write!(f, "{val}"),
21 Self::Object(map) => {
22 let joined = map
23 .iter()
24 .map(|(key, val)| format!(r#""{key}": {val}"#))
25 .collect::<Vec<_>>()
26 .join(", ");
27 write!(f, "{{ {joined} }}")
28 }
29 Self::Array(array) => {
30 let joined = array
31 .iter()
32 .map(ToString::to_string)
33 .collect::<Vec<_>>()
34 .join(", ");
35 write!(f, "[{joined}]")
36 }
37 Self::Timestamp(val) => {
38 write!(f, "t'{}'", val.to_rfc3339_opts(SecondsFormat::AutoSi, true))
39 }
40 Self::Regex(regex) => write!(f, "r'{}'", **regex),
41 Self::Null => write!(f, "null"),
42 }
43 }
44}
45
46#[cfg(test)]
47mod test {
48 use bytes::Bytes;
49 use chrono::DateTime;
50 use indoc::indoc;
51 use ordered_float::NotNan;
52 use regex::Regex;
53
54 use super::Value;
55
56 #[test]
57 fn test_display_string() {
58 assert_eq!(
59 Value::Bytes(Bytes::from("Hello, world!")).to_string(),
60 r#""Hello, world!""#
61 );
62 }
63
64 #[test]
65 fn test_display_string_with_backslashes() {
66 assert_eq!(
67 Value::Bytes(Bytes::from(r"foo \ bar \ baz")).to_string(),
68 r#""foo \\ bar \\ baz""#
69 );
70 }
71
72 #[test]
73 fn test_display_string_with_quotes() {
74 assert_eq!(
75 Value::Bytes(Bytes::from(r#""Hello, world!""#)).to_string(),
76 r#""\"Hello, world!\"""#
77 );
78 }
79
80 #[test]
81 fn test_display_string_with_newlines() {
82 assert_eq!(
83 Value::Bytes(Bytes::from(indoc! {"
84 Some
85 new
86 lines
87 "}))
88 .to_string(),
89 r#""Some\nnew\nlines\n""#
90 );
91 }
92
93 #[test]
94 fn test_display_integer() {
95 assert_eq!(Value::Integer(123).to_string(), "123");
96 }
97
98 #[test]
99 fn test_display_float() {
100 assert_eq!(
101 Value::Float(NotNan::new(123.45).unwrap()).to_string(),
102 "123.45"
103 );
104 }
105
106 #[test]
107 fn test_display_boolean() {
108 assert_eq!(Value::Boolean(true).to_string(), "true");
109 }
110
111 #[test]
112 fn test_display_object() {
113 assert_eq!(
114 Value::Object([("foo".into(), "bar".into())].into()).to_string(),
115 r#"{ "foo": "bar" }"#
116 );
117 }
118
119 #[test]
120 fn test_display_array() {
121 assert_eq!(
122 Value::Array(
123 vec!["foo", "bar"]
124 .into_iter()
125 .map(std::convert::Into::into)
126 .collect()
127 )
128 .to_string(),
129 r#"["foo", "bar"]"#
130 );
131 }
132
133 #[test]
134 fn test_display_timestamp() {
135 assert_eq!(
136 Value::Timestamp(
137 DateTime::parse_from_rfc3339("2000-10-10T20:55:36Z")
138 .unwrap()
139 .into()
140 )
141 .to_string(),
142 "t'2000-10-10T20:55:36Z'"
143 );
144 }
145
146 #[test]
147 fn test_display_regex() {
148 assert_eq!(
149 Value::Regex(Regex::new(".*").unwrap().into()).to_string(),
150 "r'.*'"
151 );
152 }
153
154 #[test]
155 fn test_display_null() {
156 assert_eq!(Value::Null.to_string(), "null");
157 }
158}