1use crate::string_value::StringValuePrinter;
2use bluejay_core::{AsIter, ObjectValue, Value, ValueReference, Variable};
3use std::fmt::{Display, Formatter, Result};
4
5pub struct ValuePrinter<'a, const CONST: bool, V: Value<CONST>>(&'a V);
6
7impl<'a, const CONST: bool, V: Value<CONST>> ValuePrinter<'a, CONST, V> {
8 pub fn new(value: &'a V) -> Self {
9 Self(value)
10 }
11
12 pub fn to_string(value: &'a V) -> String {
13 Self::new(value).to_string()
14 }
15}
16
17impl<const CONST: bool, V: Value<CONST>> Display for ValuePrinter<'_, CONST, V> {
18 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
19 let Self(value) = *self;
20 match value.as_ref() {
21 ValueReference::Boolean(b) => write!(f, "{}", b),
22 ValueReference::Enum(e) => write!(f, "{}", e),
23 ValueReference::Float(fl) => {
24 if fl.fract().abs() < 1e-10 {
25 write!(f, "{fl:.1}")
26 } else {
27 write!(f, "{fl}")
28 }
29 }
30 ValueReference::Integer(i) => write!(f, "{}", i),
31 ValueReference::List(l) => {
32 write!(f, "[")?;
33 l.iter().enumerate().try_for_each(|(idx, el)| {
34 if idx != 0 {
35 write!(f, ", ")?;
36 }
37 write!(f, "{}", Self::new(el))
38 })?;
39 write!(f, "]")
40 }
41 ValueReference::Null => write!(f, "null"),
42 ValueReference::Object(o) => {
43 write!(f, "{{ ")?;
44
45 o.iter().enumerate().try_for_each(|(idx, (key, value))| {
46 if idx != 0 {
47 write!(f, ", ")?;
48 }
49 write!(f, "{}: {}", key.as_ref(), Self::new(value))
50 })?;
51
52 write!(f, " }}")
53 }
54 ValueReference::String(s) => write!(f, "{}", StringValuePrinter::new(s)),
55 ValueReference::Variable(v) => write!(f, "${}", v.name()),
56 }
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::ValuePrinter;
63 use bluejay_parser::ast::{Parse, VariableValue};
64
65 macro_rules! assert_prints {
66 ($val:literal) => {
67 let parsed = VariableValue::parse($val).unwrap();
68 assert_eq!($val, ValuePrinter::new(&parsed).to_string());
69 };
70 ($out:literal, $in:literal) => {
71 let parsed = VariableValue::parse($in).unwrap();
72 assert_eq!($out, ValuePrinter::new(&parsed).to_string());
73 };
74 }
75
76 #[test]
77 fn test_bool() {
78 assert_prints!("true");
79 assert_prints!("false");
80 }
81
82 #[test]
83 fn test_enum() {
84 assert_prints!("ONE");
85 }
86
87 #[test]
88 fn test_float() {
89 assert_prints!("1.0");
90 assert_prints!("3.14159");
91 assert_prints!("-1.23456");
92 assert_prints!("10000.0", "1e4");
93 assert_prints!("0.0");
94 }
95
96 #[test]
97 fn test_int() {
98 assert_prints!("1");
99 assert_prints!("0");
100 assert_prints!("-100");
101 }
102
103 #[test]
104 fn test_list() {
105 assert_prints!("[1, 2, 3]");
106 assert_prints!("[]");
107 assert_prints!("[[]]");
108 }
109
110 #[test]
111 fn test_null() {
112 assert_prints!("null");
113 }
114
115 #[test]
116 fn test_object() {
117 assert_prints!("{ foo: 1, bar: 2 }");
118 }
119
120 #[test]
121 fn test_string() {
122 assert_prints!(r#""""#);
123 assert_prints!(r#""\"\\/\b\n\f\r\t""#, r#""\"\\\/\b\n\f\r\t""#);
124 assert_prints!(r#""🔥""#);
125 }
126
127 #[test]
128 fn test_variable() {
129 assert_prints!("$foo");
130 }
131}