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: 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    /// Write a key name and transition the object state machine.
165    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/// Single-use handle returned by [`JsonEmitter::key`].
173///
174/// Consumed by [`KeyedEmitter::object`], [`KeyedEmitter::array`],
175/// [`KeyedEmitter::value`], [`KeyedEmitter::open_object`], or
176/// [`KeyedEmitter::open_array`].
177#[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    /// Consume the key and write an array value via closure.
185    ///
186    /// Best-effort scope guard: if the closure returns `Err`, the array close is
187    /// still attempted; the closure's error takes precedence.
188    ///
189    /// # Errors
190    ///
191    /// Returns `Err` if a key is not allowed here, or if the closure or backend errors.
192    #[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    /// Consume the key and write an object value via closure.
206    ///
207    /// Best-effort scope guard: if the closure returns `Err`, the object close is
208    /// still attempted; the closure's error takes precedence.
209    ///
210    /// # Errors
211    ///
212    /// Returns `Err` if a key is not allowed here, or if the closure or backend errors.
213    #[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    /// Consume the key and open an array. Caller must later call
227    /// [`JsonEmitter::close_array`] on the underlying emitter.
228    ///
229    /// # Errors
230    ///
231    /// Returns `Err` if a key is not allowed here, or if the backend errors.
232    #[inline]
233    pub fn open_array(self) -> Result<()> {
234        self.emitter.write_key(self.name)?;
235        self.emitter.open_array()
236    }
237
238    /// Consume the key and open an object. Caller must later call
239    /// [`JsonEmitter::close_object`] on the underlying emitter.
240    ///
241    /// # Errors
242    ///
243    /// Returns `Err` if a key is not allowed here, or if the backend errors.
244    #[inline]
245    pub fn open_object(self) -> Result<()> {
246        self.emitter.write_key(self.name)?;
247        self.emitter.open_object()
248    }
249
250    /// Consume the key and write a scalar value.
251    ///
252    /// # Errors
253    ///
254    /// Returns `Err` if a key is not allowed here, or if the backend errors.
255    #[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    /// Consume the key and write a string value via streaming closure.
265    ///
266    /// Best-effort scope guard: if the closure returns `Err`, the value mark is
267    /// still attempted; the closure's error takes precedence.
268    ///
269    /// # Errors
270    ///
271    /// Returns `Err` if a key is not allowed here, or if the closure or backend errors.
272    #[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}