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
265#[cfg(test)]
266mod tests {
267 mod errors {
268 use super::*;
269
270 #[test]
271 fn array_in_object_without_key_errors() {
272 let mut e = make();
273 assert!(e.object(|j| j.array(|_| Ok(()))).is_err());
274 }
275
276 #[test]
277 fn close_array_when_top_is_object_errors() {
278 let mut e = make();
279 assert!(e.open_object().is_ok());
280 assert!(e.close_array().is_err());
281 }
282
283 #[test]
284 fn close_object_at_root_errors() {
285 let mut e = make();
286 assert!(e.close_object().is_err());
287 }
288
289 #[test]
290 fn close_object_when_top_is_array_errors() {
291 let mut e = make();
292 assert!(e.open_array().is_ok());
293 assert!(e.close_object().is_err());
294 }
295
296 #[test]
297 fn closure_error_in_array_still_closes_array() {
298 let mut e = make();
299 let inner = e.array(|j| {
300 j.value("first")?;
301 Err(docspec_core::Error::Other {
302 message: "inner".to_string(),
303 })
304 });
305 assert!(inner.is_err());
306 let tokens = finish_tokens(e);
307 assert_eq!(
308 tokens,
309 vec![
310 Token::BeginArray,
311 Token::StringValue("first".to_string()),
312 Token::EndArray,
313 ]
314 );
315 }
316
317 #[test]
318 fn closure_error_in_object_still_closes_object() {
319 let mut e = make();
320 let inner = e.object(|j| {
321 j.key("a").value("1")?;
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::BeginObject,
332 Token::Name("a".to_string()),
333 Token::StringValue("1".to_string()),
334 Token::EndObject,
335 ]
336 );
337 }
338
339 #[test]
340 fn closure_error_propagates() {
341 let mut e = make();
342 let result = e.object(|_| {
343 Err(docspec_core::Error::Other {
344 message: "inner error".to_string(),
345 })
346 });
347 assert!(result.is_err());
348 }
349
350 #[test]
351 fn dropped_key_does_not_corrupt_state() {
352 let mut e = make();
353 assert!(e.open_object().is_ok());
354 let k = e.key("x");
355 drop(k);
356 assert!(e.key("y").value("z").is_ok());
357 assert!(e.close_object().is_ok());
358 }
359
360 #[test]
361 fn finish_after_root_value_succeeds() {
362 let mut e = make();
363 assert!(e.value("x").is_ok());
364 assert!(e.finish().is_ok());
365 }
366
367 #[test]
368 fn finish_with_open_array_errors() {
369 let mut e = make();
370 assert!(e.open_array().is_ok());
371 assert!(e.finish().is_err());
372 }
373
374 #[test]
375 fn finish_with_open_object_errors() {
376 let mut e = make();
377 assert!(e.open_object().is_ok());
378 assert!(e.finish().is_err());
379 }
380
381 #[test]
382 fn finish_without_any_value_errors() {
383 let e = make();
384 assert!(e.finish().is_err());
385 }
386
387 #[test]
388 fn key_inside_array_errors() {
389 let mut e = make();
390 assert!(e.array(|j| j.key("x").value("1")).is_err());
391 }
392
393 #[test]
394 fn key_outside_object_errors() {
395 let mut e = make();
396 assert!(e.key("x").value("1").is_err());
397 }
398
399 #[test]
400 fn keyed_array_closure_error_still_closes_array() {
401 let mut e = make();
402 assert!(e.open_object().is_ok());
403 let inner = e.key("items").array(|j| {
404 j.value("first")?;
405 Err(docspec_core::Error::Other {
406 message: "inner".to_string(),
407 })
408 });
409 assert!(inner.is_err());
410 assert!(e.close_object().is_ok());
411 let tokens = finish_tokens(e);
412 assert_eq!(
413 tokens,
414 vec![
415 Token::BeginObject,
416 Token::Name("items".to_string()),
417 Token::BeginArray,
418 Token::StringValue("first".to_string()),
419 Token::EndArray,
420 Token::EndObject,
421 ]
422 );
423 }
424
425 #[test]
426 fn keyed_object_closure_error_still_closes_object() {
427 let mut e = make();
428 assert!(e.open_object().is_ok());
429 let inner = e.key("inner").object(|j| {
430 j.key("a").value("1")?;
431 Err(docspec_core::Error::Other {
432 message: "inner".to_string(),
433 })
434 });
435 assert!(inner.is_err());
436 assert!(e.close_object().is_ok());
437 let tokens = finish_tokens(e);
438 assert_eq!(
439 tokens,
440 vec![
441 Token::BeginObject,
442 Token::Name("inner".to_string()),
443 Token::BeginObject,
444 Token::Name("a".to_string()),
445 Token::StringValue("1".to_string()),
446 Token::EndObject,
447 Token::EndObject,
448 ]
449 );
450 }
451
452 #[test]
453 fn object_in_object_without_key_errors() {
454 let mut e = make();
455 assert!(e.object(|j| j.object(|_| Ok(()))).is_err());
456 }
457
458 #[test]
459 fn open_object_in_object_expecting_value_errors() {
460 let mut e = make();
461 assert!(e.open_object().is_ok());
462 assert!(e.key("k").open_object().is_ok());
463 assert!(e.open_object().is_err());
464 }
465
466 #[test]
467 fn state_validation_uses_json_error_variant() {
468 let mut e = make();
469 assert!(e.open_object().is_ok());
470 let err = e.value("x");
471 assert!(matches!(err, Err(docspec_core::Error::Json { .. })));
472 }
473
474 #[test]
475 fn value_at_root_after_root_value_already_written_errors() {
476 let mut e = make();
477 assert!(e.value("first").is_ok());
478 assert!(e.value("second").is_err());
479 }
480
481 #[test]
482 fn value_in_object_without_key_errors() {
483 let mut e = make();
484 assert!(e.object(|j| j.value("x")).is_err());
485 }
486 }
487
488 mod happy_path {
489 use super::*;
490
491 #[test]
492 fn array_of_objects() {
493 let mut e = make();
494 assert!(e
495 .array(|j| { j.object(|j2| j2.key("x").value("a")) })
496 .is_ok());
497 let t = finish_tokens(e);
498 assert_eq!(
499 t,
500 vec![
501 Token::BeginArray,
502 Token::BeginObject,
503 Token::Name("x".to_string()),
504 Token::StringValue("a".to_string()),
505 Token::EndObject,
506 Token::EndArray,
507 ]
508 );
509 }
510
511 #[test]
512 fn array_of_scalars() {
513 let mut e = make();
514 assert!(e
515 .array(|j| {
516 j.value("a")?;
517 j.value(true)?;
518 j.value(Null)
519 })
520 .is_ok());
521 let t = finish_tokens(e);
522 assert_eq!(
523 t,
524 vec![
525 Token::BeginArray,
526 Token::StringValue("a".to_string()),
527 Token::BoolValue(true),
528 Token::NullValue,
529 Token::EndArray,
530 ]
531 );
532 }
533
534 #[test]
535 fn finish_returns_backend_output_tokens() {
536 let mut e = make();
537 assert!(e.value("hi").is_ok());
538 let t = finish_tokens(e);
539 assert_eq!(t, vec![Token::StringValue("hi".to_string())]);
540 }
541
542 #[test]
543 fn mixed_nested_structure_object_array_object() {
544 let mut e = make();
545 assert!(e
546 .object(|j| {
547 j.key("a")
548 .array(|j2| j2.object(|j3| j3.key("b").value(true)))
549 })
550 .is_ok());
551 let t = finish_tokens(e);
552 assert_eq!(
553 t,
554 vec![
555 Token::BeginObject,
556 Token::Name("a".to_string()),
557 Token::BeginArray,
558 Token::BeginObject,
559 Token::Name("b".to_string()),
560 Token::BoolValue(true),
561 Token::EndObject,
562 Token::EndArray,
563 Token::EndObject,
564 ]
565 );
566 }
567
568 #[test]
569 fn nested_object_in_object() {
570 let mut e = make();
571 assert!(e
572 .object(|j| { j.key("inner").object(|j2| j2.key("k").value("v")) })
573 .is_ok());
574 let t = finish_tokens(e);
575 assert_eq!(
576 t,
577 vec![
578 Token::BeginObject,
579 Token::Name("inner".to_string()),
580 Token::BeginObject,
581 Token::Name("k".to_string()),
582 Token::StringValue("v".to_string()),
583 Token::EndObject,
584 Token::EndObject,
585 ]
586 );
587 }
588
589 #[test]
590 fn object_with_multiple_keys_in_order() {
591 let mut e = make();
592 assert!(e
593 .object(|j| {
594 j.key("a").value("1")?;
595 j.key("b").value(true)?;
596 j.key("c").value(Null)
597 })
598 .is_ok());
599 let t = finish_tokens(e);
600 assert_eq!(
601 t,
602 vec![
603 Token::BeginObject,
604 Token::Name("a".to_string()),
605 Token::StringValue("1".to_string()),
606 Token::Name("b".to_string()),
607 Token::BoolValue(true),
608 Token::Name("c".to_string()),
609 Token::NullValue,
610 Token::EndObject,
611 ]
612 );
613 }
614
615 #[test]
616 fn object_with_single_key_string_value() {
617 let mut e = make();
618 assert!(e.object(|j| j.key("k").value("v")).is_ok());
619 let t = finish_tokens(e);
620 assert_eq!(
621 t,
622 vec![
623 Token::BeginObject,
624 Token::Name("k".to_string()),
625 Token::StringValue("v".to_string()),
626 Token::EndObject,
627 ]
628 );
629 }
630
631 #[test]
632 fn root_array_empty() {
633 let mut e = make();
634 assert!(e.array(|_| Ok(())).is_ok());
635 assert_eq!(finish_tokens(e), vec![Token::BeginArray, Token::EndArray]);
636 }
637
638 #[test]
639 fn root_object_empty() {
640 let mut e = make();
641 assert!(e.object(|_| Ok(())).is_ok());
642 assert_eq!(finish_tokens(e), vec![Token::BeginObject, Token::EndObject]);
643 }
644
645 #[test]
646 fn root_scalar_null() {
647 let mut e = make();
648 assert!(e.value(Null).is_ok());
649 assert_eq!(finish_tokens(e), vec![Token::NullValue]);
650 }
651
652 #[test]
653 fn root_scalar_string() {
654 let mut e = make();
655 assert!(e.value("hello").is_ok());
656 assert_eq!(
657 finish_tokens(e),
658 vec![Token::StringValue("hello".to_string())]
659 );
660 }
661 }
662
663 mod streaming {
664 use super::*;
665
666 #[test]
667 fn keyed_open_array_then_close() {
668 let mut e = make();
669 assert!(e.open_object().is_ok());
670 assert!(e.key("content").open_array().is_ok());
671 assert!(e.value("x").is_ok());
672 assert!(e.close_array().is_ok());
673 assert!(e.close_object().is_ok());
674 let t = finish_tokens(e);
675 assert_eq!(
676 t,
677 vec![
678 Token::BeginObject,
679 Token::Name("content".to_string()),
680 Token::BeginArray,
681 Token::StringValue("x".to_string()),
682 Token::EndArray,
683 Token::EndObject,
684 ]
685 );
686 }
687
688 #[test]
689 fn keyed_open_object_then_close() {
690 let mut e = make();
691 assert!(e.open_array().is_ok());
692 assert!(e.open_object().is_ok());
693 assert!(e.key("type").value("h").is_ok());
694 assert!(e.close_object().is_ok());
695 assert!(e.close_array().is_ok());
696 let t = finish_tokens(e);
697 assert_eq!(
698 t,
699 vec![
700 Token::BeginArray,
701 Token::BeginObject,
702 Token::Name("type".to_string()),
703 Token::StringValue("h".to_string()),
704 Token::EndObject,
705 Token::EndArray,
706 ]
707 );
708 }
709
710 #[test]
711 fn keyed_open_then_unkeyed_open_in_array() {
712 let mut e = make();
713 assert!(e.open_object().is_ok());
714 assert!(e.key("c").open_array().is_ok());
715 assert!(e.open_object().is_ok());
716 assert!(e.close_object().is_ok());
717 assert!(e.close_array().is_ok());
718 assert!(e.close_object().is_ok());
719 assert!(!finish_tokens(e).is_empty());
720 }
721
722 #[test]
723 fn mixed_closure_and_streaming() {
724 let mut e = make();
725 assert!(e.open_object().is_ok());
726 assert!(e.key("k1").value("a").is_ok());
727 assert!(e.key("k2").array(|j| j.value(true)).is_ok());
728 assert!(e.close_object().is_ok());
729 let t = finish_tokens(e);
730 assert_eq!(
731 t,
732 vec![
733 Token::BeginObject,
734 Token::Name("k1".to_string()),
735 Token::StringValue("a".to_string()),
736 Token::Name("k2".to_string()),
737 Token::BeginArray,
738 Token::BoolValue(true),
739 Token::EndArray,
740 Token::EndObject,
741 ]
742 );
743 }
744
745 #[test]
746 fn nested_streaming_objects() {
747 let mut e = make();
748 assert!(e.open_object().is_ok());
749 assert!(e.key("a").open_object().is_ok());
750 assert!(e.key("b").open_object().is_ok());
751 assert!(e.close_object().is_ok());
752 assert!(e.close_object().is_ok());
753 assert!(e.close_object().is_ok());
754 let t = finish_tokens(e);
755 assert_eq!(
756 t,
757 vec![
758 Token::BeginObject,
759 Token::Name("a".to_string()),
760 Token::BeginObject,
761 Token::Name("b".to_string()),
762 Token::BeginObject,
763 Token::EndObject,
764 Token::EndObject,
765 Token::EndObject,
766 ]
767 );
768 }
769
770 #[test]
771 fn open_close_array_empty() {
772 let mut e = make();
773 assert!(e.open_array().is_ok());
774 assert!(e.close_array().is_ok());
775 assert_eq!(finish_tokens(e), vec![Token::BeginArray, Token::EndArray]);
776 }
777
778 #[test]
779 fn open_close_object_empty() {
780 let mut e = make();
781 assert!(e.open_object().is_ok());
782 assert!(e.close_object().is_ok());
783 assert_eq!(finish_tokens(e), vec![Token::BeginObject, Token::EndObject]);
784 }
785
786 #[test]
787 fn streaming_emits_blocknote_block_shape() {
788 let mut e = make();
789 assert!(e.open_array().is_ok());
790 assert!(e.open_object().is_ok());
791 assert!(e.key("type").value("heading").is_ok());
792 assert!(e.key("content").open_array().is_ok());
793 assert!(e.close_array().is_ok());
794 assert!(e.close_object().is_ok());
795 assert!(e.close_array().is_ok());
796 let t = finish_tokens(e);
797 assert_eq!(
798 t,
799 vec![
800 Token::BeginArray,
801 Token::BeginObject,
802 Token::Name("type".to_string()),
803 Token::StringValue("heading".to_string()),
804 Token::Name("content".to_string()),
805 Token::BeginArray,
806 Token::EndArray,
807 Token::EndObject,
808 Token::EndArray,
809 ]
810 );
811 }
812
813 #[test]
814 fn streaming_root_array_with_two_objects_via_open_close() {
815 let mut e = make();
816 assert!(e.open_array().is_ok());
817 assert!(e.open_object().is_ok());
818 assert!(e.key("a").value("1").is_ok());
819 assert!(e.close_object().is_ok());
820 assert!(e.open_object().is_ok());
821 assert!(e.key("b").value("2").is_ok());
822 assert!(e.close_object().is_ok());
823 assert!(e.close_array().is_ok());
824 let t = finish_tokens(e);
825 assert_eq!(
826 t,
827 vec![
828 Token::BeginArray,
829 Token::BeginObject,
830 Token::Name("a".to_string()),
831 Token::StringValue("1".to_string()),
832 Token::EndObject,
833 Token::BeginObject,
834 Token::Name("b".to_string()),
835 Token::StringValue("2".to_string()),
836 Token::EndObject,
837 Token::EndArray,
838 ]
839 );
840 }
841 }
842
843 use super::*;
844 use crate::backend::{CapturingBackend, Token};
845 use crate::value::Null;
846
847 fn finish_tokens(e: JsonEmitter<CapturingBackend>) -> Vec<Token> {
848 let result = e.finish();
849 assert!(result.is_ok(), "finish should succeed");
850 result.unwrap_or_default()
851 }
852
853 fn make() -> JsonEmitter<CapturingBackend> {
854 JsonEmitter::new(CapturingBackend::new())
855 }
856}