json_streaming/blocking/
json_writer.rs

1use crate::blocking::io::BlockingWrite;
2use crate::shared::*;
3use core::fmt::Display;
4use core::marker::PhantomData;
5
6/// [JsonWriter] is the starting point for serializing JSON with this library. It is a thin wrapper
7///  around a [Write], adding some JSON specifics and also formatting.
8/// 
9/// Application code should usually not have to interact with [JsonWriter] directly, but through
10///  [ObjectSer] or [ArraySer] wrapped around it.
11pub struct JsonWriter <'a, W: BlockingWrite, F: JsonFormatter, FF: FloatFormat> {
12    inner: &'a mut W,
13    formatter: F,
14    /// ending an object / array through RAII can cause an IO error that can not be propagated
15    ///  to calling code because [Drop] can not return errors. Such errors are stored in this
16    ///  field and returned from the next I/O operation.
17    ///
18    /// For this to work reliably, it is necessary to call [JsonWriter::flush()] or
19    ///  [JsonWriter::into_inner()] before it goes out of scope, in analogy to `BufWriter`'s API.
20    unreported_error: Option<W::Error>,
21    _float_format: FF,
22}
23
24impl <'a, W: BlockingWrite, F: JsonFormatter, FF: FloatFormat> JsonWriter<'a, W, F, FF> {
25    /// Create a new [JsonWriter] instance for given [Write] instance and an explicitly provided
26    ///  [JsonFormatter]. It gives full flexibility; for most cases, `new_compact()` and 
27    ///  `new_pretty()` functions are more convenient. 
28    pub fn new(inner: &'a mut W, formatter: F, float_format: FF) -> JsonWriter<'a, W, F, FF> {
29        JsonWriter {
30            inner,
31            formatter,
32            unreported_error: None,
33            _float_format: float_format,
34        }
35    }
36
37    /// Internal API for writing raw bytes to the underlying [Write].
38    pub fn write_bytes(&mut self, data: &[u8]) -> Result<(), W::Error> {
39        self.flush()?;
40        self.inner.write_all(data)
41    }
42
43    /// Internal API for writing a string as an escaped JSON string.
44    pub fn write_escaped_string(&mut self, s: &str) -> Result<(), W::Error> {
45        self.write_bytes(b"\"")?;
46        for b in s.bytes() {
47            match b {
48                b'"' => self.write_bytes(b"\\\"")?,
49                b'\\' => self.write_bytes(b"\\\\")?,
50                b'\x08' => self.write_bytes(b"\\b")?,
51                b'\x0c' => self.write_bytes(b"\\f")?,
52                b'\n' => self.write_bytes(b"\\n")?,
53                b'\r' => self.write_bytes(b"\\r")?,
54                b'\t' => self.write_bytes(b"\\t")?,
55                b if b < 0x20 => {
56                    static HEX_DIGITS: [u8; 16] = *b"0123456789abcdef";
57                    let bytes = &[
58                        b'\\',
59                        b'u',
60                        b'0',
61                        b'0',
62                        HEX_DIGITS[(b >> 4) as usize],
63                        HEX_DIGITS[(b & 0xF) as usize],
64                    ];
65                    self.write_bytes(bytes)?
66                },
67                b => self.write_bytes(&[b])?,
68            }
69        }
70        self.write_bytes(b"\"")?;
71        Ok(())
72    }
73
74    /// Internal API for writing a `bool`.
75    pub fn write_bool(&mut self, value: bool) -> Result<(), W::Error> {
76        if value {
77            self.write_bytes(b"true")
78        }
79        else {
80            self.write_bytes(b"false")
81        }
82    }
83
84    /// Internal API for writing a floating point number, representing non-finite numbers as `null`. 
85    pub fn write_f64(&mut self, value: f64) -> Result<(), W::Error> {
86
87        FormatWrapper::new(self)
88            .write_f64(value)
89    }
90
91    /// Internal API for writing a floating point number, representing non-finite numbers as `null`. 
92    pub fn write_f32(&mut self, value: f32) -> Result<(), W::Error> {
93        FormatWrapper::new(self)
94            .write_f32(value)
95    }
96
97    /// internal API for writing raw int values
98    pub fn write_raw_num(&mut self, value: impl Display) -> Result<(), W::Error> {
99        FormatWrapper::new(self)
100            .write_raw(value)
101    }
102
103    /// Internal API for interacting with the formatter
104    pub fn write_format_after_key(&mut self) -> Result<(), W::Error> {
105        self.flush()?;
106        self.inner.write_all(self.formatter.after_key().as_bytes())
107    }
108
109    /// Internal API for interacting with the formatter
110    pub fn write_format_after_start_nested(&mut self) -> Result<(), W::Error> {
111        self.flush()?;
112        self.inner.write_all(self.formatter.after_start_nested().as_bytes())
113    }
114
115    /// Internal API for interacting with the formatter
116    pub fn write_format_after_element(&mut self) -> Result<(), W::Error> {
117        self.flush()?;
118        self.inner.write_all(self.formatter.after_element().as_bytes())
119    }
120
121    /// Internal API for interacting with the formatter
122    pub fn write_format_before_end_nested(&mut self, is_empty: bool) -> Result<(), W::Error> {
123        self.flush()?;
124        self.inner.write_all(self.formatter.before_end_nested(is_empty).as_bytes())
125    }
126
127    /// Internal API for interacting with the formatter
128    pub fn write_format_indent(&mut self) -> Result<(), W::Error> {
129        self.flush()?;
130        self.inner.write_all(self.formatter.indent().as_bytes())
131    }
132
133    /// Check and return any unreported error that occurred when an object / array went out of 
134    ///  scope. Applications should call this function when serialization is complete to ensure
135    ///  that no errors get lost.    
136    pub fn flush(&mut self) -> Result<(), W::Error> {
137        if let Some(e) = self.unreported_error.take() {
138            return Err(e);
139        }
140        Ok(())
141    }
142
143    /// End this [JsonWriter]'s lifetime, returning the [Write] instance it owned. This function
144    ///  returns any unreported errors.
145    pub fn into_inner(mut self) -> Result<&'a mut W, W::Error> {
146        self.flush()?;
147        Ok(self.inner)
148    }
149
150    pub(crate) fn set_unreported_error(&mut self, unreported_error: W::Error) {
151        self.unreported_error = Some(unreported_error);
152    }
153}
154
155impl <'a, W: BlockingWrite> JsonWriter<'a, W, CompactFormatter, DefaultFloatFormat> {
156    /// Convenience factory for creating a [JsonWriter] with [CompactFormatter] and [DefaultFloatFormat]
157    pub fn new_compact(inner: &'a mut W) -> Self {
158        JsonWriter::new(inner, CompactFormatter, DefaultFloatFormat)
159    }
160}
161
162impl <'a, W: BlockingWrite> JsonWriter<'a, W, PrettyFormatter, DefaultFloatFormat> {
163    /// Convenience factory for creating a [JsonWriter] with [PrettyFormatter] and [DefaultFloatFormat]
164    pub fn new_pretty(inner: &'a mut W) -> Self {
165        JsonWriter::new(inner, PrettyFormatter::new(), DefaultFloatFormat)
166    }
167}
168
169
170struct FormatWrapper<'a, 'b, W: BlockingWrite, F: JsonFormatter, FF: FloatFormat> {
171    inner: &'a mut JsonWriter<'b, W, F, FF>,
172    cached_error: Option<W::Error>,
173    pd: PhantomData<FF>,
174}
175impl<'a, 'b, W: BlockingWrite, F: JsonFormatter, FF: FloatFormat> FormatWrapper<'a, 'b, W, F, FF> {
176    fn new(inner: &'a mut JsonWriter<'b, W, F, FF>) -> Self {
177        Self {
178            inner,
179            cached_error: None,
180            pd: PhantomData::default(),
181        }
182    }
183
184    fn write_raw(&mut self, value: impl Display) -> Result<(), W::Error> {
185        use core::fmt::Write;
186        let _ = write!(self, "{}", value);
187        match self.cached_error.take() {
188            None => Ok(()),
189            Some(e) => Err(e),
190        }
191    }
192
193    fn write_f64(&mut self, value: f64) -> Result<(), W::Error> {
194        let _ = FF::write_f64(self, value);
195        match self.cached_error.take() {
196            None => Ok(()),
197            Some(e) => Err(e),
198        }
199    }
200
201    fn write_f32(&mut self, value: f32) -> Result<(), W::Error> {
202        let _ = FF::write_f32(self, value);
203        match self.cached_error.take() {
204            None => Ok(()),
205            Some(e) => Err(e),
206        }
207    }
208}
209impl<'a, 'b, W: BlockingWrite, F: JsonFormatter, FF: FloatFormat> core::fmt::Write for FormatWrapper<'a, 'b, W, F, FF> {
210    fn write_str(&mut self, s: &str) -> core::fmt::Result {
211        match self.inner.write_bytes(s.as_bytes()) {
212            Ok(_) => {
213                Ok(())
214            }
215            Err(e) => {
216                self.cached_error = Some(e);
217                Err(core::fmt::Error)
218            }
219        }
220    }
221}
222
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227    use rstest::*;
228    use std::fmt::Write;
229    use std::io;
230
231    #[test]
232    fn test_json_writer() {
233        _test_json_writer(JsonWriter::new(&mut Vec::new(), CompactFormatter, DefaultFloatFormat));
234    }
235
236    #[test]
237    fn test_json_writer_compact() {
238        _test_json_writer(JsonWriter::new_compact(&mut Vec::new()));
239    }
240
241    #[test]
242    fn test_json_writer_pretty() {
243        _test_json_writer(JsonWriter::new_pretty(&mut Vec::new()));
244    }
245
246    fn _test_json_writer<F: JsonFormatter>(mut writer: JsonWriter<Vec<u8>, F, DefaultFloatFormat>) {
247        writer.write_bytes(b"a").unwrap();
248        writer.write_bytes(b"b").unwrap();
249        writer.write_bytes(b"cde").unwrap();
250
251        writer.flush().unwrap();
252
253        assert_eq!(as_written_string(writer), "abcde");
254    }
255
256    fn as_written_string<F: JsonFormatter>(writer: JsonWriter<Vec<u8>, F, DefaultFloatFormat>) -> String {
257        let s = writer.into_inner().unwrap();
258        String::from_utf8(s.to_vec()).unwrap()
259    }
260
261    #[rstest]
262    #[case::empty("", r#""""#)]
263    #[case::text("yo", r#""yo""#)]
264    #[case::non_ascii("äöü", r#""äöü""#)]
265    #[case::quotation_mark("\"", r#""\"""#)]
266    #[case::backquote("\\", r#""\\""#)]
267    #[case::backspace("\x08", r#""\b""#)]
268    #[case::form_feed("\x0c", r#""\f""#)]
269    #[case::line_feed("\n", r#""\n""#)]
270    #[case::carriage_return("\r", r#""\r""#)]
271    #[case::tab("\t", r#""\t""#)]
272    #[case::esc_00("\x00", r#""\u0000""#)]
273    #[case::esc_01("\x01", r#""\u0001""#)]
274    #[case::esc_02("\x02", r#""\u0002""#)]
275    #[case::esc_03("\x03", r#""\u0003""#)]
276    #[case::esc_04("\x04", r#""\u0004""#)]
277    #[case::esc_05("\x05", r#""\u0005""#)]
278    #[case::esc_06("\x06", r#""\u0006""#)]
279    #[case::esc_07("\x07", r#""\u0007""#)]
280    #[case::esc_08("\x08", r#""\b""#)]
281    #[case::esc_09("\x09", r#""\t""#)]
282    #[case::esc_0a("\x0a", r#""\n""#)]
283    #[case::esc_0b("\x0b", r#""\u000b""#)]
284    #[case::esc_0c("\x0c", r#""\f""#)]
285    #[case::esc_0d("\x0d", r#""\r""#)]
286    #[case::esc_0e("\x0e", r#""\u000e""#)]
287    #[case::esc_0f("\x0f", r#""\u000f""#)]
288    #[case::esc_10("\x10", r#""\u0010""#)]
289    #[case::esc_11("\x11", r#""\u0011""#)]
290    #[case::esc_12("\x12", r#""\u0012""#)]
291    #[case::esc_13("\x13", r#""\u0013""#)]
292    #[case::esc_14("\x14", r#""\u0014""#)]
293    #[case::esc_15("\x15", r#""\u0015""#)]
294    #[case::esc_16("\x16", r#""\u0016""#)]
295    #[case::esc_17("\x17", r#""\u0017""#)]
296    #[case::esc_18("\x18", r#""\u0018""#)]
297    #[case::esc_19("\x19", r#""\u0019""#)]
298    #[case::esc_1a("\x1a", r#""\u001a""#)]
299    #[case::esc_1b("\x1b", r#""\u001b""#)]
300    #[case::esc_1c("\x1c", r#""\u001c""#)]
301    #[case::esc_1d("\x1d", r#""\u001d""#)]
302    #[case::esc_1e("\x1e", r#""\u001e""#)]
303    #[case::esc_1f("\x1f", r#""\u001f""#)]
304    #[case::combination("asdf \n jklö \t!", r#""asdf \n jklö \t!""#)]
305    fn test_write_escaped_string(#[case] s: &str, #[case] expected: &str) {
306        let mut buf = Vec::new();
307        let mut writer = JsonWriter::new_compact(&mut buf);
308        writer.write_escaped_string(s).unwrap();
309        assert_eq!(as_written_string(writer), expected);
310    }
311
312    #[rstest]
313    #[case::bool_true(true, "true")]
314    #[case::bool_false(false, "false")]
315    fn test_write_bool(#[case] b: bool, #[case] expected: &str) {
316        let mut buf = Vec::new();
317        let mut writer = JsonWriter::new_compact(&mut buf);
318        writer.write_bool(b).unwrap();
319        assert_eq!(as_written_string(writer), expected);
320    }
321
322    #[rstest]
323    #[case::simple(2.0, "2")]
324    #[case::exp_5(1.234e5, "123400")]
325    #[case::exp_10(1.234e10, "1.234e10")]
326    #[case::exp_20(1.234e20, "1.234e20")]
327    #[case::exp_neg_3(1.234e-3, "0.001234")]
328    #[case::exp_neg_10(1.234e-10, "1.234e-10")]
329    #[case::neg_simple(-2.0, "-2")]
330    #[case::neg_exp_5(-1.234e5, "-123400")]
331    #[case::neg_exp_10(-1.234e10, "-1.234e10")]
332    #[case::neg_exp_20(-1.234e20, "-1.234e20")]
333    #[case::neg_exp_neg_3(-1.234e-3, "-0.001234")]
334    #[case::neg_exp_neg_10(-1.234e-10, "-1.234e-10")]
335    #[case::inf(f64::INFINITY, "null")]
336    #[case::neg_inf(f64::NEG_INFINITY, "null")]
337    #[case::nan(f64::NAN, "null")]
338    fn test_write_f64(#[case] value: f64, #[case] expected: &str) {
339        let mut buf = Vec::new();
340        let mut writer = JsonWriter::new_compact(&mut buf);
341        writer.write_f64(value).unwrap();
342        assert_eq!(as_written_string(writer), expected);
343    }
344
345    #[rstest]
346    #[case::simple(2.0, "2")]
347    #[case::exp_5(1.234e5, "123400")]
348    #[case::exp_10(1.234e10, "1.234e10")]
349    #[case::exp_20(1.234e20, "1.234e20")]
350    #[case::exp_neg_3(1.234e-3, "0.001234")]
351    #[case::exp_neg_10(1.234e-10, "1.234e-10")]
352    #[case::neg_simple(-2.0, "-2")]
353    #[case::neg_exp_5(-1.234e5, "-123400")]
354    #[case::neg_exp_10(-1.234e10, "-1.234e10")]
355    #[case::neg_exp_20(-1.234e20, "-1.234e20")]
356    #[case::neg_exp_neg_3(-1.234e-3, "-0.001234")]
357    #[case::neg_exp_neg_10(-1.234e-10, "-1.234e-10")]
358    #[case::inf(f32::INFINITY, "null")]
359    #[case::neg_inf(f32::NEG_INFINITY, "null")]
360    #[case::nan(f32::NAN, "null")]
361    fn test_write_f32(#[case] value: f32, #[case] expected: &str) {
362        let mut buf = Vec::new();
363        let mut writer = JsonWriter::new_compact(&mut buf);
364        writer.write_f32(value).unwrap();
365        assert_eq!(as_written_string(writer), expected);
366    }
367
368    #[test]
369    fn test_set_reported_error() {
370        let mut buf = Vec::new();
371        let mut writer = JsonWriter::new_compact(&mut buf);
372        writer.write_bytes(b"yo").unwrap();
373
374        writer.set_unreported_error(io::Error::new(io::ErrorKind::Other, "something went wrong"));
375        match writer.write_bytes(b" after error") {
376            Ok(_) => {
377                panic!("previous error should have been returned");
378            }
379            Err(e) => {
380                assert_eq!(e.kind(), io::ErrorKind::Other);
381                assert_eq!(e.to_string(), "something went wrong");
382            },
383        }
384
385        assert_eq!(as_written_string(writer), "yo");
386    }
387
388    #[rstest]
389    fn test_float_format() {
390        struct OtherFf;
391        impl FloatFormat for OtherFf {
392            fn write_f64(f: &mut impl Write, value: f64) -> std::fmt::Result {
393                write!(f, "_{}_64", value)
394            }
395
396            fn write_f32(f: &mut impl Write, value: f32) -> std::fmt::Result {
397                write!(f, "_{}_32", value)
398            }
399        }
400
401        let mut buf = Vec::new();
402        let mut writer = JsonWriter::new(&mut buf, CompactFormatter, OtherFf);
403        writer.write_f64(1.2).unwrap();
404        writer.write_f32(3.4).unwrap();
405        assert_eq!(&buf, b"_1.2_64_3.4_32");
406    }
407
408    #[test]
409    fn test_flush() {
410        let mut buf = Vec::new();
411        let mut writer = JsonWriter::new_compact(&mut buf);
412        writer.write_bytes(b"yo").unwrap();
413
414        writer.set_unreported_error(io::Error::new(io::ErrorKind::Other, "something went wrong"));
415
416        match writer.flush() {
417            Ok(_) => {
418                panic!("previous error should have been returned");
419            }
420            Err(e) => {
421                assert_eq!(e.kind(), io::ErrorKind::Other);
422                assert_eq!(e.to_string(), "something went wrong");
423            },
424        }
425
426        assert_eq!(as_written_string(writer), "yo");
427    }
428}