Skip to main content

docspec_json/
emitter.rs

1//! Fluent JSON emitter with stack-based state validation.
2
3use crate::{backend::JsonBackend, state::StateStack, value::WriteVal};
4use docspec_core::{Error, Result};
5
6/// Fluent JSON emitter generic over a [`JsonBackend`].
7///
8/// Drives the backend through valid JSON shapes only — invalid sequences
9/// (e.g. `key` outside an object, two values for one key) return errors
10/// before reaching the backend.
11///
12/// Provides two complementary APIs sharing the same state machine:
13/// - **Closure form** — `object(f)`, `array(f)`, `value(v)` plus keyed via [`KeyedEmitter`].
14/// - **Streaming form** — `open_object()`, `close_object()`, `open_array()`, `close_array()`.
15pub struct JsonEmitter<B: JsonBackend> {
16    backend: B,
17    stack: StateStack,
18}
19
20impl<B: JsonBackend> JsonEmitter<B> {
21    /// Write an unkeyed array using a closure.
22    ///
23    /// Best-effort scope guard: if the closure returns `Err`, [`Self::close_array`]
24    /// is still attempted so that the backend sees a matching `end_array` and the
25    /// emitter state machine is left in a consistent shape. The closure's error
26    /// takes precedence over any error produced by the close.
27    ///
28    /// # Errors
29    ///
30    /// Returns `Err` if a value is not allowed here, or if the closure or backend errors.
31    #[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    /// Close the current array frame. Errors if the current frame is not an array.
43    ///
44    /// # Errors
45    ///
46    /// Returns `Err` if the current frame is not an array, or if the backend errors.
47    #[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    /// Close the current object frame. Errors if the current frame is not an object.
56    ///
57    /// # Errors
58    ///
59    /// Returns `Err` if the current frame is not an object, or if the backend errors.
60    #[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    /// Finish emission and return the backend's output.
69    ///
70    /// # Errors
71    ///
72    /// Returns `Err` if emission is incomplete, or if the backend errors during finish.
73    #[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    /// Begin a keyed slot. Returns a single-use [`KeyedEmitter`] that must be
86    /// consumed by `.object()`, `.array()`, `.value()`, `.open_object()`, or `.open_array()`.
87    #[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    /// Create a new emitter wrapping `backend`.
96    #[inline]
97    #[must_use]
98    pub fn new(backend: B) -> Self {
99        Self {
100            backend,
101            stack: StateStack::new(),
102        }
103    }
104
105    /// Write an unkeyed object using a closure.
106    ///
107    /// Best-effort scope guard: if the closure returns `Err`, [`Self::close_object`]
108    /// is still attempted so that the backend sees a matching `end_object` and the
109    /// emitter state machine is left in a consistent shape. The closure's error
110    /// takes precedence over any error produced by the close.
111    ///
112    /// # Errors
113    ///
114    /// Returns `Err` if a value is not allowed here, or if the closure or backend errors.
115    #[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    /// Open an unkeyed array. Caller must later call [`JsonEmitter::close_array`].
127    ///
128    /// # Errors
129    ///
130    /// Returns `Err` if a value is not allowed here, or if the backend errors.
131    #[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    /// Open an unkeyed object. Caller must later call [`JsonEmitter::close_object`].
140    ///
141    /// # Errors
142    ///
143    /// Returns `Err` if a value is not allowed here, or if the backend errors.
144    #[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    /// Write an unkeyed scalar value.
153    ///
154    /// # Errors
155    ///
156    /// Returns `Err` if a value is not allowed here, or if the backend errors.
157    #[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    /// Write a key name and transition the object state machine.
168    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/// Single-use handle returned by [`JsonEmitter::key`].
176///
177/// Consumed by [`KeyedEmitter::object`], [`KeyedEmitter::array`],
178/// [`KeyedEmitter::value`], [`KeyedEmitter::open_object`], or
179/// [`KeyedEmitter::open_array`].
180#[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    /// Consume the key and write an array value via closure.
188    ///
189    /// Best-effort scope guard: if the closure returns `Err`, the array close is
190    /// still attempted; the closure's error takes precedence.
191    ///
192    /// # Errors
193    ///
194    /// Returns `Err` if a key is not allowed here, or if the closure or backend errors.
195    #[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    /// Consume the key and write an object value via closure.
209    ///
210    /// Best-effort scope guard: if the closure returns `Err`, the object close is
211    /// still attempted; the closure's error takes precedence.
212    ///
213    /// # Errors
214    ///
215    /// Returns `Err` if a key is not allowed here, or if the closure or backend errors.
216    #[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    /// Consume the key and open an array. Caller must later call
230    /// [`JsonEmitter::close_array`] on the underlying emitter.
231    ///
232    /// # Errors
233    ///
234    /// Returns `Err` if a key is not allowed here, or if the backend errors.
235    #[inline]
236    pub fn open_array(self) -> Result<()> {
237        self.emitter.write_key(self.name)?;
238        self.emitter.open_array()
239    }
240
241    /// Consume the key and open an object. Caller must later call
242    /// [`JsonEmitter::close_object`] on the underlying emitter.
243    ///
244    /// # Errors
245    ///
246    /// Returns `Err` if a key is not allowed here, or if the backend errors.
247    #[inline]
248    pub fn open_object(self) -> Result<()> {
249        self.emitter.write_key(self.name)?;
250        self.emitter.open_object()
251    }
252
253    /// Consume the key and write a scalar value.
254    ///
255    /// # Errors
256    ///
257    /// Returns `Err` if a key is not allowed here, or if the backend errors.
258    #[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    /// Consume the key and write a string value via streaming closure.
271    ///
272    /// Best-effort scope guard: if the closure returns `Err`, the value mark is
273    /// still attempted; the closure's error takes precedence.
274    ///
275    /// # Errors
276    ///
277    /// Returns `Err` if a key is not allowed here, or if the closure or backend errors.
278    #[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}