bluejay_printer/
value.rs

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}