1use std::fmt;
2
3#[derive(Debug, PartialEq, Eq)]
4pub(crate) enum SerializerError {
5    InvalidKey,
6    FmtError,
7}
8
9impl From<std::fmt::Error> for SerializerError {
10    fn from(_: std::fmt::Error) -> Self {
11        SerializerError::FmtError
12    }
13}
14
15pub(crate) struct Serializer<W> {
17    pub(crate) writer: W,
18    writing_first_entry: bool,
19    #[cfg(feature = "ansi_logs")]
20    with_ansi_color: bool,
21}
22
23impl<W> Serializer<W>
24where
25    W: fmt::Write,
26{
27    #[inline]
28    pub(crate) fn new(writer: W, #[cfg(feature = "ansi_logs")] with_ansi_color: bool) -> Self {
29        Serializer {
30            writer,
31            writing_first_entry: true,
32            #[cfg(feature = "ansi_logs")]
33            with_ansi_color,
34        }
35    }
36
37    #[cfg(not(feature = "ansi_logs"))]
38    pub(crate) fn serialize_entry(
39        &mut self,
40        key: &str,
41        value: &str,
42    ) -> Result<(), SerializerError> {
43        self.serialize_entry_with(key, value, |this, value| this.serialize_value(value))
44    }
45
46    #[cfg(feature = "ansi_logs")]
47    pub(crate) fn serialize_entry(
48        &mut self,
49        key: &str,
50        value: &str,
51    ) -> Result<(), SerializerError> {
52        if let "level" = key {
53            self.serialize_entry_with(key, value, |this, value| this.serialize_level(value))
54        } else {
55            self.serialize_entry_with(key, value, |this, value| this.serialize_value(value))
56        }
57    }
58
59    pub(crate) fn serialize_entry_no_quote(
60        &mut self,
61        key: &str,
62        value: impl fmt::Debug,
63    ) -> Result<(), SerializerError> {
64        self.serialize_entry_with(key, value, |this, value| {
65            this.serialize_value_no_quote(value)
66        })
67    }
68
69    fn serialize_entry_with<F, T>(
70        &mut self,
71        key: &str,
72        value: T,
73        serialize_value: F,
74    ) -> Result<(), SerializerError>
75    where
76        F: FnOnce(&mut Self, T) -> Result<(), SerializerError>,
77    {
78        self.serialize_key(key)?;
79        self.writer.write_char('=')?;
80        serialize_value(self, value)?;
81
82        Ok(())
83    }
84    pub(crate) fn serialize_key(&mut self, key: &str) -> Result<(), SerializerError> {
85        if !self.writing_first_entry {
86            self.writer.write_char(' ')?;
87        }
88        self.writing_first_entry = false;
89
90        let mut chars = key.chars().filter(|&ch| !need_quote(ch)).peekable();
91
92        if chars.peek().is_none() {
93            return Err(SerializerError::InvalidKey);
94        }
95
96        #[cfg(not(feature = "ansi_logs"))]
97        {
98            for c in chars {
99                self.writer.write_char(c)?;
100            }
101        }
102
103        #[cfg(feature = "ansi_logs")]
104        {
105            if self.with_ansi_color {
106                let mut s = String::new();
107                for c in chars {
108                    s.push(c);
109                }
110                self.writer.write_str(
111                    &nu_ansi_term::Color::Rgb(109, 139, 140)
112                        .bold()
113                        .paint(s)
114                        .to_string(),
115                )?;
116            } else {
117                for c in chars {
118                    self.writer.write_char(c)?;
119                }
120            }
121        }
122        Ok(())
123    }
124
125    pub(crate) fn serialize_value(&mut self, value: &str) -> Result<(), SerializerError> {
126        if value.chars().any(need_quote) {
127            self.writer.write_char('"')?;
128            write!(self.writer, "{}", value.escape_debug())?;
129            self.writer.write_char('"')?;
130        } else {
131            self.writer.write_str(value)?;
132        }
133
134        Ok(())
135    }
136
137    fn serialize_value_no_quote(&mut self, value: impl fmt::Debug) -> Result<(), SerializerError> {
138        write!(self.writer, "{:?}", value)?;
139        Ok(())
140    }
141
142    #[cfg(feature = "ansi_logs")]
143    fn serialize_level(&mut self, value: &str) -> Result<(), SerializerError> {
144        write!(self.writer, "{}", value)?;
145        Ok(())
146    }
147}
148
149#[inline]
150pub(crate) fn need_quote(ch: char) -> bool {
151    ch <= ' ' || matches!(ch, '=' | '"')
152}
153
154impl<W> std::io::Write for Serializer<W>
155where
156    W: fmt::Write,
157{
158    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
159        if let Ok(buf) = std::str::from_utf8(buf) {
160            self.writer
161                .write_str(buf)
162                .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?;
163        }
164        Ok(buf.len())
165    }
166
167    fn flush(&mut self) -> std::io::Result<()> {
168        Ok(())
169    }
170}
171
172#[cfg(test)]
173mod tests {
174    use super::*;
175
176    #[test]
177    #[cfg(not(feature = "ansi_logs"))]
178    fn test_serialize_entries() {
179        let mut output = String::new();
180        let mut s = Serializer::new(&mut output);
181        assert!(s.serialize_entry("key", "value").is_ok());
182        assert!(s.serialize_entry("key2", "value2").is_ok());
183
184        assert_eq!(output, "key=value key2=value2");
185    }
186
187    #[test]
188    #[cfg(not(feature = "ansi_logs"))]
189    fn test_serialize_entry() {
190        let tests = vec![
191            (("key", "value"), "key=value"),
192            (("ke=y", "value="), "key=\"value=\""),
193            (("key ", "value "), "key=\"value \""),
194            (("ke\"y", "valu\"e"), "key=\"valu\\\"e\""),
195            (("ke\ny", "valu\ne"), "key=\"valu\\ne\""),
196        ];
197
198        for ((k, v), expected_output) in tests {
199            let mut output = String::new();
200            let mut s = Serializer::new(&mut output);
201            assert!(s.serialize_entry(k, v).is_ok());
202            assert_eq!(output, expected_output,);
203        }
204    }
205
206    #[test]
207    #[cfg(feature = "ansi_logs")]
208    fn test_serialize_entry() {
209        let tests = vec![
210            (("key", "value"), make_ansi_key_value("key", "=value")),
211            (
212                ("ke=y", "value="),
213                make_ansi_key_value("key", "=\"value=\""),
214            ),
215            (
216                ("key ", "value "),
217                make_ansi_key_value("key", "=\"value \""),
218            ),
219            (("lev\"el", "info"), make_ansi_key_value("level", "=info")),
220            (
221                ("ke\ny", "valu\ne"),
222                make_ansi_key_value("key", "=\"valu\\ne\""),
223            ),
224        ];
225
226        for ((k, v), expected_output) in tests {
227            let mut output = String::new();
228            let mut s = Serializer::new(&mut output, true);
229            assert!(s.serialize_entry(k, v).is_ok());
230            assert_eq!(output, expected_output,);
231        }
232
233        fn make_ansi_key_value(key: &str, value: &str) -> String {
234            let mut key = nu_ansi_term::Color::Rgb(109, 139, 140)
235                .bold()
236                .paint(key)
237                .to_string();
238            key.push_str(value);
239            key
240        }
241    }
242
243    #[test]
244    #[cfg(not(feature = "ansi_logs"))]
245    fn test_serialize_key() {
246        let tests = vec![
247            ("key", "key"),
248            ("k ey", "key"),
249            ("k\"ey", "key"),
250            ("k=ey", "key"),
251            ("k\ney", "key"),
252        ];
253        for (input, expected_output) in tests {
254            let mut output = String::new();
255
256            let mut s = Serializer::new(&mut output);
257            assert!(s.serialize_key(input).is_ok());
258
259            assert_eq!(output, expected_output);
260        }
261    }
262
263    #[test]
264    fn test_serialize_key_invalid() {
265        let tests = vec![
266            ("", SerializerError::InvalidKey),
267            (" ", SerializerError::InvalidKey),
268            ("=", SerializerError::InvalidKey),
269            ("\"", SerializerError::InvalidKey),
270        ];
271
272        for (input, expected_error) in tests {
273            let mut output = String::new();
274
275            #[cfg(not(feature = "ansi_logs"))]
276            let mut s = Serializer::new(&mut output);
277            #[cfg(feature = "ansi_logs")]
278            let mut s = Serializer::new(&mut output, true);
279            assert_eq!(s.serialize_key(input), Err(expected_error));
280        }
281    }
282
283    #[test]
284    fn test_serialize_value() {
285        let tests = vec![
286            ("", ""),
287            ("v", "v"),
288            (" ", r#"" ""#),
289            ("=", r#""=""#),
290            (r#"\"#, r#"\"#),
291            (r#"""#, r#""\"""#),
292            (r#"\""#, r#""\\\"""#),
293            ("\n", r#""\n""#),
294            ("\x00", r#""\0""#),
295            ("\x10", r#""\u{10}""#),
296            ("\x1F", r#""\u{1f}""#),
297            ("µ", r#"µ"#),
298            ("åäö", r#"åäö"#),
299        ];
300
301        for (input, expected_output) in tests {
302            let mut output = String::new();
303
304            #[cfg(not(feature = "ansi_logs"))]
305            let mut s = Serializer::new(&mut output);
306            #[cfg(feature = "ansi_logs")]
307            let mut s = Serializer::new(&mut output, true);
308
309            assert!(s.serialize_value(input).is_ok());
310
311            assert_eq!(output, expected_output);
312        }
313    }
314}