1use tabnas_alchemy::shared::{Fail, Flow, JsonEvent, Number, Sink};
19
20use crate::number::{check_number, write_value};
21use crate::text::TextOut;
22
23pub 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
32pub struct JsonRenderer<O: TextOut> {
46 out: O,
47 options: JsonOptions,
48 indent: usize,
50 stack: Vec<Frame>,
51 root_done: bool,
52 ended: bool,
53 emitted: bool,
54 scratch: String,
55 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 pub fn depth(&self) -> usize {
80 self.stack.len()
81 }
82
83 pub fn is_done(&self) -> bool {
85 self.ended
86 }
87
88 pub fn into_inner(self) -> O {
89 self.out
90 }
91
92 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 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 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 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 let r = self.put(&pad[..width]);
164 self.pad = pad;
165 r
166 }
167
168 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 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 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 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 _ => 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 self.out.flush()?;
322 self.ended = true;
323 Ok(())
324 }
325}
326
327const 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
336fn escape(c: char) -> Option<&'static str> {
340 match c {
341 '"' => Some("\\\""),
342 '\\' => Some("\\\\"),
343 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 #[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 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 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 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 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}