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