Skip to main content

aws_smithy_types/document/
mod.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))]
7mod de;
8#[cfg(any(
9    all(aws_sdk_unstable, feature = "serde-deserialize"),
10    all(aws_sdk_unstable, feature = "serde-serialize")
11))]
12mod doc_error;
13#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))]
14mod ser;
15
16#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))]
17pub use de::from_document;
18#[cfg(any(
19    all(aws_sdk_unstable, feature = "serde-deserialize"),
20    all(aws_sdk_unstable, feature = "serde-serialize")
21))]
22pub use doc_error::DocError;
23#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))]
24pub use ser::to_document;
25
26use crate::Number;
27use std::borrow::Cow;
28use std::collections::HashMap;
29
30#[cfg(any(
31    all(aws_sdk_unstable, feature = "serde-deserialize"),
32    all(aws_sdk_unstable, feature = "serde-serialize")
33))]
34use serde;
35
36/// Document Type
37///
38/// Document types represents protocol-agnostic open content that is accessed like JSON data.
39/// Open content is useful for modeling unstructured data that has no schema, data that can't be
40/// modeled using rigid types, or data that has a schema that evolves outside of the purview of a model.
41/// The serialization format of a document is an implementation detail of a protocol.
42#[derive(Clone, Debug, PartialEq)]
43#[cfg_attr(
44    all(aws_sdk_unstable, feature = "serde-serialize"),
45    derive(serde::Serialize)
46)]
47#[cfg_attr(
48    all(aws_sdk_unstable, feature = "serde-deserialize"),
49    derive(serde::Deserialize)
50)]
51#[cfg_attr(
52    any(
53        all(aws_sdk_unstable, feature = "serde-deserialize"),
54        all(aws_sdk_unstable, feature = "serde-serialize")
55    ),
56    serde(untagged)
57)]
58pub enum Document {
59    /// JSON object
60    Object(HashMap<String, Document>),
61    /// JSON array
62    Array(Vec<Document>),
63    /// JSON number
64    Number(Number),
65    /// JSON string
66    String(String),
67    /// JSON boolean
68    Bool(bool),
69    /// JSON null
70    Null,
71}
72
73impl Document {
74    /// Returns the inner map value if this `Document` is an object.
75    pub fn as_object(&self) -> Option<&HashMap<String, Document>> {
76        if let Self::Object(object) = self {
77            Some(object)
78        } else {
79            None
80        }
81    }
82
83    /// Returns the mutable inner map value if this `Document` is an object.
84    pub fn as_object_mut(&mut self) -> Option<&mut HashMap<String, Document>> {
85        if let Self::Object(object) = self {
86            Some(object)
87        } else {
88            None
89        }
90    }
91
92    /// Returns the inner array value if this `Document` is an array.
93    pub fn as_array(&self) -> Option<&Vec<Document>> {
94        if let Self::Array(array) = self {
95            Some(array)
96        } else {
97            None
98        }
99    }
100
101    /// Returns the mutable inner array value if this `Document` is an array.
102    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Document>> {
103        if let Self::Array(array) = self {
104            Some(array)
105        } else {
106            None
107        }
108    }
109
110    /// Returns the inner number value if this `Document` is a number.
111    pub fn as_number(&self) -> Option<&Number> {
112        if let Self::Number(number) = self {
113            Some(number)
114        } else {
115            None
116        }
117    }
118
119    /// Returns the inner string value if this `Document` is a string.
120    pub fn as_string(&self) -> Option<&str> {
121        if let Self::String(string) = self {
122            Some(string)
123        } else {
124            None
125        }
126    }
127
128    /// Returns the inner boolean value if this `Document` is a boolean.
129    pub fn as_bool(&self) -> Option<bool> {
130        if let Self::Bool(boolean) = self {
131            Some(*boolean)
132        } else {
133            None
134        }
135    }
136
137    /// Returns `Some(())` if this `Document` is a null.
138    pub fn as_null(&self) -> Option<()> {
139        if let Self::Null = self {
140            Some(())
141        } else {
142            None
143        }
144    }
145
146    /// Returns `true` if this `Document` is an object.
147    pub fn is_object(&self) -> bool {
148        matches!(self, Self::Object(_))
149    }
150
151    /// Returns `true` if this `Document` is an array.
152    pub fn is_array(&self) -> bool {
153        matches!(self, Self::Array(_))
154    }
155
156    /// Returns `true` if this `Document` is a number.
157    pub fn is_number(&self) -> bool {
158        matches!(self, Self::Number(_))
159    }
160
161    /// Returns `true` if this `Document` is a string.
162    pub fn is_string(&self) -> bool {
163        matches!(self, Self::String(_))
164    }
165
166    /// Returns `true` if this `Document` is a bool.
167    pub fn is_bool(&self) -> bool {
168        matches!(self, Self::Bool(_))
169    }
170
171    /// Returns `true` if this `Document` is a boolean.
172    pub fn is_null(&self) -> bool {
173        matches!(self, Self::Null)
174    }
175}
176
177/// The default value is `Document::Null`.
178impl Default for Document {
179    fn default() -> Self {
180        Self::Null
181    }
182}
183
184impl From<bool> for Document {
185    fn from(value: bool) -> Self {
186        Document::Bool(value)
187    }
188}
189
190impl<'a> From<&'a str> for Document {
191    fn from(value: &'a str) -> Self {
192        Document::String(value.to_string())
193    }
194}
195
196impl<'a> From<Cow<'a, str>> for Document {
197    fn from(value: Cow<'a, str>) -> Self {
198        Document::String(value.into_owned())
199    }
200}
201
202impl From<String> for Document {
203    fn from(value: String) -> Self {
204        Document::String(value)
205    }
206}
207
208impl From<Vec<Document>> for Document {
209    fn from(values: Vec<Document>) -> Self {
210        Document::Array(values)
211    }
212}
213
214impl From<HashMap<String, Document>> for Document {
215    fn from(values: HashMap<String, Document>) -> Self {
216        Document::Object(values)
217    }
218}
219
220impl From<u64> for Document {
221    fn from(value: u64) -> Self {
222        Document::Number(Number::PosInt(value))
223    }
224}
225
226impl From<i64> for Document {
227    fn from(value: i64) -> Self {
228        Document::Number(Number::NegInt(value))
229    }
230}
231
232impl From<i32> for Document {
233    fn from(value: i32) -> Self {
234        Document::Number(Number::NegInt(value as i64))
235    }
236}
237
238impl From<f64> for Document {
239    fn from(value: f64) -> Self {
240        Document::Number(Number::Float(value))
241    }
242}
243
244impl From<Number> for Document {
245    fn from(value: Number) -> Self {
246        Document::Number(value)
247    }
248}
249
250impl<T> From<Option<T>> for Document
251where
252    Document: From<T>,
253{
254    fn from(value: Option<T>) -> Self {
255        match value {
256            Some(inner) => inner.into(),
257            None => Document::Null,
258        }
259    }
260}
261
262/* ANCHOR END: document */
263
264#[cfg(test)]
265#[cfg(all(
266    aws_sdk_unstable,
267    feature = "serde-serialize",
268    feature = "serde-deserialize"
269))]
270mod test {
271    use super::{from_document, to_document, Document};
272    use crate::Number;
273    use serde::{Deserialize, Serialize};
274    use std::collections::HashMap;
275
276    /// Helper: serialize a value to Document and verify the result.
277    fn test_to_document_ok<T>(cases: &[(T, Document)])
278    where
279        T: Serialize + std::fmt::Debug,
280    {
281        for (value, expected) in cases {
282            let doc = to_document(value).unwrap();
283            assert_eq!(&doc, expected, "to_document({:?})", value);
284        }
285    }
286
287    /// Helper: round-trip T → Document → T.
288    fn test_roundtrip<T>(cases: &[T])
289    where
290        T: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug + Clone,
291    {
292        for value in cases {
293            let doc = to_document(value).unwrap();
294            let roundtripped: T = from_document(doc).unwrap();
295            assert_eq!(&roundtripped, value, "roundtrip failed for {:?}", value);
296        }
297    }
298
299    // ========================================================================
300    // Null / Unit
301    // ========================================================================
302
303    #[test]
304    fn test_null() {
305        test_to_document_ok(&[((), Document::Null)]);
306
307        let v: () = from_document(Document::Null).unwrap();
308        assert_eq!(v, ());
309    }
310
311    // ========================================================================
312    // Booleans
313    // ========================================================================
314
315    #[test]
316    fn test_bool() {
317        test_to_document_ok(&[(true, Document::Bool(true)), (false, Document::Bool(false))]);
318        test_roundtrip(&[true, false]);
319    }
320
321    // ========================================================================
322    // Unsigned integers
323    // ========================================================================
324
325    #[test]
326    fn test_u8() {
327        test_to_document_ok(&[
328            (0u8, Document::Number(Number::PosInt(0))),
329            (u8::MAX, Document::Number(Number::PosInt(u8::MAX as u64))),
330        ]);
331        test_roundtrip(&[0u8, 1, 127, u8::MAX]);
332    }
333
334    #[test]
335    fn test_u16() {
336        test_to_document_ok(&[
337            (0u16, Document::Number(Number::PosInt(0))),
338            (u16::MAX, Document::Number(Number::PosInt(u16::MAX as u64))),
339        ]);
340        test_roundtrip(&[0u16, 1, u16::MAX]);
341    }
342
343    #[test]
344    fn test_u32() {
345        test_to_document_ok(&[
346            (0u32, Document::Number(Number::PosInt(0))),
347            (u32::MAX, Document::Number(Number::PosInt(u32::MAX as u64))),
348        ]);
349        test_roundtrip(&[0u32, 1, u32::MAX]);
350    }
351
352    #[test]
353    fn test_u64() {
354        test_to_document_ok(&[
355            (0u64, Document::Number(Number::PosInt(0))),
356            (u64::MAX, Document::Number(Number::PosInt(u64::MAX))),
357        ]);
358        test_roundtrip(&[0u64, 1, u64::MAX]);
359    }
360
361    // ========================================================================
362    // Signed integers
363    // ========================================================================
364
365    #[test]
366    fn test_i8() {
367        test_to_document_ok(&[
368            (0i8, Document::Number(Number::PosInt(0))),
369            (-1i8, Document::Number(Number::NegInt(-1))),
370            (i8::MIN, Document::Number(Number::NegInt(i8::MIN as i64))),
371            (i8::MAX, Document::Number(Number::PosInt(i8::MAX as u64))),
372        ]);
373        test_roundtrip(&[0i8, -1, 1, i8::MIN, i8::MAX]);
374    }
375
376    #[test]
377    fn test_i16() {
378        test_to_document_ok(&[
379            (0i16, Document::Number(Number::PosInt(0))),
380            (i16::MIN, Document::Number(Number::NegInt(i16::MIN as i64))),
381            (i16::MAX, Document::Number(Number::PosInt(i16::MAX as u64))),
382        ]);
383        test_roundtrip(&[0i16, -1, i16::MIN, i16::MAX]);
384    }
385
386    #[test]
387    fn test_i32() {
388        test_to_document_ok(&[
389            (0i32, Document::Number(Number::PosInt(0))),
390            (i32::MIN, Document::Number(Number::NegInt(i32::MIN as i64))),
391            (i32::MAX, Document::Number(Number::PosInt(i32::MAX as u64))),
392        ]);
393        test_roundtrip(&[0i32, -1, i32::MIN, i32::MAX]);
394    }
395
396    #[test]
397    fn test_i64() {
398        test_to_document_ok(&[
399            (0i64, Document::Number(Number::PosInt(0))),
400            (-1i64, Document::Number(Number::NegInt(-1))),
401            (i64::MIN, Document::Number(Number::NegInt(i64::MIN))),
402            (i64::MAX, Document::Number(Number::PosInt(i64::MAX as u64))),
403        ]);
404        test_roundtrip(&[0i64, -1, i64::MIN, i64::MAX]);
405    }
406
407    // ========================================================================
408    // Floats
409    // ========================================================================
410
411    #[test]
412    fn test_f32() {
413        test_to_document_ok(&[
414            (0.0f32, Document::Number(Number::Float(0.0))),
415            (3.5f32, Document::Number(Number::Float(3.5))),
416            (-1.5f32, Document::Number(Number::Float(-1.5))),
417        ]);
418        test_roundtrip(&[0.0f32, 3.5, -1.5, f32::MIN, f32::MAX]);
419    }
420
421    #[test]
422    fn test_f64() {
423        test_to_document_ok(&[
424            (0.0f64, Document::Number(Number::Float(0.0))),
425            (3.1f64, Document::Number(Number::Float(3.1))),
426            (-1.5f64, Document::Number(Number::Float(-1.5))),
427            (f64::MIN, Document::Number(Number::Float(f64::MIN))),
428            (f64::MAX, Document::Number(Number::Float(f64::MAX))),
429            (f64::EPSILON, Document::Number(Number::Float(f64::EPSILON))),
430        ]);
431        test_roundtrip(&[0.0f64, 3.1, -1.5, 0.5, f64::MIN, f64::MAX]);
432    }
433
434    #[test]
435    fn test_nonfinite_floats() {
436        // NaN, +Inf, -Inf all serialize to the float Document representation
437        let doc = to_document(&f64::NAN).unwrap();
438        match doc {
439            Document::Number(Number::Float(v)) => assert!(v.is_nan()),
440            other => panic!("expected NaN float, got {:?}", other),
441        }
442
443        let doc = to_document(&f64::INFINITY).unwrap();
444        assert_eq!(doc, Document::Number(Number::Float(f64::INFINITY)));
445
446        let doc = to_document(&f64::NEG_INFINITY).unwrap();
447        assert_eq!(doc, Document::Number(Number::Float(f64::NEG_INFINITY)));
448    }
449
450    // ========================================================================
451    // Strings
452    // ========================================================================
453
454    #[test]
455    fn test_string() {
456        test_to_document_ok(&[
457            (String::new(), Document::String(String::new())),
458            ("hello".to_owned(), Document::String("hello".to_owned())),
459            (
460                "with\nnewline".to_owned(),
461                Document::String("with\nnewline".to_owned()),
462            ),
463            (
464                "unicode: \u{1F600}".to_owned(),
465                Document::String("unicode: \u{1F600}".to_owned()),
466            ),
467        ]);
468        test_roundtrip(&[
469            String::new(),
470            "foo".to_owned(),
471            "bar\tbaz".to_owned(),
472            "\u{3A3}".to_owned(),
473        ]);
474    }
475
476    #[test]
477    fn test_str_ref() {
478        let doc = to_document(&"borrowed str").unwrap();
479        assert_eq!(doc, Document::String("borrowed str".to_owned()));
480    }
481
482    #[test]
483    fn test_char() {
484        let doc = to_document(&'a').unwrap();
485        assert_eq!(doc, Document::String("a".to_owned()));
486
487        let doc = to_document(&'\u{1F600}').unwrap();
488        assert_eq!(doc, Document::String("\u{1F600}".to_owned()));
489    }
490
491    // ========================================================================
492    // Option
493    // ========================================================================
494
495    #[test]
496    fn test_option() {
497        test_to_document_ok(&[
498            (None::<String>, Document::Null),
499            (
500                Some("jodhpurs".to_owned()),
501                Document::String("jodhpurs".to_owned()),
502            ),
503        ]);
504        test_to_document_ok(&[
505            (None::<u32>, Document::Null),
506            (Some(42u32), Document::Number(Number::PosInt(42))),
507        ]);
508        test_roundtrip(&[None::<u32>, Some(5), Some(0)]);
509        test_roundtrip(&[None::<String>, Some("x".to_owned())]);
510    }
511
512    // ========================================================================
513    // Sequences / Arrays
514    // ========================================================================
515
516    #[test]
517    fn test_vec_empty() {
518        let doc = to_document(&Vec::<i32>::new()).unwrap();
519        assert_eq!(doc, Document::Array(vec![]));
520
521        let v: Vec<i32> = from_document(Document::Array(vec![])).unwrap();
522        assert_eq!(v, Vec::<i32>::new());
523    }
524
525    #[test]
526    fn test_vec_integers() {
527        test_to_document_ok(&[(
528            vec![1u64, 2, 3],
529            Document::Array(vec![
530                Document::Number(Number::PosInt(1)),
531                Document::Number(Number::PosInt(2)),
532                Document::Number(Number::PosInt(3)),
533            ]),
534        )]);
535        test_roundtrip(&[vec![1i32, -2, 3], vec![], vec![0]]);
536    }
537
538    #[test]
539    fn test_vec_mixed_via_document() {
540        // Vec<Document> allows mixed types
541        let mixed = vec![
542            Document::Bool(true),
543            Document::Null,
544            Document::String("foo".to_owned()),
545            Document::Number(Number::PosInt(42)),
546        ];
547        let doc = Document::Array(mixed.clone());
548        let roundtripped: Vec<Document> = from_document(doc.clone()).unwrap();
549        assert_eq!(roundtripped, mixed);
550    }
551
552    #[test]
553    fn test_nested_vec() {
554        test_roundtrip(&[
555            vec![vec![1u32, 2], vec![], vec![3]],
556            vec![vec![], vec![], vec![]],
557        ]);
558    }
559
560    #[test]
561    fn test_tuple() {
562        let doc = to_document(&(5u32,)).unwrap();
563        assert_eq!(
564            doc,
565            Document::Array(vec![Document::Number(Number::PosInt(5))])
566        );
567
568        let doc = to_document(&(1u32, "abc", true)).unwrap();
569        assert_eq!(
570            doc,
571            Document::Array(vec![
572                Document::Number(Number::PosInt(1)),
573                Document::String("abc".to_owned()),
574                Document::Bool(true),
575            ])
576        );
577
578        test_roundtrip(&[(1u32, 2u32), (0, u32::MAX)]);
579        test_roundtrip(&[(1i32, "hello".to_owned(), true)]);
580    }
581
582    // ========================================================================
583    // Maps / Objects
584    // ========================================================================
585
586    #[test]
587    fn test_map_empty() {
588        let map: HashMap<String, u32> = HashMap::new();
589        let doc = to_document(&map).unwrap();
590        assert_eq!(doc, Document::Object(HashMap::new()));
591        test_roundtrip(&[HashMap::<String, u32>::new()]);
592    }
593
594    #[test]
595    fn test_map_string_keys() {
596        let mut map = HashMap::new();
597        map.insert("a".to_owned(), 1u32);
598        map.insert("b".to_owned(), 2u32);
599        test_roundtrip(&[map]);
600    }
601
602    #[test]
603    fn test_map_integer_keys() {
604        // Integer keys get serialized as their string representation
605        let mut map = HashMap::new();
606        map.insert(1u32, "one".to_owned());
607        map.insert(2u32, "two".to_owned());
608
609        let doc = to_document(&map).unwrap();
610        assert!(doc.is_object());
611        let obj = doc.as_object().unwrap();
612        assert!(obj.contains_key("1") || obj.contains_key("2"));
613    }
614
615    #[test]
616    fn test_nested_map() {
617        let mut inner = HashMap::new();
618        inner.insert("x".to_owned(), 10u32);
619
620        let mut outer = HashMap::new();
621        outer.insert("inner".to_owned(), inner.clone());
622
623        test_roundtrip(&[outer]);
624    }
625
626    // ========================================================================
627    // Structs
628    // ========================================================================
629
630    #[test]
631    fn test_struct() {
632        #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
633        struct Inner {
634            a: (),
635            b: usize,
636            c: Vec<String>,
637        }
638
639        #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
640        struct Outer {
641            inner: Vec<Inner>,
642        }
643
644        let outer = Outer {
645            inner: vec![Inner {
646                a: (),
647                b: 2,
648                c: vec!["abc".to_owned(), "xyz".to_owned()],
649            }],
650        };
651
652        let doc = to_document(&outer).unwrap();
653        assert!(doc.is_object());
654        let roundtripped: Outer = from_document(doc).unwrap();
655        assert_eq!(outer, roundtripped);
656
657        // Empty inner
658        test_roundtrip(&[Outer { inner: vec![] }]);
659    }
660
661    #[test]
662    fn test_newtype_struct() {
663        #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
664        struct Wrapper(u32);
665
666        test_to_document_ok(&[(Wrapper(123), Document::Number(Number::PosInt(123)))]);
667        test_roundtrip(&[Wrapper(0), Wrapper(u32::MAX)]);
668    }
669
670    #[test]
671    fn test_unit_struct() {
672        #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
673        struct Unit;
674
675        test_to_document_ok(&[(Unit, Document::Null)]);
676        let v: Unit = from_document(Document::Null).unwrap();
677        assert_eq!(v, Unit);
678    }
679
680    // ========================================================================
681    // Enums
682    // ========================================================================
683
684    #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
685    enum Animal {
686        Dog,
687        Frog(String, Vec<isize>),
688        Cat { age: usize, name: String },
689        AntHive(Vec<String>),
690    }
691
692    #[test]
693    fn test_enum_unit_variant() {
694        let doc = to_document(&Animal::Dog).unwrap();
695        assert_eq!(doc, Document::String("Dog".to_owned()));
696        test_roundtrip(&[Animal::Dog]);
697    }
698
699    #[test]
700    fn test_enum_tuple_variant() {
701        let frog = Animal::Frog("Henry".to_owned(), vec![349, 102]);
702        let doc = to_document(&frog).unwrap();
703        assert!(doc.is_object());
704        let obj = doc.as_object().unwrap();
705        assert!(obj.contains_key("Frog"));
706        test_roundtrip(&[
707            Animal::Frog("Henry".to_owned(), vec![]),
708            Animal::Frog("Henry".to_owned(), vec![349, 102]),
709        ]);
710    }
711
712    #[test]
713    fn test_enum_struct_variant() {
714        let cat = Animal::Cat {
715            age: 5,
716            name: "Kate".to_owned(),
717        };
718        let doc = to_document(&cat).unwrap();
719        assert!(doc.is_object());
720        let obj = doc.as_object().unwrap();
721        assert!(obj.contains_key("Cat"));
722        test_roundtrip(&[cat]);
723    }
724
725    #[test]
726    fn test_enum_newtype_variant() {
727        let hive = Animal::AntHive(vec!["Bob".to_owned(), "Stuart".to_owned()]);
728        test_roundtrip(&[hive]);
729    }
730
731    // ========================================================================
732    // Bytes
733    // ========================================================================
734
735    #[test]
736    fn test_bytes() {
737        // Bytes serialize as an array of numbers
738        let data: &[u8] = &[1, 2, 3];
739        let doc = to_document(&data).unwrap();
740        assert_eq!(
741            doc,
742            Document::Array(vec![
743                Document::Number(Number::PosInt(1)),
744                Document::Number(Number::PosInt(2)),
745                Document::Number(Number::PosInt(3)),
746            ])
747        );
748
749        let empty: &[u8] = &[];
750        let doc = to_document(&empty).unwrap();
751        assert_eq!(doc, Document::Array(vec![]));
752    }
753
754    // ========================================================================
755    // Error cases
756    // ========================================================================
757
758    #[test]
759    fn test_deserialize_wrong_type() {
760        let result = from_document::<bool>(Document::String("not a bool".to_owned()));
761        assert!(result.is_err());
762        let err = result.unwrap_err();
763        assert!(
764            err.to_string().contains("invalid type"),
765            "unexpected error message: {}",
766            err
767        );
768    }
769
770    #[test]
771    fn test_deserialize_missing_field() {
772        #[derive(Debug, Deserialize)]
773        struct Required {
774            #[allow(dead_code)]
775            x: u32,
776        }
777
778        let doc = Document::Object(HashMap::new());
779        let result = from_document::<Required>(doc);
780        assert!(result.is_err());
781        let err = result.unwrap_err();
782        assert!(err.to_string().contains("missing field"));
783    }
784
785    #[test]
786    fn test_serialize_non_string_map_key_rejected() {
787        // Map keys that cannot be coerced to strings should fail
788        use std::collections::HashMap;
789        let mut map: HashMap<Option<u32>, u32> = HashMap::new();
790        map.insert(None, 1);
791
792        let result = to_document(&map);
793        assert!(result.is_err());
794    }
795
796    // ========================================================================
797    // serde_json compatibility (existing test)
798    // ========================================================================
799
800    #[test]
801    fn test_serde_json_compatibility() {
802        let mut map: HashMap<String, Document> = HashMap::new();
803        map.insert("hello".into(), "world".to_string().into());
804        map.insert("pos_int".into(), Document::Number(Number::PosInt(1).into()));
805        map.insert(
806            "neg_int".into(),
807            Document::Number(Number::NegInt(-1).into()),
808        );
809        map.insert(
810            "float".into(),
811            Document::Number(Number::Float(0.1 + 0.2).into()),
812        );
813        map.insert("true".into(), true.into());
814        map.insert("false".into(), false.into());
815        map.insert(
816            "array".into(),
817            vec![
818                map.clone().into(),
819                "hello-world".to_string().into(),
820                true.into(),
821                false.into(),
822            ]
823            .into(),
824        );
825        map.insert("map".into(), map.clone().into());
826        map.insert("null".into(), Document::Null);
827        let obj = Document::Object(map);
828
829        let target_file = include_str!("../../test_data/serialize_document.json");
830        let json: Result<serde_json::Value, _> = serde_json::from_str(target_file);
831        assert_eq!(serde_json::to_value(&obj).unwrap(), json.unwrap());
832        let doc: Result<Document, _> = serde_json::from_str(target_file);
833        assert_eq!(obj, doc.unwrap());
834    }
835}