json_streaming/nonblocking/
json_writer.rs

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