1use crate::{backend::JsonBackend, state::StateStack, value::WriteVal};
4use docspec_core::{Error, Result};
5
6pub struct JsonEmitter<B: JsonBackend> {
16 backend: B,
17 stack: StateStack,
18}
19
20impl<B: JsonBackend> JsonEmitter<B> {
21 #[inline]
32 pub fn array<F>(&mut self, f: F) -> Result<()>
33 where
34 F: FnOnce(&mut Self) -> Result<()>,
35 {
36 self.open_array()?;
37 let inner = f(self);
38 let close = self.close_array();
39 inner.and(close)
40 }
41
42 #[inline]
48 pub fn close_array(&mut self) -> Result<()> {
49 self.stack.peek_array()?;
50 self.backend.end_array()?;
51 self.stack.pop_array()?;
52 self.stack.mark_value_written()
53 }
54
55 #[inline]
61 pub fn close_object(&mut self) -> Result<()> {
62 self.stack.peek_object()?;
63 self.backend.end_object()?;
64 self.stack.pop_object()?;
65 self.stack.mark_value_written()
66 }
67
68 #[inline]
74 pub fn finish(self) -> Result<B::Output> {
75 if !self.stack.is_finished() {
76 return Err(Error::Json {
77 message: "cannot finish: open containers remain or no root value written"
78 .to_string(),
79 position: None,
80 });
81 }
82 self.backend.finish()
83 }
84
85 #[inline]
88 pub fn key<'a>(&'a mut self, name: &'a str) -> KeyedEmitter<'a, B> {
89 KeyedEmitter {
90 emitter: self,
91 name,
92 }
93 }
94
95 #[inline]
97 #[must_use]
98 pub fn new(backend: B) -> Self {
99 Self {
100 backend,
101 stack: StateStack::new(),
102 }
103 }
104
105 #[inline]
116 pub fn object<F>(&mut self, f: F) -> Result<()>
117 where
118 F: FnOnce(&mut Self) -> Result<()>,
119 {
120 self.open_object()?;
121 let inner = f(self);
122 let close = self.close_object();
123 inner.and(close)
124 }
125
126 #[inline]
132 pub fn open_array(&mut self) -> Result<()> {
133 self.stack.expect_value_allowed()?;
134 self.backend.begin_array()?;
135 self.stack.push_array();
136 Ok(())
137 }
138
139 #[inline]
145 pub fn open_object(&mut self) -> Result<()> {
146 self.stack.expect_value_allowed()?;
147 self.backend.begin_object()?;
148 self.stack.push_object();
149 Ok(())
150 }
151
152 #[inline]
158 pub fn value<V: WriteVal>(&mut self, v: V) -> Result<()> {
159 self.stack.expect_value_allowed()?;
160 v.write_to(&mut self.backend)?;
161 self.stack.mark_value_written()
162 }
163
164 fn write_key(&mut self, name: &str) -> Result<()> {
166 self.stack.expect_key_allowed()?;
167 self.backend.write_name(name)?;
168 self.stack.mark_key_written()
169 }
170}
171
172#[must_use = "KeyedEmitter must be consumed by .object(), .array(), .value(), .open_object(), or .open_array()"]
178pub struct KeyedEmitter<'a, B: JsonBackend> {
179 emitter: &'a mut JsonEmitter<B>,
180 name: &'a str,
181}
182
183impl<B: JsonBackend> KeyedEmitter<'_, B> {
184 #[inline]
193 pub fn array<F>(self, f: F) -> Result<()>
194 where
195 F: FnOnce(&mut JsonEmitter<B>) -> Result<()>,
196 {
197 let emitter = self.emitter;
198 emitter.write_key(self.name)?;
199 emitter.open_array()?;
200 let inner = f(emitter);
201 let close = emitter.close_array();
202 inner.and(close)
203 }
204
205 #[inline]
214 pub fn object<F>(self, f: F) -> Result<()>
215 where
216 F: FnOnce(&mut JsonEmitter<B>) -> Result<()>,
217 {
218 let emitter = self.emitter;
219 emitter.write_key(self.name)?;
220 emitter.open_object()?;
221 let inner = f(emitter);
222 let close = emitter.close_object();
223 inner.and(close)
224 }
225
226 #[inline]
233 pub fn open_array(self) -> Result<()> {
234 self.emitter.write_key(self.name)?;
235 self.emitter.open_array()
236 }
237
238 #[inline]
245 pub fn open_object(self) -> Result<()> {
246 self.emitter.write_key(self.name)?;
247 self.emitter.open_object()
248 }
249
250 #[inline]
256 pub fn value<V: WriteVal>(self, v: V) -> Result<()> {
257 let emitter = self.emitter;
258 let name = self.name;
259 emitter.write_key(name)?;
260 v.write_to(&mut emitter.backend)?;
261 emitter.stack.mark_value_written()
262 }
263
264 #[inline]
273 pub fn string_value_streaming<F>(self, f: F) -> Result<()>
274 where
275 F: FnOnce(&mut dyn std::io::Write) -> std::io::Result<()>,
276 {
277 let emitter = self.emitter;
278 let name = self.name;
279 emitter.write_key(name)?;
280 let inner = emitter.backend.write_string_streaming(f);
281 let mark = emitter.stack.mark_value_written();
282 inner.and(mark)
283 }
284}
285
286#[cfg(test)]
287mod tests {
288 mod errors {
289 use super::*;
290
291 #[test]
292 fn array_in_object_without_key_errors() {
293 let mut e = make();
294 assert!(e.object(|j| j.array(|_| Ok(()))).is_err());
295 }
296
297 #[test]
298 fn close_array_when_top_is_object_errors() {
299 let mut e = make();
300 assert!(e.open_object().is_ok());
301 assert!(e.close_array().is_err());
302 }
303
304 #[test]
305 fn close_object_at_root_errors() {
306 let mut e = make();
307 assert!(e.close_object().is_err());
308 }
309
310 #[test]
311 fn close_object_when_top_is_array_errors() {
312 let mut e = make();
313 assert!(e.open_array().is_ok());
314 assert!(e.close_object().is_err());
315 }
316
317 #[test]
318 fn closure_error_in_array_still_closes_array() {
319 let mut e = make();
320 let inner = e.array(|j| {
321 j.value("first")?;
322 Err(docspec_core::Error::Other {
323 message: "inner".to_string(),
324 })
325 });
326 assert!(inner.is_err());
327 let tokens = finish_tokens(e);
328 assert_eq!(
329 tokens,
330 vec![
331 Token::BeginArray,
332 Token::StringValue("first".to_string()),
333 Token::EndArray,
334 ]
335 );
336 }
337
338 #[test]
339 fn closure_error_in_object_still_closes_object() {
340 let mut e = make();
341 let inner = e.object(|j| {
342 j.key("a").value("1")?;
343 Err(docspec_core::Error::Other {
344 message: "inner".to_string(),
345 })
346 });
347 assert!(inner.is_err());
348 let tokens = finish_tokens(e);
349 assert_eq!(
350 tokens,
351 vec![
352 Token::BeginObject,
353 Token::Name("a".to_string()),
354 Token::StringValue("1".to_string()),
355 Token::EndObject,
356 ]
357 );
358 }
359
360 #[test]
361 fn closure_error_propagates() {
362 let mut e = make();
363 let result = e.object(|_| {
364 Err(docspec_core::Error::Other {
365 message: "inner error".to_string(),
366 })
367 });
368 assert!(result.is_err());
369 }
370
371 #[test]
372 fn dropped_key_does_not_corrupt_state() {
373 let mut e = make();
374 assert!(e.open_object().is_ok());
375 let k = e.key("x");
376 drop(k);
377 assert!(e.key("y").value("z").is_ok());
378 assert!(e.close_object().is_ok());
379 }
380
381 #[test]
382 fn finish_after_root_value_succeeds() {
383 let mut e = make();
384 assert!(e.value("x").is_ok());
385 assert!(e.finish().is_ok());
386 }
387
388 #[test]
389 fn finish_with_open_array_errors() {
390 let mut e = make();
391 assert!(e.open_array().is_ok());
392 assert!(e.finish().is_err());
393 }
394
395 #[test]
396 fn finish_with_open_object_errors() {
397 let mut e = make();
398 assert!(e.open_object().is_ok());
399 assert!(e.finish().is_err());
400 }
401
402 #[test]
403 fn finish_without_any_value_errors() {
404 let e = make();
405 assert!(e.finish().is_err());
406 }
407
408 #[test]
409 fn key_inside_array_errors() {
410 let mut e = make();
411 assert!(e.array(|j| j.key("x").value("1")).is_err());
412 }
413
414 #[test]
415 fn key_outside_object_errors() {
416 let mut e = make();
417 assert!(e.key("x").value("1").is_err());
418 }
419
420 #[test]
421 fn keyed_array_closure_error_still_closes_array() {
422 let mut e = make();
423 assert!(e.open_object().is_ok());
424 let inner = e.key("items").array(|j| {
425 j.value("first")?;
426 Err(docspec_core::Error::Other {
427 message: "inner".to_string(),
428 })
429 });
430 assert!(inner.is_err());
431 assert!(e.close_object().is_ok());
432 let tokens = finish_tokens(e);
433 assert_eq!(
434 tokens,
435 vec![
436 Token::BeginObject,
437 Token::Name("items".to_string()),
438 Token::BeginArray,
439 Token::StringValue("first".to_string()),
440 Token::EndArray,
441 Token::EndObject,
442 ]
443 );
444 }
445
446 #[test]
447 fn keyed_object_closure_error_still_closes_object() {
448 let mut e = make();
449 assert!(e.open_object().is_ok());
450 let inner = e.key("inner").object(|j| {
451 j.key("a").value("1")?;
452 Err(docspec_core::Error::Other {
453 message: "inner".to_string(),
454 })
455 });
456 assert!(inner.is_err());
457 assert!(e.close_object().is_ok());
458 let tokens = finish_tokens(e);
459 assert_eq!(
460 tokens,
461 vec![
462 Token::BeginObject,
463 Token::Name("inner".to_string()),
464 Token::BeginObject,
465 Token::Name("a".to_string()),
466 Token::StringValue("1".to_string()),
467 Token::EndObject,
468 Token::EndObject,
469 ]
470 );
471 }
472
473 #[test]
474 fn object_in_object_without_key_errors() {
475 let mut e = make();
476 assert!(e.object(|j| j.object(|_| Ok(()))).is_err());
477 }
478
479 #[test]
480 fn open_object_in_object_expecting_value_errors() {
481 let mut e = make();
482 assert!(e.open_object().is_ok());
483 assert!(e.key("k").open_object().is_ok());
484 assert!(e.open_object().is_err());
485 }
486
487 #[test]
488 fn state_validation_uses_json_error_variant() {
489 let mut e = make();
490 assert!(e.open_object().is_ok());
491 let err = e.value("x");
492 assert!(matches!(err, Err(docspec_core::Error::Json { .. })));
493 }
494
495 #[test]
496 fn value_at_root_after_root_value_already_written_errors() {
497 let mut e = make();
498 assert!(e.value("first").is_ok());
499 assert!(e.value("second").is_err());
500 }
501
502 #[test]
503 fn value_in_object_without_key_errors() {
504 let mut e = make();
505 assert!(e.object(|j| j.value("x")).is_err());
506 }
507 }
508
509 mod happy_path {
510 use super::*;
511
512 #[test]
513 fn array_of_objects() {
514 let mut e = make();
515 assert!(e
516 .array(|j| { j.object(|j2| j2.key("x").value("a")) })
517 .is_ok());
518 let t = finish_tokens(e);
519 assert_eq!(
520 t,
521 vec![
522 Token::BeginArray,
523 Token::BeginObject,
524 Token::Name("x".to_string()),
525 Token::StringValue("a".to_string()),
526 Token::EndObject,
527 Token::EndArray,
528 ]
529 );
530 }
531
532 #[test]
533 fn array_of_scalars() {
534 let mut e = make();
535 assert!(e
536 .array(|j| {
537 j.value("a")?;
538 j.value(true)?;
539 j.value(Null)
540 })
541 .is_ok());
542 let t = finish_tokens(e);
543 assert_eq!(
544 t,
545 vec![
546 Token::BeginArray,
547 Token::StringValue("a".to_string()),
548 Token::BoolValue(true),
549 Token::NullValue,
550 Token::EndArray,
551 ]
552 );
553 }
554
555 #[test]
556 fn finish_returns_backend_output_tokens() {
557 let mut e = make();
558 assert!(e.value("hi").is_ok());
559 let t = finish_tokens(e);
560 assert_eq!(t, vec![Token::StringValue("hi".to_string())]);
561 }
562
563 #[test]
564 fn mixed_nested_structure_object_array_object() {
565 let mut e = make();
566 assert!(e
567 .object(|j| {
568 j.key("a")
569 .array(|j2| j2.object(|j3| j3.key("b").value(true)))
570 })
571 .is_ok());
572 let t = finish_tokens(e);
573 assert_eq!(
574 t,
575 vec![
576 Token::BeginObject,
577 Token::Name("a".to_string()),
578 Token::BeginArray,
579 Token::BeginObject,
580 Token::Name("b".to_string()),
581 Token::BoolValue(true),
582 Token::EndObject,
583 Token::EndArray,
584 Token::EndObject,
585 ]
586 );
587 }
588
589 #[test]
590 fn nested_object_in_object() {
591 let mut e = make();
592 assert!(e
593 .object(|j| { j.key("inner").object(|j2| j2.key("k").value("v")) })
594 .is_ok());
595 let t = finish_tokens(e);
596 assert_eq!(
597 t,
598 vec![
599 Token::BeginObject,
600 Token::Name("inner".to_string()),
601 Token::BeginObject,
602 Token::Name("k".to_string()),
603 Token::StringValue("v".to_string()),
604 Token::EndObject,
605 Token::EndObject,
606 ]
607 );
608 }
609
610 #[test]
611 fn object_with_multiple_keys_in_order() {
612 let mut e = make();
613 assert!(e
614 .object(|j| {
615 j.key("a").value("1")?;
616 j.key("b").value(true)?;
617 j.key("c").value(Null)
618 })
619 .is_ok());
620 let t = finish_tokens(e);
621 assert_eq!(
622 t,
623 vec![
624 Token::BeginObject,
625 Token::Name("a".to_string()),
626 Token::StringValue("1".to_string()),
627 Token::Name("b".to_string()),
628 Token::BoolValue(true),
629 Token::Name("c".to_string()),
630 Token::NullValue,
631 Token::EndObject,
632 ]
633 );
634 }
635
636 #[test]
637 fn object_with_single_key_string_value() {
638 let mut e = make();
639 assert!(e.object(|j| j.key("k").value("v")).is_ok());
640 let t = finish_tokens(e);
641 assert_eq!(
642 t,
643 vec![
644 Token::BeginObject,
645 Token::Name("k".to_string()),
646 Token::StringValue("v".to_string()),
647 Token::EndObject,
648 ]
649 );
650 }
651
652 #[test]
653 fn root_array_empty() {
654 let mut e = make();
655 assert!(e.array(|_| Ok(())).is_ok());
656 assert_eq!(finish_tokens(e), vec![Token::BeginArray, Token::EndArray]);
657 }
658
659 #[test]
660 fn root_object_empty() {
661 let mut e = make();
662 assert!(e.object(|_| Ok(())).is_ok());
663 assert_eq!(finish_tokens(e), vec![Token::BeginObject, Token::EndObject]);
664 }
665
666 #[test]
667 fn root_scalar_null() {
668 let mut e = make();
669 assert!(e.value(Null).is_ok());
670 assert_eq!(finish_tokens(e), vec![Token::NullValue]);
671 }
672
673 #[test]
674 fn root_scalar_string() {
675 let mut e = make();
676 assert!(e.value("hello").is_ok());
677 assert_eq!(
678 finish_tokens(e),
679 vec![Token::StringValue("hello".to_string())]
680 );
681 }
682 }
683
684 mod streaming {
685 use super::*;
686
687 #[test]
688 fn keyed_open_array_then_close() {
689 let mut e = make();
690 assert!(e.open_object().is_ok());
691 assert!(e.key("content").open_array().is_ok());
692 assert!(e.value("x").is_ok());
693 assert!(e.close_array().is_ok());
694 assert!(e.close_object().is_ok());
695 let t = finish_tokens(e);
696 assert_eq!(
697 t,
698 vec![
699 Token::BeginObject,
700 Token::Name("content".to_string()),
701 Token::BeginArray,
702 Token::StringValue("x".to_string()),
703 Token::EndArray,
704 Token::EndObject,
705 ]
706 );
707 }
708
709 #[test]
710 fn keyed_open_object_then_close() {
711 let mut e = make();
712 assert!(e.open_array().is_ok());
713 assert!(e.open_object().is_ok());
714 assert!(e.key("type").value("h").is_ok());
715 assert!(e.close_object().is_ok());
716 assert!(e.close_array().is_ok());
717 let t = finish_tokens(e);
718 assert_eq!(
719 t,
720 vec![
721 Token::BeginArray,
722 Token::BeginObject,
723 Token::Name("type".to_string()),
724 Token::StringValue("h".to_string()),
725 Token::EndObject,
726 Token::EndArray,
727 ]
728 );
729 }
730
731 #[test]
732 fn keyed_open_then_unkeyed_open_in_array() {
733 let mut e = make();
734 assert!(e.open_object().is_ok());
735 assert!(e.key("c").open_array().is_ok());
736 assert!(e.open_object().is_ok());
737 assert!(e.close_object().is_ok());
738 assert!(e.close_array().is_ok());
739 assert!(e.close_object().is_ok());
740 assert!(!finish_tokens(e).is_empty());
741 }
742
743 #[test]
744 fn mixed_closure_and_streaming() {
745 let mut e = make();
746 assert!(e.open_object().is_ok());
747 assert!(e.key("k1").value("a").is_ok());
748 assert!(e.key("k2").array(|j| j.value(true)).is_ok());
749 assert!(e.close_object().is_ok());
750 let t = finish_tokens(e);
751 assert_eq!(
752 t,
753 vec![
754 Token::BeginObject,
755 Token::Name("k1".to_string()),
756 Token::StringValue("a".to_string()),
757 Token::Name("k2".to_string()),
758 Token::BeginArray,
759 Token::BoolValue(true),
760 Token::EndArray,
761 Token::EndObject,
762 ]
763 );
764 }
765
766 #[test]
767 fn nested_streaming_objects() {
768 let mut e = make();
769 assert!(e.open_object().is_ok());
770 assert!(e.key("a").open_object().is_ok());
771 assert!(e.key("b").open_object().is_ok());
772 assert!(e.close_object().is_ok());
773 assert!(e.close_object().is_ok());
774 assert!(e.close_object().is_ok());
775 let t = finish_tokens(e);
776 assert_eq!(
777 t,
778 vec![
779 Token::BeginObject,
780 Token::Name("a".to_string()),
781 Token::BeginObject,
782 Token::Name("b".to_string()),
783 Token::BeginObject,
784 Token::EndObject,
785 Token::EndObject,
786 Token::EndObject,
787 ]
788 );
789 }
790
791 #[test]
792 fn open_close_array_empty() {
793 let mut e = make();
794 assert!(e.open_array().is_ok());
795 assert!(e.close_array().is_ok());
796 assert_eq!(finish_tokens(e), vec![Token::BeginArray, Token::EndArray]);
797 }
798
799 #[test]
800 fn open_close_object_empty() {
801 let mut e = make();
802 assert!(e.open_object().is_ok());
803 assert!(e.close_object().is_ok());
804 assert_eq!(finish_tokens(e), vec![Token::BeginObject, Token::EndObject]);
805 }
806
807 #[test]
808 fn streaming_emits_blocknote_block_shape() {
809 let mut e = make();
810 assert!(e.open_array().is_ok());
811 assert!(e.open_object().is_ok());
812 assert!(e.key("type").value("heading").is_ok());
813 assert!(e.key("content").open_array().is_ok());
814 assert!(e.close_array().is_ok());
815 assert!(e.close_object().is_ok());
816 assert!(e.close_array().is_ok());
817 let t = finish_tokens(e);
818 assert_eq!(
819 t,
820 vec![
821 Token::BeginArray,
822 Token::BeginObject,
823 Token::Name("type".to_string()),
824 Token::StringValue("heading".to_string()),
825 Token::Name("content".to_string()),
826 Token::BeginArray,
827 Token::EndArray,
828 Token::EndObject,
829 Token::EndArray,
830 ]
831 );
832 }
833
834 #[test]
835 fn streaming_root_array_with_two_objects_via_open_close() {
836 let mut e = make();
837 assert!(e.open_array().is_ok());
838 assert!(e.open_object().is_ok());
839 assert!(e.key("a").value("1").is_ok());
840 assert!(e.close_object().is_ok());
841 assert!(e.open_object().is_ok());
842 assert!(e.key("b").value("2").is_ok());
843 assert!(e.close_object().is_ok());
844 assert!(e.close_array().is_ok());
845 let t = finish_tokens(e);
846 assert_eq!(
847 t,
848 vec![
849 Token::BeginArray,
850 Token::BeginObject,
851 Token::Name("a".to_string()),
852 Token::StringValue("1".to_string()),
853 Token::EndObject,
854 Token::BeginObject,
855 Token::Name("b".to_string()),
856 Token::StringValue("2".to_string()),
857 Token::EndObject,
858 Token::EndArray,
859 ]
860 );
861 }
862
863 #[test]
864 fn keyed_streaming_value_writes_correct_json() {
865 let mut e = make();
866 assert!(e.open_object().is_ok());
867 assert!(e
868 .key("url")
869 .string_value_streaming(|w| w.write_all(b"hello"))
870 .is_ok());
871 assert!(e.close_object().is_ok());
872 let t = finish_tokens(e);
873 assert_eq!(
874 t,
875 vec![
876 Token::BeginObject,
877 Token::Name("url".to_string()),
878 Token::StringValue("hello".to_string()),
879 Token::EndObject,
880 ]
881 );
882 }
883
884 #[test]
885 fn keyed_streaming_value_consumes_key_on_error_then_allows_next_key() {
886 let mut e = make();
887 assert!(e.open_object().is_ok());
888 let err_result = e
889 .key("first")
890 .string_value_streaming(|_w| Err(std::io::Error::other("test error")));
891 assert!(err_result.is_err());
892 assert!(e.key("other").value("x").is_ok());
893 assert!(e.close_object().is_ok());
894 let t = finish_tokens(e);
895 assert_eq!(
896 t,
897 vec![
898 Token::BeginObject,
899 Token::Name("first".to_string()),
900 Token::Name("other".to_string()),
901 Token::StringValue("x".to_string()),
902 Token::EndObject,
903 ]
904 );
905 }
906
907 #[test]
908 fn keyed_streaming_value_with_base64_chars() {
909 let mut e = make();
910 assert!(e.open_object().is_ok());
911 assert!(e
912 .key("data")
913 .string_value_streaming(|w| w.write_all(b"data:image/png;base64,iVBORw=="))
914 .is_ok());
915 assert!(e.close_object().is_ok());
916 let t = finish_tokens(e);
917 assert_eq!(
918 t,
919 vec![
920 Token::BeginObject,
921 Token::Name("data".to_string()),
922 Token::StringValue("data:image/png;base64,iVBORw==".to_string()),
923 Token::EndObject,
924 ]
925 );
926 }
927 }
928
929 use super::*;
930 use crate::backend::{CapturingBackend, Token};
931 use crate::value::Null;
932
933 fn finish_tokens(e: JsonEmitter<CapturingBackend>) -> Vec<Token> {
934 let result = e.finish();
935 assert!(result.is_ok(), "finish should succeed");
936 result.unwrap_or_default()
937 }
938
939 fn make() -> JsonEmitter<CapturingBackend> {
940 JsonEmitter::new(CapturingBackend::new())
941 }
942}