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