aws_smithy_json/codec/
deserializer.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! JSON deserializer implementation.
7
8use aws_smithy_schema::serde::ShapeDeserializer;
9use aws_smithy_schema::Schema;
10use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime, Document, Number};
11use std::fmt;
12
13use crate::codec::JsonCodecSettings;
14use crate::deserialize::{json_token_iter, Token};
15
16/// Error type for JSON deserialization.
17#[derive(Debug)]
18pub enum JsonDeserializerError {
19    /// An error occurred during JSON parsing.
20    ParseError(String),
21}
22
23impl fmt::Display for JsonDeserializerError {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        match self {
26            Self::ParseError(msg) => write!(f, "JSON parse error: {}", msg),
27        }
28    }
29}
30
31impl std::error::Error for JsonDeserializerError {}
32
33/// JSON deserializer that implements the ShapeDeserializer trait.
34pub struct JsonDeserializer {
35    input: Vec<u8>,
36    position: usize,
37    _settings: JsonCodecSettings,
38}
39
40impl JsonDeserializer {
41    /// Creates a new JSON deserializer with the given settings.
42    pub fn new(input: &[u8], settings: JsonCodecSettings) -> Self {
43        Self {
44            input: input.to_vec(),
45            position: 0,
46            _settings: settings,
47        }
48    }
49
50    fn remaining(&self) -> &[u8] {
51        &self.input[self.position..]
52    }
53
54    fn advance_by(&mut self, n: usize) {
55        self.position += n;
56    }
57}
58
59impl ShapeDeserializer for JsonDeserializer {
60    type Error = JsonDeserializerError;
61
62    fn read_struct<T, F>(
63        &mut self,
64        schema: &dyn Schema,
65        mut state: T,
66        mut consumer: F,
67    ) -> Result<T, Self::Error>
68    where
69        F: FnMut(T, &dyn Schema, &mut Self) -> Result<T, Self::Error>,
70    {
71        // Expect opening brace
72        self.skip_whitespace();
73        if self.remaining().first() != Some(&b'{') {
74            return Err(JsonDeserializerError::ParseError("Expected object".into()));
75        }
76        self.advance_by(1);
77
78        loop {
79            self.skip_whitespace();
80
81            // Check for end of object
82            if self.remaining().first() == Some(&b'}') {
83                self.advance_by(1);
84                break;
85            }
86
87            // Expect a key (quoted string)
88            if self.remaining().first() != Some(&b'"') {
89                return Err(JsonDeserializerError::ParseError(
90                    "Expected object key".into(),
91                ));
92            }
93
94            // Parse the key using the token iterator
95            let mut iter = json_token_iter(self.remaining());
96            let key_str = match iter.next() {
97                Some(Ok(Token::ValueString { value, .. })) => {
98                    let key_len = value.as_escaped_str().len();
99                    let key = value
100                        .to_unescaped()
101                        .map_err(|e| JsonDeserializerError::ParseError(e.to_string()))?
102                        .into_owned();
103                    // Advance past opening quote + key + closing quote
104                    self.advance_by(key_len + 2);
105                    key
106                }
107                _ => {
108                    return Err(JsonDeserializerError::ParseError(
109                        "Expected object key".into(),
110                    ))
111                }
112            };
113
114            // Skip whitespace and expect colon
115            self.skip_whitespace();
116            if self.remaining().first() != Some(&b':') {
117                return Err(JsonDeserializerError::ParseError(
118                    "Expected colon after key".into(),
119                ));
120            }
121            self.advance_by(1);
122            self.skip_whitespace();
123
124            // Process the value
125            if let Some(member_schema) = schema.member_schema(&key_str) {
126                state = consumer(state, member_schema, self)?;
127            } else {
128                self.skip_value()?;
129            }
130        }
131
132        Ok(state)
133    }
134
135    fn read_list<T, F>(
136        &mut self,
137        _schema: &dyn Schema,
138        mut state: T,
139        mut consumer: F,
140    ) -> Result<T, Self::Error>
141    where
142        F: FnMut(T, &mut Self) -> Result<T, Self::Error>,
143    {
144        self.skip_whitespace();
145        if self.remaining().first() != Some(&b'[') {
146            return Err(JsonDeserializerError::ParseError("Expected array".into()));
147        }
148        self.advance_by(1);
149
150        loop {
151            self.skip_whitespace();
152            if self.remaining().first() == Some(&b']') {
153                self.advance_by(1);
154                break;
155            }
156            state = consumer(state, self)?;
157        }
158
159        Ok(state)
160    }
161
162    fn read_map<T, F>(
163        &mut self,
164        _schema: &dyn Schema,
165        mut state: T,
166        mut consumer: F,
167    ) -> Result<T, Self::Error>
168    where
169        F: FnMut(T, String, &mut Self) -> Result<T, Self::Error>,
170    {
171        self.skip_whitespace();
172        if self.remaining().first() != Some(&b'{') {
173            return Err(JsonDeserializerError::ParseError("Expected object".into()));
174        }
175        self.advance_by(1);
176
177        loop {
178            self.skip_whitespace();
179            if self.remaining().first() == Some(&b'}') {
180                self.advance_by(1);
181                break;
182            }
183
184            if self.remaining().first() != Some(&b'"') {
185                return Err(JsonDeserializerError::ParseError("Expected key".into()));
186            }
187
188            let mut iter = json_token_iter(self.remaining());
189            let key = match iter.next() {
190                Some(Ok(Token::ValueString { value, .. })) => {
191                    let len = value.as_escaped_str().len();
192                    let key = value
193                        .to_unescaped()
194                        .map_err(|e| JsonDeserializerError::ParseError(e.to_string()))?
195                        .into_owned();
196                    self.advance_by(len + 2);
197                    key
198                }
199                _ => return Err(JsonDeserializerError::ParseError("Expected key".into())),
200            };
201
202            self.skip_whitespace();
203            if self.remaining().first() != Some(&b':') {
204                return Err(JsonDeserializerError::ParseError("Expected colon".into()));
205            }
206            self.advance_by(1);
207            self.skip_whitespace();
208
209            state = consumer(state, key, self)?;
210        }
211
212        Ok(state)
213    }
214
215    fn read_boolean(&mut self, _schema: &dyn Schema) -> Result<bool, Self::Error> {
216        let mut iter = json_token_iter(self.remaining());
217        match iter.next() {
218            Some(Ok(Token::ValueBool { value, .. })) => {
219                self.advance_by(if value { 4 } else { 5 });
220                Ok(value)
221            }
222            _ => Err(JsonDeserializerError::ParseError("Expected boolean".into())),
223        }
224    }
225
226    fn read_byte(&mut self, _schema: &dyn Schema) -> Result<i8, Self::Error> {
227        self.read_integer_value().and_then(|n| {
228            i8::try_from(n).map_err(|_| {
229                JsonDeserializerError::ParseError("Value out of range for byte".into())
230            })
231        })
232    }
233
234    fn read_short(&mut self, _schema: &dyn Schema) -> Result<i16, Self::Error> {
235        self.read_integer_value().and_then(|n| {
236            i16::try_from(n).map_err(|_| {
237                JsonDeserializerError::ParseError("Value out of range for short".into())
238            })
239        })
240    }
241
242    fn read_integer(&mut self, _schema: &dyn Schema) -> Result<i32, Self::Error> {
243        self.read_integer_value().and_then(|n| {
244            i32::try_from(n).map_err(|_| {
245                JsonDeserializerError::ParseError("Value out of range for integer".into())
246            })
247        })
248    }
249
250    fn read_long(&mut self, _schema: &dyn Schema) -> Result<i64, Self::Error> {
251        self.read_integer_value()
252    }
253
254    fn read_float(&mut self, _schema: &dyn Schema) -> Result<f32, Self::Error> {
255        self.read_float_value().map(|f| f as f32)
256    }
257
258    fn read_double(&mut self, _schema: &dyn Schema) -> Result<f64, Self::Error> {
259        self.read_float_value()
260    }
261
262    fn read_big_integer(&mut self, _schema: &dyn Schema) -> Result<BigInteger, Self::Error> {
263        use std::str::FromStr;
264        let mut iter = json_token_iter(self.remaining());
265        match iter.next() {
266            Some(Ok(Token::ValueNumber { .. })) => {
267                self.consume_number();
268                BigInteger::from_str("0")
269                    .map_err(|e| JsonDeserializerError::ParseError(e.to_string()))
270            }
271            _ => Err(JsonDeserializerError::ParseError("Expected number".into())),
272        }
273    }
274
275    fn read_big_decimal(&mut self, _schema: &dyn Schema) -> Result<BigDecimal, Self::Error> {
276        use std::str::FromStr;
277        let mut iter = json_token_iter(self.remaining());
278        match iter.next() {
279            Some(Ok(Token::ValueNumber { .. })) => {
280                self.consume_number();
281                BigDecimal::from_str("0")
282                    .map_err(|e| JsonDeserializerError::ParseError(e.to_string()))
283            }
284            _ => Err(JsonDeserializerError::ParseError("Expected number".into())),
285        }
286    }
287
288    fn read_string(&mut self, _schema: &dyn Schema) -> Result<String, Self::Error> {
289        let mut iter = json_token_iter(self.remaining());
290        match iter.next() {
291            Some(Ok(Token::ValueString { value, .. })) => {
292                let len = value.as_escaped_str().len();
293                let result = value
294                    .to_unescaped()
295                    .map(|s| s.into_owned())
296                    .map_err(|e| JsonDeserializerError::ParseError(e.to_string()))?;
297                self.advance_by(len + 2);
298                Ok(result)
299            }
300            _ => Err(JsonDeserializerError::ParseError("Expected string".into())),
301        }
302    }
303
304    fn read_blob(&mut self, _schema: &dyn Schema) -> Result<Blob, Self::Error> {
305        let s = self.read_string(_schema)?;
306        Ok(Blob::new(s.into_bytes()))
307    }
308
309    fn read_timestamp(&mut self, _schema: &dyn Schema) -> Result<DateTime, Self::Error> {
310        let mut iter = json_token_iter(self.remaining());
311        match iter.next() {
312            Some(Ok(Token::ValueNumber {
313                value: Number::PosInt(n),
314                ..
315            })) => {
316                self.consume_number();
317                Ok(DateTime::from_secs(n as i64))
318            }
319            Some(Ok(Token::ValueNumber {
320                value: Number::NegInt(n),
321                ..
322            })) => {
323                self.consume_number();
324                Ok(DateTime::from_secs(n))
325            }
326            _ => Err(JsonDeserializerError::ParseError(
327                "Expected timestamp".into(),
328            )),
329        }
330    }
331
332    fn read_document(&mut self, _schema: &dyn Schema) -> Result<Document, Self::Error> {
333        let mut iter = json_token_iter(self.remaining());
334        match iter.next() {
335            Some(Ok(Token::ValueNull { .. })) => {
336                self.advance_by(4);
337                Ok(Document::Null)
338            }
339            _ => Err(JsonDeserializerError::ParseError(
340                "Document deserialization not fully implemented".into(),
341            )),
342        }
343    }
344
345    fn is_null(&self) -> bool {
346        let mut iter = json_token_iter(self.remaining());
347        matches!(iter.next(), Some(Ok(Token::ValueNull { .. })))
348    }
349
350    fn container_size(&self) -> Option<usize> {
351        let mut iter = json_token_iter(self.remaining());
352        match iter.next()? {
353            Ok(Token::StartArray { .. }) => {
354                let mut count = 0;
355                let mut depth = 1;
356                for token in iter {
357                    match token {
358                        Ok(Token::StartArray { .. }) | Ok(Token::StartObject { .. }) => {
359                            if depth == 1 {
360                                count += 1;
361                            }
362                            depth += 1;
363                        }
364                        Ok(Token::EndArray { .. }) | Ok(Token::EndObject { .. }) => {
365                            depth -= 1;
366                            if depth == 0 {
367                                return Some(count);
368                            }
369                        }
370                        Ok(Token::ValueBool { .. })
371                        | Ok(Token::ValueNull { .. })
372                        | Ok(Token::ValueString { .. })
373                        | Ok(Token::ValueNumber { .. })
374                            if depth == 1 =>
375                        {
376                            count += 1
377                        }
378                        _ => {}
379                    }
380                }
381                None
382            }
383            Ok(Token::StartObject { .. }) => {
384                let mut count = 0;
385                let mut depth = 1;
386                for token in iter {
387                    match token {
388                        Ok(Token::StartArray { .. }) | Ok(Token::StartObject { .. }) => depth += 1,
389                        Ok(Token::EndArray { .. }) | Ok(Token::EndObject { .. }) => {
390                            depth -= 1;
391                            if depth == 0 {
392                                return Some(count);
393                            }
394                        }
395                        Ok(Token::ObjectKey { .. }) if depth == 1 => count += 1,
396                        _ => {}
397                    }
398                }
399                None
400            }
401            _ => None,
402        }
403    }
404}
405
406impl JsonDeserializer {
407    fn skip_whitespace(&mut self) {
408        while self.position < self.input.len() {
409            match self.input[self.position] {
410                b' ' | b'\t' | b'\n' | b'\r' | b',' => self.position += 1,
411                _ => break,
412            }
413        }
414    }
415
416    fn consume_number(&mut self) {
417        let mut len = 0;
418        for &b in self.remaining() {
419            if b.is_ascii_digit() || b == b'-' || b == b'.' || b == b'e' || b == b'E' || b == b'+' {
420                len += 1;
421            } else {
422                break;
423            }
424        }
425        self.advance_by(len);
426    }
427
428    fn skip_value(&mut self) -> Result<(), JsonDeserializerError> {
429        let mut depth = 0;
430        loop {
431            let mut iter = json_token_iter(self.remaining());
432            match iter.next() {
433                Some(Ok(Token::StartObject { .. })) | Some(Ok(Token::StartArray { .. })) => {
434                    self.advance_by(1);
435                    depth += 1;
436                }
437                Some(Ok(Token::EndObject { .. })) | Some(Ok(Token::EndArray { .. })) => {
438                    self.advance_by(1);
439                    if depth == 0 {
440                        return Err(JsonDeserializerError::ParseError(
441                            "Unexpected end token".into(),
442                        ));
443                    }
444                    depth -= 1;
445                    if depth == 0 {
446                        return Ok(());
447                    }
448                }
449                Some(Ok(Token::ValueBool { value, .. })) if depth == 0 => {
450                    self.advance_by(if value { 4 } else { 5 });
451                    return Ok(());
452                }
453                Some(Ok(Token::ValueNull { .. })) if depth == 0 => {
454                    self.advance_by(4);
455                    return Ok(());
456                }
457                Some(Ok(Token::ValueString { value, .. })) if depth == 0 => {
458                    self.advance_by(value.as_escaped_str().len() + 2);
459                    return Ok(());
460                }
461                Some(Ok(Token::ValueNumber { .. })) if depth == 0 => {
462                    self.consume_number();
463                    return Ok(());
464                }
465                Some(Ok(Token::ObjectKey { key, .. })) => {
466                    self.advance_by(key.as_escaped_str().len() + 3);
467                }
468                Some(Ok(_)) => {}
469                Some(Err(e)) => return Err(JsonDeserializerError::ParseError(e.to_string())),
470                None => {
471                    return Err(JsonDeserializerError::ParseError(
472                        "Unexpected end of input".into(),
473                    ))
474                }
475            }
476        }
477    }
478
479    fn read_integer_value(&mut self) -> Result<i64, JsonDeserializerError> {
480        let mut iter = json_token_iter(self.remaining());
481        match iter.next() {
482            Some(Ok(Token::ValueNumber {
483                value: Number::PosInt(n),
484                ..
485            })) => {
486                self.consume_number();
487                i64::try_from(n)
488                    .map_err(|_| JsonDeserializerError::ParseError("Value out of range".into()))
489            }
490            Some(Ok(Token::ValueNumber {
491                value: Number::NegInt(n),
492                ..
493            })) => {
494                self.consume_number();
495                Ok(n)
496            }
497            _ => Err(JsonDeserializerError::ParseError("Expected integer".into())),
498        }
499    }
500
501    fn read_float_value(&mut self) -> Result<f64, JsonDeserializerError> {
502        let mut iter = json_token_iter(self.remaining());
503        match iter.next() {
504            Some(Ok(Token::ValueNumber {
505                value: Number::Float(f),
506                ..
507            })) => {
508                self.consume_number();
509                Ok(f)
510            }
511            Some(Ok(Token::ValueNumber {
512                value: Number::PosInt(n),
513                ..
514            })) => {
515                self.consume_number();
516                Ok(n as f64)
517            }
518            Some(Ok(Token::ValueNumber {
519                value: Number::NegInt(n),
520                ..
521            })) => {
522                self.consume_number();
523                Ok(n as f64)
524            }
525            _ => Err(JsonDeserializerError::ParseError("Expected number".into())),
526        }
527    }
528}
529
530#[cfg(test)]
531mod tests {
532    use super::*;
533
534    fn dummy_schema() -> &'static impl aws_smithy_schema::Schema {
535        &aws_smithy_schema::prelude::STRING
536    }
537
538    #[test]
539    fn test_read_boolean() {
540        let mut deser = JsonDeserializer::new(b"true", JsonCodecSettings::default());
541        assert_eq!(deser.read_boolean(dummy_schema()).unwrap(), true);
542
543        let mut deser = JsonDeserializer::new(b"false", JsonCodecSettings::default());
544        assert_eq!(deser.read_boolean(dummy_schema()).unwrap(), false);
545    }
546
547    #[test]
548    fn test_read_integer() {
549        let mut deser = JsonDeserializer::new(b"42", JsonCodecSettings::default());
550        assert_eq!(deser.read_integer(dummy_schema()).unwrap(), 42);
551
552        let mut deser = JsonDeserializer::new(b"-123", JsonCodecSettings::default());
553        assert_eq!(deser.read_integer(dummy_schema()).unwrap(), -123);
554    }
555
556    #[test]
557    fn test_read_long() {
558        let mut deser = JsonDeserializer::new(b"9223372036854775807", JsonCodecSettings::default());
559        assert_eq!(deser.read_long(dummy_schema()).unwrap(), i64::MAX);
560    }
561
562    #[test]
563    fn test_read_float() {
564        let mut deser = JsonDeserializer::new(b"3.14", JsonCodecSettings::default());
565        assert!((deser.read_float(dummy_schema()).unwrap() - 3.14).abs() < 0.01);
566    }
567
568    #[test]
569    fn test_read_double() {
570        let mut deser = JsonDeserializer::new(b"2.718", JsonCodecSettings::default());
571        assert!((deser.read_double(dummy_schema()).unwrap() - 2.718).abs() < 0.001);
572    }
573
574    #[test]
575    fn test_read_string() {
576        let mut deser = JsonDeserializer::new(br#""hello world""#, JsonCodecSettings::default());
577        assert_eq!(deser.read_string(dummy_schema()).unwrap(), "hello world");
578
579        let mut deser = JsonDeserializer::new(br#""hello\nworld""#, JsonCodecSettings::default());
580        assert_eq!(deser.read_string(dummy_schema()).unwrap(), "hello\nworld");
581    }
582
583    #[test]
584    fn test_is_null() {
585        let deser = JsonDeserializer::new(b"null", JsonCodecSettings::default());
586        assert!(deser.is_null());
587
588        let deser = JsonDeserializer::new(b"42", JsonCodecSettings::default());
589        assert!(!deser.is_null());
590    }
591
592    #[test]
593    fn test_read_byte_range() {
594        let mut deser = JsonDeserializer::new(b"127", JsonCodecSettings::default());
595        assert_eq!(deser.read_byte(dummy_schema()).unwrap(), 127);
596
597        let mut deser = JsonDeserializer::new(b"128", JsonCodecSettings::default());
598        assert!(deser.read_byte(dummy_schema()).is_err());
599    }
600
601    #[test]
602    fn test_read_struct() {
603        use aws_smithy_schema::{prelude, Schema, ShapeId, ShapeType, TraitMap};
604
605        #[derive(Debug, Default, PartialEq)]
606        struct Person {
607            first_name: String,
608            last_name: String,
609            age: i32,
610        }
611
612        struct MemberSchema {
613            name: &'static str,
614            target: &'static dyn Schema,
615        }
616
617        impl Schema for MemberSchema {
618            fn shape_id(&self) -> &ShapeId {
619                self.target.shape_id()
620            }
621            fn shape_type(&self) -> ShapeType {
622                self.target.shape_type()
623            }
624            fn traits(&self) -> &TraitMap {
625                self.target.traits()
626            }
627            fn member_name(&self) -> Option<&str> {
628                Some(self.name)
629            }
630        }
631
632        static FIRST_NAME: MemberSchema = MemberSchema {
633            name: "firstName",
634            target: &prelude::STRING,
635        };
636        static LAST_NAME: MemberSchema = MemberSchema {
637            name: "lastName",
638            target: &prelude::STRING,
639        };
640        static AGE: MemberSchema = MemberSchema {
641            name: "age",
642            target: &prelude::INTEGER,
643        };
644
645        struct TestSchema;
646        impl Schema for TestSchema {
647            fn shape_id(&self) -> &ShapeId {
648                static ID: std::sync::LazyLock<ShapeId> =
649                    std::sync::LazyLock::new(|| ShapeId::from_static("test#Test", "test", "Test"));
650                &ID
651            }
652            fn shape_type(&self) -> ShapeType {
653                ShapeType::Structure
654            }
655            fn traits(&self) -> &TraitMap {
656                static MAP: std::sync::LazyLock<TraitMap> = std::sync::LazyLock::new(TraitMap::new);
657                &MAP
658            }
659            fn member_schema(&self, name: &str) -> Option<&dyn Schema> {
660                match name {
661                    "firstName" => Some(&FIRST_NAME),
662                    "lastName" => Some(&LAST_NAME),
663                    "age" => Some(&AGE),
664                    _ => None,
665                }
666            }
667            fn member_schema_by_index(&self, index: usize) -> Option<(&str, &dyn Schema)> {
668                match index {
669                    0 => Some(("firstName", &FIRST_NAME)),
670                    1 => Some(("lastName", &LAST_NAME)),
671                    2 => Some(("age", &AGE)),
672                    _ => None,
673                }
674            }
675        }
676
677        fn consume_person(
678            mut person: Person,
679            schema: &dyn Schema,
680            deser: &mut JsonDeserializer,
681        ) -> Result<Person, JsonDeserializerError> {
682            match schema.member_name() {
683                Some("firstName") => person.first_name = deser.read_string(schema)?,
684                Some("lastName") => person.last_name = deser.read_string(schema)?,
685                Some("age") => person.age = deser.read_integer(schema)?,
686                _ => {}
687            }
688            Ok(person)
689        }
690
691        let json = br#"{"lastName":"Smithy","firstName":"Alice","age":30}"#;
692        let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
693        let person = deser
694            .read_struct(&TestSchema, Person::default(), consume_person)
695            .unwrap();
696        assert_eq!(
697            person,
698            Person {
699                first_name: "Alice".to_string(),
700                last_name: "Smithy".to_string(),
701                age: 30
702            }
703        );
704
705        let json =
706            br#"{"firstName":          "Alice","age":12345678,     "lastName":"\"Smithy\""}"#;
707        let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
708        let person = deser
709            .read_struct(&TestSchema, Person::default(), consume_person)
710            .unwrap();
711        assert_eq!(
712            person,
713            Person {
714                first_name: "Alice".to_string(),
715                last_name: "\"Smithy\"".to_string(),
716                age: 12345678
717            }
718        );
719    }
720
721    #[test]
722    fn test_read_list() {
723        let json = b"[1, 2, 3, 4, 5]";
724        let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
725        let capacity = deser.container_size().unwrap_or(0);
726        let container = Vec::with_capacity(capacity);
727        let allocated_capacity = container.capacity();
728        let result = deser
729            .read_list(dummy_schema(), container, |mut vec, deser| {
730                vec.push(deser.read_integer(dummy_schema())?);
731                Ok(vec)
732            })
733            .unwrap();
734        assert_eq!(result, vec![1, 2, 3, 4, 5]);
735        // Ensure no more memory was allocated for the container
736        assert_eq!(result.capacity(), allocated_capacity);
737
738        let json = b"[]";
739        let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
740        let capacity = deser.container_size().unwrap_or(0);
741        let container = Vec::with_capacity(capacity);
742        let allocated_capacity = container.capacity();
743        let result = deser
744            .read_list(dummy_schema(), container, |mut vec, deser| {
745                vec.push(deser.read_integer(dummy_schema())?);
746                Ok(vec)
747            })
748            .unwrap();
749        assert_eq!(result, Vec::<i32>::new());
750        // Ensure no more memory was allocated for the container
751        assert_eq!(result.capacity(), allocated_capacity);
752
753        let json = br#"["hello", "world"]"#;
754        let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
755        let capacity = deser.container_size().unwrap_or(0);
756        let container = Vec::with_capacity(capacity);
757        let allocated_capacity = container.capacity();
758        let result = deser
759            .read_list(dummy_schema(), container, |mut vec, deser| {
760                vec.push(deser.read_string(dummy_schema())?);
761                Ok(vec)
762            })
763            .unwrap();
764        assert_eq!(result, vec!["hello", "world"]);
765        // Ensure no more memory was allocated for the container
766        assert_eq!(result.capacity(), allocated_capacity);
767    }
768
769    #[test]
770    fn test_container_size() {
771        let deser = JsonDeserializer::new(b"[1, 2, 3, 4, 5]", JsonCodecSettings::default());
772        assert_eq!(deser.container_size(), Some(5));
773
774        let deser = JsonDeserializer::new(b"[]", JsonCodecSettings::default());
775        assert_eq!(deser.container_size(), Some(0));
776
777        let deser =
778            JsonDeserializer::new(br#"{"a": 1, "b": 2, "c": 3}"#, JsonCodecSettings::default());
779        assert_eq!(deser.container_size(), Some(3));
780
781        let deser = JsonDeserializer::new(b"{}", JsonCodecSettings::default());
782        assert_eq!(deser.container_size(), Some(0));
783
784        let deser =
785            JsonDeserializer::new(b"[[1, 2], [3, 4], [5, 6]]", JsonCodecSettings::default());
786        assert_eq!(deser.container_size(), Some(3));
787
788        let deser = JsonDeserializer::new(b"42", JsonCodecSettings::default());
789        assert_eq!(deser.container_size(), None);
790    }
791
792    #[test]
793    fn test_read_map() {
794        use std::collections::HashMap;
795
796        let json = br#"{"a": 1, "b": 2, "c": 3}"#;
797        let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
798        let calculated_capacity = deser.container_size().unwrap_or(0);
799        let container = HashMap::with_capacity(calculated_capacity);
800        let allocated_capacity = container.capacity();
801        let result = deser
802            .read_map(dummy_schema(), container, |mut map, key, deser| {
803                map.insert(key, deser.read_integer(dummy_schema())?);
804                Ok(map)
805            })
806            .unwrap();
807        assert_eq!(result.len(), 3);
808        assert_eq!(result.get("a"), Some(&1));
809        assert_eq!(result.get("b"), Some(&2));
810        assert_eq!(result.get("c"), Some(&3));
811        // Ensure no more memory was allocated for the container
812        assert_eq!(result.capacity(), allocated_capacity);
813
814        let json = b"{}";
815        let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
816        let calculated_capacity = deser.container_size().unwrap_or(0);
817        let container = HashMap::with_capacity(calculated_capacity);
818        let allocated_capacity = container.capacity();
819        let result = deser
820            .read_map(dummy_schema(), container, |mut map, key, deser| {
821                map.insert(key, deser.read_integer(dummy_schema())?);
822                Ok(map)
823            })
824            .unwrap();
825        assert_eq!(result, HashMap::<String, i32>::new());
826        // Ensure no more memory was allocated for the container
827        assert_eq!(result.capacity(), allocated_capacity);
828
829        let json = br#"{"name": "Alice", "city": "Seattle"}"#;
830        let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
831        let calculated_capacity = deser.container_size().unwrap_or(0);
832        let container = HashMap::with_capacity(calculated_capacity);
833        let allocated_capacity = container.capacity();
834        let result = deser
835            .read_map(dummy_schema(), container, |mut map, key, deser| {
836                map.insert(key, deser.read_string(dummy_schema())?);
837                Ok(map)
838            })
839            .unwrap();
840        assert_eq!(result.len(), 2);
841        assert_eq!(result.get("name"), Some(&"Alice".to_string()));
842        assert_eq!(result.get("city"), Some(&"Seattle".to_string()));
843        // Ensure no more memory was allocated for the container
844        assert_eq!(result.capacity(), allocated_capacity);
845    }
846
847    #[test]
848    fn test_nested_complex_deserialization() {
849        use aws_smithy_schema::{prelude, Schema, ShapeId, ShapeType, TraitMap};
850        use std::collections::HashMap;
851
852        #[derive(Debug, Default, PartialEq)]
853        struct Address {
854            street: String,
855            city: String,
856            zip: i32,
857        }
858
859        #[derive(Debug, Default, PartialEq)]
860        struct Company {
861            name: String,
862            employees: Vec<String>,
863            metadata: HashMap<String, i32>,
864            active: bool,
865        }
866
867        #[derive(Debug, Default, PartialEq)]
868        struct User {
869            id: i64,
870            name: String,
871            scores: Vec<f64>,
872            address: Address,
873            companies: Vec<Company>,
874            tags: HashMap<String, String>,
875        }
876
877        struct MemberSchema {
878            name: &'static str,
879            target: &'static dyn Schema,
880        }
881
882        impl Schema for MemberSchema {
883            fn shape_id(&self) -> &ShapeId {
884                self.target.shape_id()
885            }
886            fn shape_type(&self) -> ShapeType {
887                self.target.shape_type()
888            }
889            fn traits(&self) -> &TraitMap {
890                self.target.traits()
891            }
892            fn member_name(&self) -> Option<&str> {
893                Some(self.name)
894            }
895        }
896
897        static ADDR_STREET: MemberSchema = MemberSchema {
898            name: "street",
899            target: &prelude::STRING,
900        };
901        static ADDR_CITY: MemberSchema = MemberSchema {
902            name: "city",
903            target: &prelude::STRING,
904        };
905        static ADDR_ZIP: MemberSchema = MemberSchema {
906            name: "zip",
907            target: &prelude::INTEGER,
908        };
909
910        struct AddressSchema;
911        impl Schema for AddressSchema {
912            fn shape_id(&self) -> &ShapeId {
913                static ID: std::sync::LazyLock<ShapeId> = std::sync::LazyLock::new(|| {
914                    ShapeId::from_static("test#Address", "test", "Address")
915                });
916                &ID
917            }
918            fn shape_type(&self) -> ShapeType {
919                ShapeType::Structure
920            }
921            fn traits(&self) -> &TraitMap {
922                static MAP: std::sync::LazyLock<TraitMap> = std::sync::LazyLock::new(TraitMap::new);
923                &MAP
924            }
925            fn member_schema(&self, name: &str) -> Option<&dyn Schema> {
926                match name {
927                    "street" => Some(&ADDR_STREET),
928                    "city" => Some(&ADDR_CITY),
929                    "zip" => Some(&ADDR_ZIP),
930                    _ => None,
931                }
932            }
933            fn member_schema_by_index(&self, index: usize) -> Option<(&str, &dyn Schema)> {
934                match index {
935                    0 => Some(("street", &ADDR_STREET)),
936                    1 => Some(("city", &ADDR_CITY)),
937                    2 => Some(("zip", &ADDR_ZIP)),
938                    _ => None,
939                }
940            }
941        }
942
943        static COMP_NAME: MemberSchema = MemberSchema {
944            name: "name",
945            target: &prelude::STRING,
946        };
947        static COMP_ACTIVE: MemberSchema = MemberSchema {
948            name: "active",
949            target: &prelude::BOOLEAN,
950        };
951        static COMP_EMPLOYEES: MemberSchema = MemberSchema {
952            name: "employees",
953            target: &prelude::STRING,
954        };
955        static COMP_METADATA: MemberSchema = MemberSchema {
956            name: "metadata",
957            target: &prelude::STRING,
958        };
959
960        struct CompanySchema;
961        impl Schema for CompanySchema {
962            fn shape_id(&self) -> &ShapeId {
963                static ID: std::sync::LazyLock<ShapeId> = std::sync::LazyLock::new(|| {
964                    ShapeId::from_static("test#Company", "test", "Company")
965                });
966                &ID
967            }
968            fn shape_type(&self) -> ShapeType {
969                ShapeType::Structure
970            }
971            fn traits(&self) -> &TraitMap {
972                static MAP: std::sync::LazyLock<TraitMap> = std::sync::LazyLock::new(TraitMap::new);
973                &MAP
974            }
975            fn member_schema(&self, name: &str) -> Option<&dyn Schema> {
976                match name {
977                    "name" => Some(&COMP_NAME),
978                    "active" => Some(&COMP_ACTIVE),
979                    "employees" => Some(&COMP_EMPLOYEES),
980                    "metadata" => Some(&COMP_METADATA),
981                    _ => None,
982                }
983            }
984            fn member_schema_by_index(&self, index: usize) -> Option<(&str, &dyn Schema)> {
985                match index {
986                    0 => Some(("name", &COMP_NAME)),
987                    1 => Some(("active", &COMP_ACTIVE)),
988                    _ => None,
989                }
990            }
991        }
992
993        static USER_ID: MemberSchema = MemberSchema {
994            name: "id",
995            target: &prelude::LONG,
996        };
997        static USER_NAME: MemberSchema = MemberSchema {
998            name: "name",
999            target: &prelude::STRING,
1000        };
1001        static USER_SCORES: MemberSchema = MemberSchema {
1002            name: "scores",
1003            target: &prelude::STRING,
1004        };
1005        static USER_ADDRESS: MemberSchema = MemberSchema {
1006            name: "address",
1007            target: &prelude::STRING,
1008        };
1009        static USER_COMPANIES: MemberSchema = MemberSchema {
1010            name: "companies",
1011            target: &prelude::STRING,
1012        };
1013        static USER_TAGS: MemberSchema = MemberSchema {
1014            name: "tags",
1015            target: &prelude::STRING,
1016        };
1017
1018        struct UserSchema;
1019        impl Schema for UserSchema {
1020            fn shape_id(&self) -> &ShapeId {
1021                static ID: std::sync::LazyLock<ShapeId> =
1022                    std::sync::LazyLock::new(|| ShapeId::from_static("test#User", "test", "User"));
1023                &ID
1024            }
1025            fn shape_type(&self) -> ShapeType {
1026                ShapeType::Structure
1027            }
1028            fn traits(&self) -> &TraitMap {
1029                static MAP: std::sync::LazyLock<TraitMap> = std::sync::LazyLock::new(TraitMap::new);
1030                &MAP
1031            }
1032            fn member_schema(&self, name: &str) -> Option<&dyn Schema> {
1033                match name {
1034                    "id" => Some(&USER_ID),
1035                    "name" => Some(&USER_NAME),
1036                    "scores" => Some(&USER_SCORES),
1037                    "address" => Some(&USER_ADDRESS),
1038                    "companies" => Some(&USER_COMPANIES),
1039                    "tags" => Some(&USER_TAGS),
1040                    _ => None,
1041                }
1042            }
1043            fn member_schema_by_index(&self, index: usize) -> Option<(&str, &dyn Schema)> {
1044                match index {
1045                    0 => Some(("id", &USER_ID)),
1046                    1 => Some(("name", &USER_NAME)),
1047                    _ => None,
1048                }
1049            }
1050        }
1051
1052        fn consume_address(
1053            mut addr: Address,
1054            schema: &dyn Schema,
1055            deser: &mut JsonDeserializer,
1056        ) -> Result<Address, JsonDeserializerError> {
1057            match schema.member_name() {
1058                Some("street") => addr.street = deser.read_string(schema)?,
1059                Some("city") => addr.city = deser.read_string(schema)?,
1060                Some("zip") => addr.zip = deser.read_integer(schema)?,
1061                _ => {}
1062            }
1063            Ok(addr)
1064        }
1065
1066        fn consume_company(
1067            mut comp: Company,
1068            schema: &dyn Schema,
1069            deser: &mut JsonDeserializer,
1070        ) -> Result<Company, JsonDeserializerError> {
1071            match schema.member_name() {
1072                Some("name") => comp.name = deser.read_string(schema)?,
1073                Some("active") => comp.active = deser.read_boolean(schema)?,
1074                Some("employees") => {
1075                    comp.employees = deser.read_list(schema, Vec::new(), |mut v, d| {
1076                        v.push(d.read_string(dummy_schema())?);
1077                        Ok(v)
1078                    })?
1079                }
1080                Some("metadata") => {
1081                    comp.metadata = deser.read_map(schema, HashMap::new(), |mut m, k, d| {
1082                        m.insert(k, d.read_integer(dummy_schema())?);
1083                        Ok(m)
1084                    })?
1085                }
1086                _ => {}
1087            }
1088            Ok(comp)
1089        }
1090
1091        fn consume_user(
1092            mut user: User,
1093            schema: &dyn Schema,
1094            deser: &mut JsonDeserializer,
1095        ) -> Result<User, JsonDeserializerError> {
1096            match schema.member_name() {
1097                Some("id") => user.id = deser.read_long(schema)?,
1098                Some("name") => user.name = deser.read_string(schema)?,
1099                Some("scores") => {
1100                    user.scores = deser.read_list(schema, Vec::new(), |mut v, d| {
1101                        v.push(d.read_double(dummy_schema())?);
1102                        Ok(v)
1103                    })?
1104                }
1105                Some("address") => {
1106                    user.address =
1107                        deser.read_struct(&AddressSchema, Address::default(), consume_address)?
1108                }
1109                Some("companies") => {
1110                    user.companies = deser.read_list(schema, Vec::new(), |mut v, d| {
1111                        v.push(d.read_struct(
1112                            &CompanySchema,
1113                            Company::default(),
1114                            consume_company,
1115                        )?);
1116                        Ok(v)
1117                    })?
1118                }
1119                Some("tags") => {
1120                    user.tags = deser.read_map(schema, HashMap::new(), |mut m, k, d| {
1121                        m.insert(k, d.read_string(dummy_schema())?);
1122                        Ok(m)
1123                    })?
1124                }
1125                _ => {}
1126            }
1127            Ok(user)
1128        }
1129
1130        let json = br#"{
1131            "id": 12345,
1132            "name": "John Doe",
1133            "scores": [95.5, 87.3, 92.1],
1134            "address": {
1135                "street": "123 Main St",
1136                "city": "Seattle",
1137                "zip": 98101
1138            },
1139            "companies": [
1140                {
1141                    "name": "TechCorp",
1142                    "employees": ["Alice", "Bob"],
1143                    "metadata": {"founded": 2010, "size": 500},
1144                    "active": true
1145                },
1146                {
1147                    "name": "StartupInc",
1148                    "employees": ["Charlie"],
1149                    "metadata": {"founded": 2020},
1150                    "active": false
1151                }
1152            ],
1153            "tags": {"role": "admin", "level": "senior"}
1154        }"#;
1155
1156        let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
1157        let user = deser
1158            .read_struct(&UserSchema, User::default(), consume_user)
1159            .unwrap();
1160
1161        assert_eq!(user.id, 12345);
1162        assert_eq!(user.name, "John Doe");
1163        assert_eq!(user.scores, vec![95.5, 87.3, 92.1]);
1164        assert_eq!(user.address.street, "123 Main St");
1165        assert_eq!(user.address.city, "Seattle");
1166        assert_eq!(user.address.zip, 98101);
1167        assert_eq!(user.companies.len(), 2);
1168        assert_eq!(user.companies[0].name, "TechCorp");
1169        assert_eq!(user.companies[0].employees, vec!["Alice", "Bob"]);
1170        assert_eq!(user.companies[0].metadata.get("founded"), Some(&2010));
1171        assert_eq!(user.companies[0].metadata.get("size"), Some(&500));
1172        assert_eq!(user.companies[0].active, true);
1173        assert_eq!(user.companies[1].name, "StartupInc");
1174        assert_eq!(user.companies[1].employees, vec!["Charlie"]);
1175        assert_eq!(user.companies[1].metadata.get("founded"), Some(&2020));
1176        assert_eq!(user.companies[1].active, false);
1177        assert_eq!(user.tags.get("role"), Some(&"admin".to_string()));
1178        assert_eq!(user.tags.get("level"), Some(&"senior".to_string()));
1179    }
1180}