Skip to main content

tabnas_render/
json.rs

1//! `JsonEvents/1` as JSON text.
2//!
3//! The renderer writes what it is given, in the order it is given, with
4//! nothing held back but the separators: a comma is written when the next
5//! item begins, never speculatively, so an aborted document is still a
6//! prefix of a valid one. Compact output is the standard profile; a fixed
7//! indent is a separate profile for people rather than programs, and the
8//! two differ only in whitespace. Strings are escaped as RFC 8259 requires
9//! and no more: `"`, `\`, and the control characters, with everything else,
10//! non-ASCII included, written as itself, because the output is UTF-8 and
11//! an escape would only make it longer.
12//!
13//! The renderer validates the event sequence as it goes, because a
14//! third-party source is as much a source of `JsonEvents/1` as the
15//! standard ones are: one root value, keys only where a member begins,
16//! balanced containers, one end.
17
18use tabnas_transduce::{Fail, Flow, JsonEvent, Number, Sink};
19
20use crate::number::{check_number, write_value};
21use crate::text::TextOut;
22
23/// The JSON profile.
24#[derive(Clone, Debug, Default, PartialEq, Eq)]
25pub struct JsonOptions {
26    /// Spaces per nesting level, with a newline before every item and
27    /// every closing bracket of a non-empty container. `None` or `Some(0)`
28    /// is compact: no whitespace at all.
29    pub indent: Option<usize>,
30    /// Write a newline after the root value, at `End`.
31    pub trailing_newline: bool,
32}
33
34#[derive(Clone, Copy, Debug, PartialEq, Eq)]
35enum Frame {
36    Object { first: bool, expecting_key: bool },
37    Array { first: bool },
38}
39
40/// Renders `JsonEvents/1` as JSON text.
41///
42/// Exactly one root value, then `End`; a second root, an `End` before the
43/// root or with a container open, a key outside an object or where a value
44/// is due, a value where a key is due, an unbalanced or mismatched close,
45/// and any event after `End` are `PROTOCOL_ORDER_ERROR`. Numbers write
46/// their lexeme when it is a JSON number (`INVALID_NUMBER` otherwise) and
47/// the shortest text that reads back as the value when there is none; NaN
48/// and infinity have no JSON form and are `TARGET_VALUE_UNREPRESENTABLE`,
49/// whatever lexeme stands beside them. A number is checked before its
50/// separator is written, so a rejected value leaves no trace. The output
51/// is flushed once, at `End`; a failure found after any text was written
52/// says so with `committed_output`.
53pub struct JsonRenderer<O: TextOut> {
54    out: O,
55    options: JsonOptions,
56    /// Spaces per level; zero is compact.
57    indent: usize,
58    stack: Vec<Frame>,
59    root_done: bool,
60    ended: bool,
61    emitted: bool,
62    scratch: String,
63    /// Spaces, grown to the widest indentation written so far.
64    pad: String,
65}
66
67impl<O: TextOut> JsonRenderer<O> {
68    pub fn new(out: O, options: JsonOptions) -> Self {
69        JsonRenderer {
70            indent: options.indent.unwrap_or(0),
71            out,
72            options,
73            stack: Vec::new(),
74            root_done: false,
75            ended: false,
76            emitted: false,
77            scratch: String::new(),
78            pad: String::new(),
79        }
80    }
81
82    pub fn options(&self) -> &JsonOptions {
83        &self.options
84    }
85
86    /// Containers currently open.
87    pub fn depth(&self) -> usize {
88        self.stack.len()
89    }
90
91    /// Whether `End` has been rendered.
92    pub fn is_done(&self) -> bool {
93        self.ended
94    }
95
96    pub fn into_inner(self) -> O {
97        self.out
98    }
99
100    /// Mark a failure as leaving partial output when text this renderer
101    /// wrote has reached the destination; text still buffered in the
102    /// output has not, and the output knows which.
103    fn fail(&self, f: Fail) -> Fail {
104        if self.emitted && self.out.has_committed() {
105            f.committed()
106        } else {
107            f
108        }
109    }
110
111    fn protocol(&self, message: &str) -> Fail {
112        self.fail(Fail::protocol(message))
113    }
114
115    fn put(&mut self, s: &str) -> Result<(), Fail> {
116        self.emitted = true;
117        self.out.write_str(s)
118    }
119
120    /// The escaped form of `s`, streamed: each run that needs no escaping
121    /// is written as it is and each escape as it comes, so the renderer
122    /// never holds a copy of a scalar. Building the escaped text first would
123    /// keep up to six bytes per byte of the largest string seen for the
124    /// renderer's whole life, against the promise that nothing here holds a
125    /// document.
126    fn put_string(&mut self, s: &str) -> Result<(), Fail> {
127        self.put("\"")?;
128        let mut rest = s;
129        while let Some((i, width, escaped)) = rest
130            .char_indices()
131            .find_map(|(i, c)| escape(c).map(|e| (i, c.len_utf8(), e)))
132        {
133            if i > 0 {
134                self.put(&rest[..i])?;
135            }
136            self.put(escaped)?;
137            rest = &rest[i + width..];
138        }
139        if !rest.is_empty() {
140            self.put(rest)?;
141        }
142        self.put("\"")
143    }
144
145    /// Write a number that [`check_number`] has passed: the lexeme as it
146    /// is, or the value formatted once into the reused scratch buffer.
147    fn put_number(&mut self, n: Number<'_>) -> Result<(), Fail> {
148        match n.lexeme {
149            Some(l) => self.put(l),
150            None => {
151                self.emitted = true;
152                self.out.write_str(write_value(n.value, &mut self.scratch))
153            }
154        }
155    }
156
157    /// A line break and the indentation of `depth` levels; nothing when
158    /// compact.
159    fn break_line(&mut self, depth: usize) -> Result<(), Fail> {
160        if self.indent == 0 {
161            return Ok(());
162        }
163        let width = depth.saturating_mul(self.indent);
164        while self.pad.len() < width {
165            self.pad.push(' ');
166        }
167        let pad = std::mem::take(&mut self.pad);
168        self.put("\n")?;
169        // `pad` is ASCII spaces at least `width` long, so the slice is on a
170        // char boundary and within bounds.
171        let r = self.put(&pad[..width]);
172        self.pad = pad;
173        r
174    }
175
176    /// The separators before a value, and the check that one may begin.
177    fn begin_value(&mut self) -> Result<(), Fail> {
178        if self.ended {
179            return Err(self.protocol("a value after the end"));
180        }
181        let depth = self.stack.len();
182        match self.stack.last_mut() {
183            None if self.root_done => Err(self.protocol("a second root value")),
184            None => Ok(()),
185            Some(Frame::Object {
186                expecting_key: true,
187                ..
188            }) => Err(self.protocol("a value where a key is due")),
189            Some(Frame::Object { .. }) => Ok(()),
190            Some(Frame::Array { first }) => {
191                let comma = !*first;
192                *first = false;
193                if comma {
194                    self.put(",")?;
195                }
196                self.break_line(depth)
197            }
198        }
199    }
200
201    /// Bookkeeping after a whole value.
202    fn end_value(&mut self) {
203        match self.stack.last_mut() {
204            None => self.root_done = true,
205            Some(Frame::Object { expecting_key, .. }) => *expecting_key = true,
206            Some(Frame::Array { .. }) => {}
207        }
208    }
209
210    fn key(&mut self, k: &str) -> Result<(), Fail> {
211        if self.ended {
212            return Err(self.protocol("a key after the end"));
213        }
214        let depth = self.stack.len();
215        match self.stack.last_mut() {
216            Some(Frame::Object {
217                first,
218                expecting_key: true,
219            }) => {
220                let comma = !*first;
221                *first = false;
222                if comma {
223                    self.put(",")?;
224                }
225                self.break_line(depth)?;
226                self.put_string(k)?;
227                self.put(if self.indent > 0 { ": " } else { ":" })?;
228                // Only after the key is on the wire, so a write failure
229                // cannot leave the frame half updated.
230                if let Some(Frame::Object { expecting_key, .. }) = self.stack.last_mut() {
231                    *expecting_key = false;
232                }
233                Ok(())
234            }
235            Some(Frame::Object { .. }) => Err(self.protocol("a key where a value is due")),
236            Some(Frame::Array { .. }) => Err(self.protocol("a key inside an array")),
237            None => Err(self.protocol("a key outside an object")),
238        }
239    }
240
241    fn start(&mut self, open: &str, frame: Frame) -> Result<(), Fail> {
242        self.begin_value()?;
243        self.put(open)?;
244        self.stack.push(frame);
245        Ok(())
246    }
247
248    fn close_object(&mut self) -> Result<(), Fail> {
249        if self.ended {
250            return Err(self.protocol("an object end after the end"));
251        }
252        let first = match self.stack.last() {
253            Some(Frame::Object {
254                expecting_key: false,
255                ..
256            }) => return Err(self.protocol("an object ended after a key with no value")),
257            Some(Frame::Object { first, .. }) => *first,
258            Some(Frame::Array { .. }) => return Err(self.protocol("an object end inside an array")),
259            None => return Err(self.protocol("an object end with no open object")),
260        };
261        self.stack.pop();
262        if !first {
263            self.break_line(self.stack.len())?;
264        }
265        self.put("}")?;
266        self.end_value();
267        Ok(())
268    }
269
270    fn close_array(&mut self) -> Result<(), Fail> {
271        if self.ended {
272            return Err(self.protocol("an array end after the end"));
273        }
274        let first = match self.stack.last() {
275            Some(Frame::Array { first }) => *first,
276            Some(Frame::Object { .. }) => {
277                return Err(self.protocol("an array end inside an object"))
278            }
279            None => return Err(self.protocol("an array end with no open array")),
280        };
281        self.stack.pop();
282        if !first {
283            self.break_line(self.stack.len())?;
284        }
285        self.put("]")?;
286        self.end_value();
287        Ok(())
288    }
289
290    fn scalar(&mut self, ev: JsonEvent<'_>) -> Result<(), Fail> {
291        // Before the separator: a number that will be refused must leave
292        // nothing behind, or a caller that carries on after the failure
293        // would find `[1,,2]` in the output.
294        if let JsonEvent::Number(n) = ev {
295            check_number(n.value, n.lexeme).map_err(|f| self.fail(f))?;
296        }
297        self.begin_value()?;
298        match ev {
299            JsonEvent::Null => self.put("null")?,
300            JsonEvent::Bool(true) => self.put("true")?,
301            JsonEvent::Bool(false) => self.put("false")?,
302            JsonEvent::Number(n) => self.put_number(n)?,
303            JsonEvent::String(s) => self.put_string(s)?,
304            // `scalar` is called for the four scalar events only.
305            _ => return Err(self.protocol("not a scalar")),
306        }
307        self.end_value();
308        Ok(())
309    }
310
311    fn end(&mut self) -> Result<(), Fail> {
312        if self.ended {
313            return Err(self.protocol("a second end"));
314        }
315        if !self.stack.is_empty() {
316            return Err(self.protocol(&format!(
317                "the end with {} open container(s)",
318                self.stack.len()
319            )));
320        }
321        if !self.root_done {
322            return Err(self.protocol("the end before a root value"));
323        }
324        if self.options.trailing_newline {
325            self.put("\n")?;
326        }
327        // Ended only once the flush has succeeded: a document whose last
328        // bytes never reached the writer is not done, whatever `End` said.
329        self.out.flush()?;
330        self.ended = true;
331        Ok(())
332    }
333}
334
335/// The `\u00XX` forms of the control characters, the short escapes RFC 8259
336/// names among them, indexed by code point.
337const CONTROL: [&str; 32] = [
338    "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b",
339    "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012",
340    "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a",
341    "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f",
342];
343
344/// The escape RFC 8259 requires for `c`, or `None` when the character is
345/// written as itself: `"`, `\` and the control characters, and no more,
346/// because the output is UTF-8 and an escape would only make it longer.
347fn escape(c: char) -> Option<&'static str> {
348    match c {
349        '"' => Some("\\\""),
350        '\\' => Some("\\\\"),
351        // Below 0x20 the index is within the table; `get` says so without
352        // a panic path.
353        c if (c as u32) < 0x20 => CONTROL.get(c as usize).copied(),
354        _ => None,
355    }
356}
357
358impl<O: TextOut> Sink for JsonRenderer<O> {
359    fn event(&mut self, ev: JsonEvent<'_>) -> Result<Flow, Fail> {
360        match ev {
361            JsonEvent::ObjectStart => self.start(
362                "{",
363                Frame::Object {
364                    first: true,
365                    expecting_key: true,
366                },
367            )?,
368            JsonEvent::ArrayStart => self.start("[", Frame::Array { first: true })?,
369            JsonEvent::ObjectEnd => self.close_object()?,
370            JsonEvent::ArrayEnd => self.close_array()?,
371            JsonEvent::Key(k) => self.key(k)?,
372            JsonEvent::Null | JsonEvent::Bool(_) | JsonEvent::Number(_) | JsonEvent::String(_) => {
373                self.scalar(ev)?
374            }
375            JsonEvent::End => self.end()?,
376        }
377        Ok(Flow::Continue)
378    }
379}
380
381#[cfg(test)]
382mod tests {
383    use super::*;
384    use crate::text::{StringOut, WriteOut};
385    use tabnas_transduce::Code;
386    use JsonEvent::*;
387
388    fn num(lexeme: &str) -> JsonEvent<'_> {
389        Number(tabnas_transduce::Number::with_lexeme(
390            lexeme.parse().unwrap_or(0.0),
391            lexeme,
392        ))
393    }
394
395    fn value(v: f64) -> JsonEvent<'static> {
396        Number(tabnas_transduce::Number::new(v))
397    }
398
399    fn render(options: JsonOptions, events: &[JsonEvent<'_>]) -> Result<std::string::String, Fail> {
400        let mut r = JsonRenderer::new(StringOut::new(), options);
401        for ev in events {
402            r.event(*ev)?;
403        }
404        Ok(r.into_inner().into_string())
405    }
406
407    fn compact(events: &[JsonEvent<'_>]) -> Result<std::string::String, Fail> {
408        render(JsonOptions::default(), events)
409    }
410
411    fn indented(n: usize, events: &[JsonEvent<'_>]) -> std::string::String {
412        render(
413            JsonOptions {
414                indent: Some(n),
415                trailing_newline: false,
416            },
417            events,
418        )
419        .unwrap()
420    }
421
422    const DOC: &[JsonEvent<'static>] = &[
423        ObjectStart,
424        Key("a"),
425        ArrayStart,
426        Number(tabnas_transduce::Number {
427            value: 1.0,
428            lexeme: Some("1"),
429        }),
430        Number(tabnas_transduce::Number {
431            value: 2.5,
432            lexeme: None,
433        }),
434        String("x"),
435        Bool(true),
436        Null,
437        ArrayEnd,
438        Key("b"),
439        ObjectStart,
440        ObjectEnd,
441        Key("c"),
442        ArrayStart,
443        ArrayEnd,
444        Key("d"),
445        ObjectStart,
446        Key("e"),
447        Bool(false),
448        ObjectEnd,
449        ObjectEnd,
450        End,
451    ];
452
453    #[test]
454    fn compact_output_has_no_whitespace() {
455        assert_eq!(
456            compact(DOC).unwrap(),
457            r#"{"a":[1,2.5,"x",true,null],"b":{},"c":[],"d":{"e":false}}"#
458        );
459    }
460
461    #[test]
462    fn an_indent_writes_fixed_nesting_and_keeps_empty_containers_on_one_line() {
463        assert_eq!(
464            indented(2, DOC),
465            "{\n  \"a\": [\n    1,\n    2.5,\n    \"x\",\n    true,\n    null\n  ],\n  \"b\": {},\n  \"c\": [],\n  \"d\": {\n    \"e\": false\n  }\n}"
466        );
467        assert_eq!(
468            indented(4, &[ArrayStart, ArrayStart, Null, ArrayEnd, ArrayEnd, End]),
469            "[\n    [\n        null\n    ]\n]"
470        );
471    }
472
473    #[test]
474    fn an_indent_of_zero_is_compact() {
475        assert_eq!(indented(0, DOC), compact(DOC).unwrap());
476    }
477
478    #[test]
479    fn the_trailing_newline_is_written_at_end_when_asked() {
480        let options = JsonOptions {
481            indent: None,
482            trailing_newline: true,
483        };
484        assert_eq!(render(options, &[Null, End]).unwrap(), "null\n");
485        assert_eq!(compact(&[Null, End]).unwrap(), "null");
486    }
487
488    #[test]
489    fn a_root_scalar_is_a_document() {
490        assert_eq!(compact(&[String("x"), End]).unwrap(), "\"x\"");
491        assert_eq!(compact(&[num("-0.5e3"), End]).unwrap(), "-0.5e3");
492        assert_eq!(compact(&[Bool(false), End]).unwrap(), "false");
493    }
494
495    #[test]
496    fn strings_are_escaped_as_rfc_8259_requires_and_no_more() {
497        let text =
498            "q\" b\\ n\n r\r t\t bs\u{8} ff\u{c} nul\0 c1\u{1} us\u{1f} del\u{7f} é 日本 🚀 /";
499        assert_eq!(
500            compact(&[String(text), End]).unwrap(),
501            "\"q\\\" b\\\\ n\\n r\\r t\\t bs\\b ff\\f nul\\u0000 c1\\u0001 us\\u001f del\u{7f} é 日本 🚀 /\""
502        );
503        assert_eq!(
504            compact(&[ObjectStart, Key("k\"\n"), Null, ObjectEnd, End]).unwrap(),
505            "{\"k\\\"\\n\":null}"
506        );
507    }
508
509    /// A `TextOut` that keeps every fragment apart, so streaming is
510    /// observable.
511    #[derive(Default)]
512    struct Fragments(Vec<std::string::String>);
513
514    impl TextOut for Fragments {
515        fn write_str(&mut self, s: &str) -> Result<(), Fail> {
516            self.0.push(s.to_owned());
517            Ok(())
518        }
519
520        fn flush(&mut self) -> Result<(), Fail> {
521            Ok(())
522        }
523    }
524
525    #[test]
526    fn strings_escape_exactly_as_transduce_does() {
527        let mut every_control = std::string::String::new();
528        for c in 0u32..0x20 {
529            every_control.push(char::from_u32(c).unwrap_or(' '));
530            every_control.push('x');
531        }
532        for text in [
533            "",
534            "plain",
535            "\"",
536            "\\",
537            "\"\\\"\\",
538            "a\"b\\c\nd",
539            every_control.as_str(),
540            "é 日本 🚀 \u{7f} \u{80} \u{2028} \u{ffff}",
541            "ends with control \u{1}",
542            "\u{1} starts with control",
543        ] {
544            let mut want = std::string::String::new();
545            tabnas_transduce::write_json_string(text, &mut want);
546            assert_eq!(compact(&[String(text), End]).unwrap(), want, "{text:?}");
547        }
548    }
549
550    #[test]
551    fn strings_are_streamed_in_runs_and_never_copied_whole() {
552        let mut r = JsonRenderer::new(Fragments::default(), JsonOptions::default());
553        r.event(String("ab\"cd\n\u{1}ef")).unwrap();
554        assert_eq!(
555            r.out.0,
556            ["\"", "ab", "\\\"", "cd", "\\n", "\\u0001", "ef", "\""]
557        );
558        // A long string of control characters, six bytes of output each,
559        // leaves nothing behind in the renderer.
560        let big = "\u{1}".repeat(64 * 1024);
561        let mut r = JsonRenderer::new(StringOut::new(), JsonOptions::default());
562        r.event(String(&big)).unwrap();
563        assert_eq!(r.out.as_str().len(), big.len() * 6 + 2);
564        assert_eq!(r.scratch.capacity(), 0, "strings do not touch the scratch");
565    }
566
567    #[test]
568    fn numbers_keep_their_lexeme_or_take_the_shortest_form() {
569        let events = [
570            ArrayStart,
571            num("1.00"),
572            num("123456789012345678901234567890"),
573            num("-0"),
574            num("1E+2"),
575            value(0.0),
576            value(1e21),
577            value(0.1),
578            value(-2.0),
579            ArrayEnd,
580            End,
581        ];
582        assert_eq!(
583            compact(&events).unwrap(),
584            "[1.00,123456789012345678901234567890,-0,1E+2,0,1e21,0.1,-2]"
585        );
586        assert_eq!(
587            compact(&[
588                ArrayStart,
589                value(1e300),
590                value(1e-300),
591                value(1.5e17),
592                value(1e20),
593                ArrayEnd,
594                End
595            ])
596            .unwrap(),
597            "[1e300,1e-300,150000000000000000,100000000000000000000]"
598        );
599    }
600
601    #[test]
602    fn a_lexeme_that_is_not_a_json_number_is_invalid_number() {
603        for bad in ["1.", "01", "NaN", "+1", "0x1"] {
604            let err = compact(&[ArrayStart, num(bad), ArrayEnd, End]).unwrap_err();
605            assert_eq!(err.code, Code::InvalidNumber, "{bad:?}");
606            assert!(err.committed_output);
607        }
608        let err = compact(&[num("1."), End]).unwrap_err();
609        assert!(!err.committed_output);
610    }
611
612    #[test]
613    fn nan_and_infinity_are_unrepresentable() {
614        for v in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
615            let err = compact(&[value(v), End]).unwrap_err();
616            assert_eq!(err.code, Code::TargetValueUnrepresentable);
617        }
618    }
619
620    #[test]
621    fn an_overflowed_lexeme_is_unrepresentable_too() {
622        // "1e999" is a JSON number by grammar, but the value beside it is
623        // infinity and a reader of the text would refuse it; the crate's
624        // own oracle (serde_json) does. Nothing is written for it.
625        let overflowed = Number(tabnas_transduce::Number::with_lexeme(
626            f64::INFINITY,
627            "1e999",
628        ));
629        let mut r = JsonRenderer::new(StringOut::new(), JsonOptions::default());
630        r.event(ArrayStart).unwrap();
631        r.event(num("1")).unwrap();
632        let err = r.event(overflowed).unwrap_err();
633        assert_eq!(err.code, Code::TargetValueUnrepresentable);
634        assert!(err.committed_output);
635        assert_eq!(r.out.as_str(), "[1");
636        let err = compact(&[overflowed, End]).unwrap_err();
637        assert_eq!(err.code, Code::TargetValueUnrepresentable);
638        assert!(!err.committed_output);
639    }
640
641    #[test]
642    fn a_rejected_number_leaves_no_separator_behind() {
643        let mut r = JsonRenderer::new(StringOut::new(), JsonOptions::default());
644        for ev in [ArrayStart, num("1")] {
645            r.event(ev).unwrap();
646        }
647        assert_eq!(r.event(num("01")).unwrap_err().code, Code::InvalidNumber);
648        assert_eq!(r.out.as_str(), "[1");
649        assert_eq!(
650            r.event(value(f64::NAN)).unwrap_err().code,
651            Code::TargetValueUnrepresentable
652        );
653        assert_eq!(r.out.as_str(), "[1");
654        // A caller that carries on regardless still gets a document.
655        for ev in [value(2.0), ArrayEnd, End] {
656            r.event(ev).unwrap();
657        }
658        assert_eq!(r.into_inner().as_str(), "[1,2]");
659    }
660
661    fn protocol_error(events: &[JsonEvent<'_>]) -> Fail {
662        let err = compact(events).unwrap_err();
663        assert_eq!(err.code, Code::ProtocolOrderError, "{events:?}");
664        err
665    }
666
667    #[test]
668    fn a_second_root_is_a_protocol_error() {
669        protocol_error(&[Null, Null]);
670        protocol_error(&[ObjectStart, ObjectEnd, ArrayStart]);
671        protocol_error(&[String("a"), String("b"), End]);
672    }
673
674    #[test]
675    fn an_end_without_a_complete_root_is_a_protocol_error() {
676        assert!(!protocol_error(&[End]).committed_output);
677        protocol_error(&[ArrayStart, End]);
678        protocol_error(&[ObjectStart, Key("a"), End]);
679        protocol_error(&[ObjectStart, Key("a"), Null, End]);
680    }
681
682    #[test]
683    fn a_key_outside_an_object_or_where_a_value_is_due_is_a_protocol_error() {
684        protocol_error(&[Key("a")]);
685        protocol_error(&[ArrayStart, Key("a")]);
686        protocol_error(&[ObjectStart, Key("a"), Key("b")]);
687        protocol_error(&[Null, Key("a")]);
688    }
689
690    #[test]
691    fn a_value_where_a_key_is_due_is_a_protocol_error() {
692        protocol_error(&[ObjectStart, Null]);
693        protocol_error(&[ObjectStart, ArrayStart]);
694        protocol_error(&[ObjectStart, Key("a"), Null, String("b")]);
695    }
696
697    #[test]
698    fn an_unbalanced_or_mismatched_close_is_a_protocol_error() {
699        protocol_error(&[ObjectEnd]);
700        protocol_error(&[ArrayEnd]);
701        protocol_error(&[ArrayStart, ObjectEnd]);
702        protocol_error(&[ObjectStart, ArrayEnd]);
703        protocol_error(&[ObjectStart, Key("a"), ObjectEnd]);
704        protocol_error(&[ArrayStart, ArrayEnd, ArrayEnd]);
705    }
706
707    #[test]
708    fn anything_after_the_end_is_a_protocol_error() {
709        for after in [End, Null, Key("a"), ObjectStart, ObjectEnd, ArrayEnd] {
710            let err = protocol_error(&[Null, End, after]);
711            assert!(err.committed_output);
712        }
713    }
714
715    #[test]
716    fn a_failure_leaves_the_output_a_prefix_of_the_document() {
717        let mut r = JsonRenderer::new(StringOut::new(), JsonOptions::default());
718        for ev in [ObjectStart, Key("a"), ArrayStart, Null] {
719            r.event(ev).unwrap();
720        }
721        assert_eq!(r.depth(), 2);
722        assert_eq!(
723            r.event(Key("b")).unwrap_err().code,
724            Code::ProtocolOrderError
725        );
726        assert_eq!(r.into_inner().as_str(), "{\"a\":[null");
727    }
728
729    /// A writer that takes every byte and refuses to flush.
730    struct NoFlush;
731
732    impl std::io::Write for NoFlush {
733        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
734            Ok(buf.len())
735        }
736
737        fn flush(&mut self) -> std::io::Result<()> {
738            Err(std::io::Error::other("pipe closed"))
739        }
740    }
741
742    #[test]
743    fn a_failed_flush_at_end_leaves_the_renderer_not_done() {
744        let mut r = JsonRenderer::new(WriteOut::new(NoFlush), JsonOptions::default());
745        r.event(Null).unwrap();
746        let err = r.event(End).unwrap_err();
747        assert_eq!(err.code, Code::OutputFailed);
748        assert!(!r.is_done());
749    }
750
751    #[test]
752    fn committed_output_means_bytes_that_reached_the_writer() {
753        let mut r = JsonRenderer::new(WriteOut::new(Vec::new()), JsonOptions::default());
754        r.event(ArrayStart).unwrap();
755        let err = r.event(Key("k")).unwrap_err();
756        assert_eq!(err.code, Code::ProtocolOrderError);
757        assert!(!err.committed_output, "the bracket is only buffered");
758        assert_eq!(r.out.committed(), 0);
759
760        let mut r = JsonRenderer::new(
761            WriteOut::new(Vec::new()).with_budget(0),
762            JsonOptions::default(),
763        );
764        r.event(ArrayStart).unwrap();
765        let err = r.event(Key("k")).unwrap_err();
766        assert!(err.committed_output, "the bracket reached the writer");
767    }
768
769    #[test]
770    fn end_flushes_the_output_and_nothing_else_does() {
771        let mut r = JsonRenderer::new(WriteOut::new(Vec::new()), JsonOptions::default());
772        for ev in [ArrayStart, Bool(true), ArrayEnd] {
773            assert_eq!(r.event(ev).unwrap(), Flow::Continue);
774        }
775        assert_eq!(r.out.committed(), 0);
776        assert!(!r.is_done());
777        r.event(End).unwrap();
778        assert!(r.is_done());
779        assert_eq!(r.out.committed(), 6);
780        assert_eq!(r.into_inner().into_inner(), b"[true]");
781    }
782}