1use tabnas_transduce::{Fail, Flow, JsonEvent, Number, Sink};
19
20use crate::number::{check_number, write_value};
21use crate::text::TextOut;
22
23#[derive(Clone, Debug, Default, PartialEq, Eq)]
25pub struct JsonOptions {
26 pub indent: Option<usize>,
30 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
40pub struct JsonRenderer<O: TextOut> {
54 out: O,
55 options: JsonOptions,
56 indent: usize,
58 stack: Vec<Frame>,
59 root_done: bool,
60 ended: bool,
61 emitted: bool,
62 scratch: String,
63 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 pub fn depth(&self) -> usize {
88 self.stack.len()
89 }
90
91 pub fn is_done(&self) -> bool {
93 self.ended
94 }
95
96 pub fn into_inner(self) -> O {
97 self.out
98 }
99
100 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 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 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 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 let r = self.put(&pad[..width]);
172 self.pad = pad;
173 r
174 }
175
176 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 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 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 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 _ => 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 self.out.flush()?;
330 self.ended = true;
331 Ok(())
332 }
333}
334
335const 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
344fn escape(c: char) -> Option<&'static str> {
348 match c {
349 '"' => Some("\\\""),
350 '\\' => Some("\\\\"),
351 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 #[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 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 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 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 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}