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