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::SerdeError;
9use aws_smithy_schema::serde::ShapeDeserializer;
10use aws_smithy_schema::Schema;
11use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime, Document};
12
13use crate::codec::JsonCodecSettings;
14use crate::deserialize::{json_token_iter, Token};
15
16use std::sync::Arc;
17
18/// JSON deserializer that implements the ShapeDeserializer trait.
19pub struct JsonDeserializer<'a> {
20    input: &'a [u8],
21    position: usize,
22    settings: Arc<JsonCodecSettings>,
23}
24
25impl<'a> JsonDeserializer<'a> {
26    /// Creates a new JSON deserializer with the given settings.
27    pub(crate) fn new(input: &'a [u8], settings: Arc<JsonCodecSettings>) -> Self {
28        Self {
29            input,
30            position: 0,
31            settings,
32        }
33    }
34
35    /// Resolves a JSON field name to a member schema.
36    fn resolve_member<'s>(&self, schema: &'s Schema, field_name: &str) -> Option<&'s Schema> {
37        self.settings.field_to_member(schema, field_name)
38    }
39
40    fn remaining(&self) -> &[u8] {
41        &self.input[self.position..]
42    }
43
44    fn advance_by(&mut self, n: usize) {
45        self.position += n;
46    }
47
48    /// Parse a JSON quoted string key directly from bytes, advancing past it.
49    /// Assumes the current position is at the opening `"`.
50    /// Returns a borrowed `&str` when no escape sequences are present (common case),
51    /// avoiding a heap allocation per JSON key.
52    fn parse_key(&mut self) -> Result<std::borrow::Cow<'a, str>, SerdeError> {
53        let start = self.position + 1; // skip opening quote
54        self.position += 1;
55        let input = self.input;
56        let remaining = &input[start..];
57        let mut i = 0;
58        let mut has_escapes = false;
59        while i < remaining.len() {
60            match remaining[i] {
61                b'"' => break,
62                b'\\' => {
63                    has_escapes = true;
64                    i += 2;
65                }
66                _ => i += 1,
67            }
68        }
69        self.position = start + i + 1; // advance past key bytes + closing quote
70        let key_bytes = &input[start..start + i];
71        if has_escapes {
72            let raw = std::str::from_utf8(key_bytes).map_err(|e| SerdeError::InvalidInput {
73                message: e.to_string(),
74            })?;
75            Ok(std::borrow::Cow::Owned(
76                crate::escape::unescape_string(raw)
77                    .map_err(|e| SerdeError::InvalidInput {
78                        message: e.to_string(),
79                    })?
80                    .into_owned(),
81            ))
82        } else {
83            Ok(std::borrow::Cow::Borrowed(
84                std::str::from_utf8(key_bytes).map_err(|e| SerdeError::InvalidInput {
85                    message: e.to_string(),
86                })?,
87            ))
88        }
89    }
90}
91
92impl<'a> ShapeDeserializer for JsonDeserializer<'a> {
93    fn read_struct(
94        &mut self,
95        schema: &Schema,
96        consumer: &mut dyn FnMut(&Schema, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
97    ) -> Result<(), SerdeError> {
98        // Expect opening brace
99        self.skip_whitespace();
100        if self.remaining().is_empty() {
101            // Treat empty input as an empty object (e.g., empty HTTP response body)
102            return Ok(());
103        }
104        if self.remaining().first() != Some(&b'{') {
105            return Err(SerdeError::TypeMismatch {
106                message: "expected object".into(),
107            });
108        }
109        self.advance_by(1);
110
111        loop {
112            self.skip_whitespace();
113
114            // Check for end of object
115            if self.remaining().first() == Some(&b'}') {
116                self.advance_by(1);
117                break;
118            }
119
120            // Expect a key (quoted string)
121            if self.remaining().first() != Some(&b'"') {
122                return Err(SerdeError::InvalidInput {
123                    message: "expected object key".into(),
124                });
125            }
126
127            // Parse the key directly from bytes
128            let key_str = self.parse_key()?;
129
130            // Skip whitespace and expect colon
131            self.skip_whitespace();
132            if self.remaining().first() != Some(&b':') {
133                return Err(SerdeError::InvalidInput {
134                    message: "expected colon after key".into(),
135                });
136            }
137            self.advance_by(1);
138            self.skip_whitespace();
139
140            // Process the value — skip nulls (they represent absent optional members)
141            let rem = self.remaining();
142            if rem.starts_with(b"null") && !rem.get(4).is_some_and(|b| b.is_ascii_alphanumeric()) {
143                self.advance_by(4);
144            } else if let Some(member_schema) = self.resolve_member(schema, &key_str) {
145                consumer(member_schema, self)?;
146            } else {
147                self.skip_value()?;
148            }
149        }
150
151        Ok(())
152    }
153
154    fn read_list(
155        &mut self,
156        _schema: &Schema,
157        consumer: &mut dyn FnMut(&mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
158    ) -> Result<(), SerdeError> {
159        self.skip_whitespace();
160        if self.remaining().first() != Some(&b'[') {
161            return Err(SerdeError::TypeMismatch {
162                message: "expected array".into(),
163            });
164        }
165        self.advance_by(1);
166
167        loop {
168            self.skip_whitespace();
169            if self.remaining().first() == Some(&b']') {
170                self.advance_by(1);
171                break;
172            }
173            consumer(self)?;
174        }
175
176        Ok(())
177    }
178
179    fn read_map(
180        &mut self,
181        _schema: &Schema,
182        consumer: &mut dyn FnMut(String, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
183    ) -> Result<(), SerdeError> {
184        self.skip_whitespace();
185        if self.remaining().first() != Some(&b'{') {
186            return Err(SerdeError::TypeMismatch {
187                message: "expected object".into(),
188            });
189        }
190        self.advance_by(1);
191
192        loop {
193            self.skip_whitespace();
194            if self.remaining().first() == Some(&b'}') {
195                self.advance_by(1);
196                break;
197            }
198
199            if self.remaining().first() != Some(&b'"') {
200                return Err(SerdeError::InvalidInput {
201                    message: "expected key".into(),
202                });
203            }
204
205            let key = self.parse_key()?;
206
207            self.skip_whitespace();
208            if self.remaining().first() != Some(&b':') {
209                return Err(SerdeError::InvalidInput {
210                    message: "expected colon".into(),
211                });
212            }
213            self.advance_by(1);
214            self.skip_whitespace();
215
216            consumer(key.into_owned(), self)?;
217        }
218
219        Ok(())
220    }
221
222    fn read_boolean(&mut self, _schema: &Schema) -> Result<bool, SerdeError> {
223        self.skip_whitespace();
224        let rem = self.remaining();
225        if rem.starts_with(b"true") {
226            self.advance_by(4);
227            Ok(true)
228        } else if rem.starts_with(b"false") {
229            self.advance_by(5);
230            Ok(false)
231        } else {
232            Err(SerdeError::TypeMismatch {
233                message: "expected boolean".into(),
234            })
235        }
236    }
237
238    fn read_byte(&mut self, _schema: &Schema) -> Result<i8, SerdeError> {
239        self.read_integer_value().and_then(|n| {
240            i8::try_from(n).map_err(|_| SerdeError::InvalidInput {
241                message: "value out of range for byte".into(),
242            })
243        })
244    }
245
246    fn read_short(&mut self, _schema: &Schema) -> Result<i16, SerdeError> {
247        self.read_integer_value().and_then(|n| {
248            i16::try_from(n).map_err(|_| SerdeError::InvalidInput {
249                message: "value out of range for short".into(),
250            })
251        })
252    }
253
254    fn read_integer(&mut self, _schema: &Schema) -> Result<i32, SerdeError> {
255        self.read_integer_value().and_then(|n| {
256            i32::try_from(n).map_err(|_| SerdeError::InvalidInput {
257                message: "value out of range for integer".into(),
258            })
259        })
260    }
261
262    fn read_long(&mut self, _schema: &Schema) -> Result<i64, SerdeError> {
263        self.read_integer_value()
264    }
265
266    fn read_float(&mut self, _schema: &Schema) -> Result<f32, SerdeError> {
267        self.read_float_value().map(|f| f as f32)
268    }
269
270    fn read_double(&mut self, _schema: &Schema) -> Result<f64, SerdeError> {
271        self.read_float_value()
272    }
273
274    fn read_big_integer(&mut self, _schema: &Schema) -> Result<BigInteger, SerdeError> {
275        use std::str::FromStr;
276        self.skip_whitespace();
277        match self.remaining().first() {
278            Some(b'-') | Some(b'0'..=b'9') => {
279                let start = self.position;
280                self.consume_number();
281                let num_str =
282                    std::str::from_utf8(&self.input[start..self.position]).map_err(|e| {
283                        SerdeError::InvalidInput {
284                            message: e.to_string(),
285                        }
286                    })?;
287                BigInteger::from_str(num_str).map_err(|e| SerdeError::InvalidInput {
288                    message: e.to_string(),
289                })
290            }
291            _ => Err(SerdeError::TypeMismatch {
292                message: "expected number".into(),
293            }),
294        }
295    }
296
297    fn read_big_decimal(&mut self, _schema: &Schema) -> Result<BigDecimal, SerdeError> {
298        use std::str::FromStr;
299        self.skip_whitespace();
300        match self.remaining().first() {
301            Some(b'-') | Some(b'0'..=b'9') => {
302                let start = self.position;
303                self.consume_number();
304                let num_str =
305                    std::str::from_utf8(&self.input[start..self.position]).map_err(|e| {
306                        SerdeError::InvalidInput {
307                            message: e.to_string(),
308                        }
309                    })?;
310                BigDecimal::from_str(num_str).map_err(|e| SerdeError::InvalidInput {
311                    message: e.to_string(),
312                })
313            }
314            _ => Err(SerdeError::TypeMismatch {
315                message: "expected number".into(),
316            }),
317        }
318    }
319
320    fn read_string(&mut self, _schema: &Schema) -> Result<String, SerdeError> {
321        self.skip_whitespace();
322        let pos = self.position;
323        let input = self.input;
324        let rem = &input[pos..];
325        if rem.first() != Some(&b'"') {
326            return Err(SerdeError::TypeMismatch {
327                message: "expected string".into(),
328            });
329        }
330        // Scan for end of string, tracking whether escapes are present
331        let mut i = 1;
332        let mut has_escape = false;
333        while i < rem.len() {
334            if rem[i] == b'\\' {
335                has_escape = true;
336                i += 2;
337            } else if rem[i] == b'"' {
338                let raw = &input[pos + 1..pos + i];
339                self.position = pos + i + 1;
340                if !has_escape {
341                    return std::str::from_utf8(raw).map(|s| s.to_owned()).map_err(|e| {
342                        SerdeError::InvalidInput {
343                            message: e.to_string(),
344                        }
345                    });
346                }
347                let s = std::str::from_utf8(raw).map_err(|e| SerdeError::InvalidInput {
348                    message: e.to_string(),
349                })?;
350                return crate::deserialize::EscapedStr::new(s)
351                    .to_unescaped()
352                    .map(|s| s.into_owned())
353                    .map_err(|e| SerdeError::InvalidInput {
354                        message: e.to_string(),
355                    });
356            } else {
357                i += 1;
358            }
359        }
360        Err(SerdeError::InvalidInput {
361            message: "unterminated string".into(),
362        })
363    }
364
365    fn read_blob(&mut self, _schema: &Schema) -> Result<Blob, SerdeError> {
366        let s = self.read_string(_schema)?;
367        let decoded =
368            aws_smithy_types::base64::decode(&s).map_err(|e| SerdeError::InvalidInput {
369                message: format!("invalid base64: {}", e),
370            })?;
371        Ok(Blob::new(decoded))
372    }
373
374    fn read_string_list(&mut self, _schema: &Schema) -> Result<Vec<String>, SerdeError> {
375        self.skip_whitespace();
376        if self.remaining().first() != Some(&b'[') {
377            return Err(SerdeError::TypeMismatch {
378                message: "expected array".into(),
379            });
380        }
381        self.advance_by(1);
382        let mut out = Vec::new();
383        loop {
384            self.skip_whitespace();
385            if self.remaining().first() == Some(&b']') {
386                self.advance_by(1);
387                break;
388            }
389            out.push(self.read_string(_schema)?);
390        }
391        Ok(out)
392    }
393
394    fn read_blob_list(&mut self, _schema: &Schema) -> Result<Vec<Blob>, SerdeError> {
395        self.skip_whitespace();
396        if self.remaining().first() != Some(&b'[') {
397            return Err(SerdeError::TypeMismatch {
398                message: "expected array".into(),
399            });
400        }
401        self.advance_by(1);
402        let mut out = Vec::new();
403        loop {
404            self.skip_whitespace();
405            if self.remaining().first() == Some(&b']') {
406                self.advance_by(1);
407                break;
408            }
409            out.push(self.read_blob(_schema)?);
410        }
411        Ok(out)
412    }
413
414    fn read_integer_list(&mut self, _schema: &Schema) -> Result<Vec<i32>, SerdeError> {
415        self.skip_whitespace();
416        if self.remaining().first() != Some(&b'[') {
417            return Err(SerdeError::TypeMismatch {
418                message: "expected array".into(),
419            });
420        }
421        self.advance_by(1);
422        let mut out = Vec::new();
423        loop {
424            self.skip_whitespace();
425            if self.remaining().first() == Some(&b']') {
426                self.advance_by(1);
427                break;
428            }
429            out.push(self.read_integer(_schema)?);
430        }
431        Ok(out)
432    }
433
434    fn read_long_list(&mut self, _schema: &Schema) -> Result<Vec<i64>, SerdeError> {
435        self.skip_whitespace();
436        if self.remaining().first() != Some(&b'[') {
437            return Err(SerdeError::TypeMismatch {
438                message: "expected array".into(),
439            });
440        }
441        self.advance_by(1);
442        let mut out = Vec::new();
443        loop {
444            self.skip_whitespace();
445            if self.remaining().first() == Some(&b']') {
446                self.advance_by(1);
447                break;
448            }
449            out.push(self.read_long(_schema)?);
450        }
451        Ok(out)
452    }
453
454    fn read_string_string_map(
455        &mut self,
456        _schema: &Schema,
457    ) -> Result<std::collections::HashMap<String, String>, SerdeError> {
458        self.skip_whitespace();
459        if self.remaining().first() != Some(&b'{') {
460            return Err(SerdeError::TypeMismatch {
461                message: "expected object".into(),
462            });
463        }
464        self.advance_by(1);
465        let mut out = std::collections::HashMap::new();
466        loop {
467            self.skip_whitespace();
468            if self.remaining().first() == Some(&b'}') {
469                self.advance_by(1);
470                break;
471            }
472            if self.remaining().first() != Some(&b'"') {
473                return Err(SerdeError::InvalidInput {
474                    message: "expected key".into(),
475                });
476            }
477            let key = self.parse_key()?;
478            self.skip_whitespace();
479            if self.remaining().first() != Some(&b':') {
480                return Err(SerdeError::InvalidInput {
481                    message: "expected colon".into(),
482                });
483            }
484            self.advance_by(1);
485            self.skip_whitespace();
486            let val = self.read_string(_schema)?;
487            out.insert(key.into_owned(), val);
488        }
489        Ok(out)
490    }
491
492    fn read_timestamp(&mut self, schema: &Schema) -> Result<DateTime, SerdeError> {
493        self.skip_whitespace();
494        let rem = self.remaining();
495        match rem.first() {
496            Some(b'"') => {
497                let s = self.read_string(schema)?;
498                // Determine parse format from @timestampFormat trait or default
499                let format = if let Some(ts_trait) = schema.timestamp_format() {
500                    match ts_trait.format() {
501                        aws_smithy_schema::traits::TimestampFormat::HttpDate => {
502                            aws_smithy_types::date_time::Format::HttpDate
503                        }
504                        aws_smithy_schema::traits::TimestampFormat::EpochSeconds => {
505                            aws_smithy_types::date_time::Format::EpochSeconds
506                        }
507                        aws_smithy_schema::traits::TimestampFormat::DateTime => {
508                            aws_smithy_types::date_time::Format::DateTimeWithOffset
509                        }
510                    }
511                } else {
512                    // Default: try date-time with offsets allowed
513                    aws_smithy_types::date_time::Format::DateTimeWithOffset
514                };
515                DateTime::from_str(&s, format)
516                    .map_err(|e| SerdeError::custom(format!("invalid timestamp string: {e}")))
517            }
518            Some(b'-') | Some(b'0'..=b'9') => {
519                // Numeric timestamp — epoch seconds
520                let start = self.position;
521                self.consume_number();
522                let num_str =
523                    std::str::from_utf8(&self.input[start..self.position]).map_err(|e| {
524                        SerdeError::InvalidInput {
525                            message: e.to_string(),
526                        }
527                    })?;
528                if num_str.contains('.') || num_str.contains('e') || num_str.contains('E') {
529                    let f: f64 = num_str.parse().map_err(|e: std::num::ParseFloatError| {
530                        SerdeError::InvalidInput {
531                            message: e.to_string(),
532                        }
533                    })?;
534                    Ok(DateTime::from_secs_f64(f))
535                } else if num_str.starts_with('-') {
536                    let n: i64 = num_str.parse().map_err(|e: std::num::ParseIntError| {
537                        SerdeError::InvalidInput {
538                            message: e.to_string(),
539                        }
540                    })?;
541                    Ok(DateTime::from_secs(n))
542                } else {
543                    let n: u64 = num_str.parse().map_err(|e: std::num::ParseIntError| {
544                        SerdeError::InvalidInput {
545                            message: e.to_string(),
546                        }
547                    })?;
548                    Ok(DateTime::from_secs(n as i64))
549                }
550            }
551            _ => Err(SerdeError::TypeMismatch {
552                message: "expected timestamp".into(),
553            }),
554        }
555    }
556
557    fn read_document(&mut self, _schema: &Schema) -> Result<Document, SerdeError> {
558        self.skip_whitespace();
559        match self.remaining().first() {
560            Some(b'"') => Ok(Document::String(self.read_string(_schema)?)),
561            Some(b't') | Some(b'f') => Ok(Document::Bool(self.read_boolean(_schema)?)),
562            Some(b'n') => {
563                if self.remaining().starts_with(b"null") {
564                    self.advance_by(4);
565                    Ok(Document::Null)
566                } else {
567                    Err(SerdeError::InvalidInput {
568                        message: "unexpected token in document".into(),
569                    })
570                }
571            }
572            Some(b'{') => {
573                self.advance_by(1);
574                let mut map = std::collections::HashMap::new();
575                loop {
576                    self.skip_whitespace();
577                    if self.remaining().first() == Some(&b'}') {
578                        self.advance_by(1);
579                        break;
580                    }
581                    if self.remaining().first() != Some(&b'"') {
582                        return Err(SerdeError::InvalidInput {
583                            message: "expected object key in document".into(),
584                        });
585                    }
586                    let key = self.parse_key()?.into_owned();
587                    self.skip_whitespace();
588                    if self.remaining().first() != Some(&b':') {
589                        return Err(SerdeError::InvalidInput {
590                            message: "expected colon in document object".into(),
591                        });
592                    }
593                    self.advance_by(1);
594                    let value = self.read_document(_schema)?;
595                    map.insert(key, value);
596                }
597                Ok(Document::Object(map))
598            }
599            Some(b'[') => {
600                self.advance_by(1);
601                let mut arr = Vec::new();
602                loop {
603                    self.skip_whitespace();
604                    if self.remaining().first() == Some(&b']') {
605                        self.advance_by(1);
606                        break;
607                    }
608                    arr.push(self.read_document(_schema)?);
609                }
610                Ok(Document::Array(arr))
611            }
612            Some(c) if *c == b'-' || c.is_ascii_digit() => {
613                // Parse number — determine if integer or float
614                let rem = self.remaining();
615                let mut len = 0;
616                let mut is_float = false;
617                let mut is_negative = false;
618                for (i, &b) in rem.iter().enumerate() {
619                    if b == b'-' && i == 0 {
620                        is_negative = true;
621                        len += 1;
622                    } else if b.is_ascii_digit() || b == b'+' {
623                        len += 1;
624                    } else if b == b'.' || b == b'e' || b == b'E' {
625                        is_float = true;
626                        len += 1;
627                    } else {
628                        break;
629                    }
630                }
631                let pos = self.position;
632                self.advance_by(len);
633                let s = std::str::from_utf8(&self.input[pos..pos + len]).map_err(|e| {
634                    SerdeError::InvalidInput {
635                        message: e.to_string(),
636                    }
637                })?;
638                if is_float {
639                    let f = s.parse::<f64>().map_err(|e| SerdeError::InvalidInput {
640                        message: e.to_string(),
641                    })?;
642                    Ok(Document::Number(aws_smithy_types::Number::Float(f)))
643                } else if is_negative {
644                    let n = s.parse::<i64>().map_err(|e| SerdeError::InvalidInput {
645                        message: e.to_string(),
646                    })?;
647                    Ok(Document::Number(aws_smithy_types::Number::NegInt(n)))
648                } else {
649                    let n = s.parse::<u64>().map_err(|e| SerdeError::InvalidInput {
650                        message: e.to_string(),
651                    })?;
652                    Ok(Document::Number(aws_smithy_types::Number::PosInt(n)))
653                }
654            }
655            _ => Err(SerdeError::InvalidInput {
656                message: "unexpected token in document".into(),
657            }),
658        }
659    }
660
661    fn is_null(&self) -> bool {
662        let remaining = self.remaining();
663        remaining.len() >= 4
664            && &remaining[..4] == b"null"
665            && !remaining.get(4).is_some_and(|b| b.is_ascii_alphanumeric())
666    }
667
668    fn read_null(&mut self) -> Result<(), SerdeError> {
669        self.skip_whitespace();
670        if self.is_null() {
671            self.advance_by(4);
672        }
673        Ok(())
674    }
675
676    fn container_size(&self) -> Option<usize> {
677        let mut iter = json_token_iter(self.remaining());
678        match iter.next()? {
679            Ok(Token::StartArray { .. }) => {
680                let mut count = 0;
681                let mut depth = 1;
682                for token in iter {
683                    match token {
684                        Ok(Token::StartArray { .. }) | Ok(Token::StartObject { .. }) => {
685                            if depth == 1 {
686                                count += 1;
687                            }
688                            depth += 1;
689                        }
690                        Ok(Token::EndArray { .. }) | Ok(Token::EndObject { .. }) => {
691                            depth -= 1;
692                            if depth == 0 {
693                                return Some(count);
694                            }
695                        }
696                        Ok(Token::ValueBool { .. })
697                        | Ok(Token::ValueNull { .. })
698                        | Ok(Token::ValueString { .. })
699                        | Ok(Token::ValueNumber { .. })
700                            if depth == 1 =>
701                        {
702                            count += 1
703                        }
704                        _ => {}
705                    }
706                }
707                None
708            }
709            Ok(Token::StartObject { .. }) => {
710                let mut count = 0;
711                let mut depth = 1;
712                for token in iter {
713                    match token {
714                        Ok(Token::StartArray { .. }) | Ok(Token::StartObject { .. }) => depth += 1,
715                        Ok(Token::EndArray { .. }) | Ok(Token::EndObject { .. }) => {
716                            depth -= 1;
717                            if depth == 0 {
718                                return Some(count);
719                            }
720                        }
721                        Ok(Token::ObjectKey { .. }) if depth == 1 => count += 1,
722                        _ => {}
723                    }
724                }
725                None
726            }
727            _ => None,
728        }
729    }
730}
731
732impl<'a> JsonDeserializer<'a> {
733    fn skip_whitespace(&mut self) {
734        while self.position < self.input.len() {
735            match self.input[self.position] {
736                b' ' | b'\t' | b'\n' | b'\r' | b',' => self.position += 1,
737                _ => break,
738            }
739        }
740    }
741
742    fn consume_number(&mut self) {
743        let mut len = 0;
744        for &b in self.remaining() {
745            if b.is_ascii_digit() || b == b'-' || b == b'.' || b == b'e' || b == b'E' || b == b'+' {
746                len += 1;
747            } else {
748                break;
749            }
750        }
751        self.advance_by(len);
752    }
753
754    fn skip_value(&mut self) -> Result<(), SerdeError> {
755        self.skip_whitespace();
756        let mut depth: usize = 0;
757        loop {
758            self.skip_whitespace();
759            match self.remaining().first().copied() {
760                Some(b'{') | Some(b'[') => {
761                    self.advance_by(1);
762                    depth += 1;
763                }
764                Some(b'}') | Some(b']') => {
765                    if depth == 0 {
766                        return Err(SerdeError::InvalidInput {
767                            message: "unexpected end token".into(),
768                        });
769                    }
770                    self.advance_by(1);
771                    depth -= 1;
772                    if depth == 0 {
773                        return Ok(());
774                    }
775                }
776                Some(b'"') => {
777                    // Skip quoted string (handles escapes)
778                    let mut i = 1;
779                    let rem = self.remaining();
780                    while i < rem.len() {
781                        if rem[i] == b'\\' {
782                            i += 2; // skip escape sequence
783                        } else if rem[i] == b'"' {
784                            i += 1;
785                            break;
786                        } else {
787                            i += 1;
788                        }
789                    }
790                    self.advance_by(i);
791                    // After a string inside an object, skip optional ':'
792                    if depth > 0 {
793                        self.skip_whitespace();
794                        if self.remaining().first() == Some(&b':') {
795                            self.advance_by(1);
796                            continue; // read the value after the colon
797                        }
798                    }
799                    if depth == 0 {
800                        return Ok(());
801                    }
802                }
803                Some(b't') => {
804                    self.advance_by(4); // true
805                    if depth == 0 {
806                        return Ok(());
807                    }
808                }
809                Some(b'f') => {
810                    self.advance_by(5); // false
811                    if depth == 0 {
812                        return Ok(());
813                    }
814                }
815                Some(b'n') => {
816                    self.advance_by(4); // null
817                    if depth == 0 {
818                        return Ok(());
819                    }
820                }
821                Some(c) if c == b'-' || c.is_ascii_digit() => {
822                    self.consume_number();
823                    if depth == 0 {
824                        return Ok(());
825                    }
826                }
827                Some(_) => {
828                    return Err(SerdeError::InvalidInput {
829                        message: "unexpected token in skip_value".into(),
830                    })
831                }
832                None => {
833                    return Err(SerdeError::InvalidInput {
834                        message: "unexpected end of input".into(),
835                    })
836                }
837            }
838        }
839    }
840
841    fn read_integer_value(&mut self) -> Result<i64, SerdeError> {
842        self.skip_whitespace();
843        let rem = self.remaining();
844        let mut len = 0;
845        for &b in rem {
846            if b.is_ascii_digit() || b == b'-' || b == b'+' {
847                len += 1;
848            } else {
849                break;
850            }
851        }
852        if len == 0 {
853            return Err(SerdeError::TypeMismatch {
854                message: "expected integer".into(),
855            });
856        }
857        let s = std::str::from_utf8(&rem[..len]).map_err(|e| SerdeError::InvalidInput {
858            message: e.to_string(),
859        })?;
860        let n = s.parse::<i64>().map_err(|e| SerdeError::InvalidInput {
861            message: e.to_string(),
862        })?;
863        self.advance_by(len);
864        Ok(n)
865    }
866
867    fn read_float_value(&mut self) -> Result<f64, SerdeError> {
868        self.skip_whitespace();
869        let rem = self.remaining();
870        // Handle string-encoded special float values: "NaN", "Infinity", "-Infinity"
871        if rem.first() == Some(&b'"') {
872            let s = self.read_string(&aws_smithy_schema::prelude::STRING)?;
873            return match s.as_str() {
874                "NaN" => Ok(f64::NAN),
875                "Infinity" => Ok(f64::INFINITY),
876                "-Infinity" => Ok(f64::NEG_INFINITY),
877                _ => s.parse::<f64>().map_err(|e| SerdeError::InvalidInput {
878                    message: e.to_string(),
879                }),
880            };
881        }
882        let mut len = 0;
883        for &b in rem {
884            if b.is_ascii_digit() || b == b'-' || b == b'+' || b == b'.' || b == b'e' || b == b'E' {
885                len += 1;
886            } else {
887                break;
888            }
889        }
890        if len == 0 {
891            return Err(SerdeError::TypeMismatch {
892                message: "expected number".into(),
893            });
894        }
895        let s = std::str::from_utf8(&rem[..len]).map_err(|e| SerdeError::InvalidInput {
896            message: e.to_string(),
897        })?;
898        let n = s.parse::<f64>().map_err(|e| SerdeError::InvalidInput {
899            message: e.to_string(),
900        })?;
901        self.advance_by(len);
902        Ok(n)
903    }
904}
905
906#[cfg(test)]
907mod tests {
908    use super::*;
909
910    fn dummy_schema() -> &'static aws_smithy_schema::Schema {
911        &aws_smithy_schema::prelude::STRING
912    }
913
914    #[test]
915    fn test_read_boolean() {
916        let mut deser = JsonDeserializer::new(b"true", Arc::new(JsonCodecSettings::default()));
917        assert!(deser.read_boolean(dummy_schema()).unwrap());
918
919        let mut deser = JsonDeserializer::new(b"false", Arc::new(JsonCodecSettings::default()));
920        assert!(!(deser.read_boolean(dummy_schema()).unwrap()));
921    }
922
923    #[test]
924    fn test_read_integer() {
925        let mut deser = JsonDeserializer::new(b"42", Arc::new(JsonCodecSettings::default()));
926        assert_eq!(deser.read_integer(dummy_schema()).unwrap(), 42);
927
928        let mut deser = JsonDeserializer::new(b"-123", Arc::new(JsonCodecSettings::default()));
929        assert_eq!(deser.read_integer(dummy_schema()).unwrap(), -123);
930    }
931
932    #[test]
933    fn test_read_long() {
934        let mut deser = JsonDeserializer::new(
935            b"9223372036854775807",
936            Arc::new(JsonCodecSettings::default()),
937        );
938        assert_eq!(deser.read_long(dummy_schema()).unwrap(), i64::MAX);
939    }
940
941    #[test]
942    fn test_read_float() {
943        let mut deser = JsonDeserializer::new(b"3.15", Arc::new(JsonCodecSettings::default()));
944        assert!((deser.read_float(dummy_schema()).unwrap() - 3.15).abs() < 0.01);
945    }
946
947    #[test]
948    fn test_read_double() {
949        let mut deser = JsonDeserializer::new(b"2.72", Arc::new(JsonCodecSettings::default()));
950        assert!((deser.read_double(dummy_schema()).unwrap() - 2.72).abs() < 0.001);
951    }
952
953    #[test]
954    fn test_read_string() {
955        let mut deser =
956            JsonDeserializer::new(br#""hello world""#, Arc::new(JsonCodecSettings::default()));
957        assert_eq!(deser.read_string(dummy_schema()).unwrap(), "hello world");
958
959        let mut deser =
960            JsonDeserializer::new(br#""hello\nworld""#, Arc::new(JsonCodecSettings::default()));
961        assert_eq!(deser.read_string(dummy_schema()).unwrap(), "hello\nworld");
962    }
963
964    #[test]
965    fn test_is_null() {
966        let deser = JsonDeserializer::new(b"null", Arc::new(JsonCodecSettings::default()));
967        assert!(deser.is_null());
968
969        let deser = JsonDeserializer::new(b"42", Arc::new(JsonCodecSettings::default()));
970        assert!(!deser.is_null());
971    }
972
973    #[test]
974    fn test_read_byte_range() {
975        let mut deser = JsonDeserializer::new(b"127", Arc::new(JsonCodecSettings::default()));
976        assert_eq!(deser.read_byte(dummy_schema()).unwrap(), 127);
977
978        let mut deser = JsonDeserializer::new(b"128", Arc::new(JsonCodecSettings::default()));
979        assert!(deser.read_byte(dummy_schema()).is_err());
980    }
981
982    #[test]
983    fn test_read_struct() {
984        use aws_smithy_schema::Schema;
985
986        #[derive(Debug, Default, PartialEq)]
987        struct Person {
988            first_name: String,
989            last_name: String,
990            age: i32,
991        }
992
993        static FIRST_NAME: Schema = Schema::new_member(
994            aws_smithy_schema::shape_id!("test", "Person"),
995            aws_smithy_schema::ShapeType::String,
996            "firstName",
997            0,
998        );
999        static LAST_NAME: Schema = Schema::new_member(
1000            aws_smithy_schema::shape_id!("test", "Person"),
1001            aws_smithy_schema::ShapeType::String,
1002            "lastName",
1003            1,
1004        );
1005        static AGE: Schema = Schema::new_member(
1006            aws_smithy_schema::shape_id!("test", "Person"),
1007            aws_smithy_schema::ShapeType::Integer,
1008            "age",
1009            2,
1010        );
1011        static PERSON_SCHEMA: Schema = Schema::new_struct(
1012            aws_smithy_schema::shape_id!("test", "Person"),
1013            aws_smithy_schema::ShapeType::Structure,
1014            &[&FIRST_NAME, &LAST_NAME, &AGE],
1015        );
1016
1017        fn consume_person(
1018            person: &mut Person,
1019            schema: &Schema,
1020            deser: &mut dyn ShapeDeserializer,
1021        ) -> Result<(), SerdeError> {
1022            match schema.member_name() {
1023                Some("firstName") => person.first_name = deser.read_string(schema)?,
1024                Some("lastName") => person.last_name = deser.read_string(schema)?,
1025                Some("age") => person.age = deser.read_integer(schema)?,
1026                _ => {}
1027            }
1028            Ok(())
1029        }
1030
1031        let json = br#"{"lastName":"Smithy","firstName":"Alice","age":30}"#;
1032        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1033        let mut person = Person::default();
1034        deser
1035            .read_struct(&PERSON_SCHEMA, &mut |member, d| {
1036                consume_person(&mut person, member, d)
1037            })
1038            .unwrap();
1039        assert_eq!(
1040            person,
1041            Person {
1042                first_name: "Alice".to_string(),
1043                last_name: "Smithy".to_string(),
1044                age: 30
1045            }
1046        );
1047
1048        let json =
1049            br#"{"firstName":          "Alice","age":12345678,     "lastName":"\"Smithy\""}"#;
1050        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1051        let mut person = Person::default();
1052        deser
1053            .read_struct(&PERSON_SCHEMA, &mut |member, d| {
1054                consume_person(&mut person, member, d)
1055            })
1056            .unwrap();
1057        assert_eq!(
1058            person,
1059            Person {
1060                first_name: "Alice".to_string(),
1061                last_name: "\"Smithy\"".to_string(),
1062                age: 12345678
1063            }
1064        );
1065    }
1066
1067    #[test]
1068    fn test_read_list() {
1069        let json = b"[1, 2, 3, 4, 5]";
1070        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1071        let capacity = deser.container_size().unwrap_or(0);
1072        let mut result = Vec::with_capacity(capacity);
1073        let allocated_capacity = result.capacity();
1074        deser
1075            .read_list(dummy_schema(), &mut |deser| {
1076                result.push(deser.read_integer(dummy_schema())?);
1077                Ok(())
1078            })
1079            .unwrap();
1080        assert_eq!(result, vec![1, 2, 3, 4, 5]);
1081        // Ensure no more memory was allocated for the container
1082        assert_eq!(result.capacity(), allocated_capacity);
1083
1084        let json = b"[]";
1085        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1086        let capacity = deser.container_size().unwrap_or(0);
1087        let mut result = Vec::<i32>::with_capacity(capacity);
1088        let allocated_capacity = result.capacity();
1089        deser
1090            .read_list(dummy_schema(), &mut |deser| {
1091                result.push(deser.read_integer(dummy_schema())?);
1092                Ok(())
1093            })
1094            .unwrap();
1095        assert_eq!(result, Vec::<i32>::new());
1096        // Ensure no more memory was allocated for the container
1097        assert_eq!(result.capacity(), allocated_capacity);
1098
1099        let json = br#"["hello", "world"]"#;
1100        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1101        let capacity = deser.container_size().unwrap_or(0);
1102        let mut result = Vec::with_capacity(capacity);
1103        let allocated_capacity = result.capacity();
1104        deser
1105            .read_list(dummy_schema(), &mut |deser| {
1106                result.push(deser.read_string(dummy_schema())?);
1107                Ok(())
1108            })
1109            .unwrap();
1110        assert_eq!(result, vec!["hello", "world"]);
1111        // Ensure no more memory was allocated for the container
1112        assert_eq!(result.capacity(), allocated_capacity);
1113    }
1114
1115    #[test]
1116    fn test_container_size() {
1117        let deser =
1118            JsonDeserializer::new(b"[1, 2, 3, 4, 5]", Arc::new(JsonCodecSettings::default()));
1119        assert_eq!(deser.container_size(), Some(5));
1120
1121        let deser = JsonDeserializer::new(b"[]", Arc::new(JsonCodecSettings::default()));
1122        assert_eq!(deser.container_size(), Some(0));
1123
1124        let deser = JsonDeserializer::new(
1125            br#"{"a": 1, "b": 2, "c": 3}"#,
1126            Arc::new(JsonCodecSettings::default()),
1127        );
1128        assert_eq!(deser.container_size(), Some(3));
1129
1130        let deser = JsonDeserializer::new(b"{}", Arc::new(JsonCodecSettings::default()));
1131        assert_eq!(deser.container_size(), Some(0));
1132
1133        let deser = JsonDeserializer::new(
1134            b"[[1, 2], [3, 4], [5, 6]]",
1135            Arc::new(JsonCodecSettings::default()),
1136        );
1137        assert_eq!(deser.container_size(), Some(3));
1138
1139        let deser = JsonDeserializer::new(b"42", Arc::new(JsonCodecSettings::default()));
1140        assert_eq!(deser.container_size(), None);
1141    }
1142
1143    #[test]
1144    fn test_read_map() {
1145        use std::collections::HashMap;
1146
1147        let json = br#"{"a": 1, "b": 2, "c": 3}"#;
1148        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1149        let calculated_capacity = deser.container_size().unwrap_or(0);
1150        let mut result = HashMap::with_capacity(calculated_capacity);
1151        let allocated_capacity = result.capacity();
1152        deser
1153            .read_map(dummy_schema(), &mut |key, deser| {
1154                result.insert(key, deser.read_integer(dummy_schema())?);
1155                Ok(())
1156            })
1157            .unwrap();
1158        assert_eq!(result.len(), 3);
1159        assert_eq!(result.get("a"), Some(&1));
1160        assert_eq!(result.get("b"), Some(&2));
1161        assert_eq!(result.get("c"), Some(&3));
1162        // Ensure no more memory was allocated for the container
1163        assert_eq!(result.capacity(), allocated_capacity);
1164
1165        let json = b"{}";
1166        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1167        let calculated_capacity = deser.container_size().unwrap_or(0);
1168        let mut result = HashMap::<String, i32>::with_capacity(calculated_capacity);
1169        let allocated_capacity = result.capacity();
1170        deser
1171            .read_map(dummy_schema(), &mut |key, deser| {
1172                result.insert(key, deser.read_integer(dummy_schema())?);
1173                Ok(())
1174            })
1175            .unwrap();
1176        assert_eq!(result, HashMap::<String, i32>::new());
1177        // Ensure no more memory was allocated for the container
1178        assert_eq!(result.capacity(), allocated_capacity);
1179
1180        let json = br#"{"name": "Alice", "city": "Seattle"}"#;
1181        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1182        let calculated_capacity = deser.container_size().unwrap_or(0);
1183        let mut result = HashMap::with_capacity(calculated_capacity);
1184        let allocated_capacity = result.capacity();
1185        deser
1186            .read_map(dummy_schema(), &mut |key, deser| {
1187                result.insert(key, deser.read_string(dummy_schema())?);
1188                Ok(())
1189            })
1190            .unwrap();
1191        assert_eq!(result.len(), 2);
1192        assert_eq!(result.get("name"), Some(&"Alice".to_string()));
1193        assert_eq!(result.get("city"), Some(&"Seattle".to_string()));
1194        // Ensure no more memory was allocated for the container
1195        assert_eq!(result.capacity(), allocated_capacity);
1196    }
1197
1198    #[test]
1199    fn test_nested_complex_deserialization() {
1200        use aws_smithy_schema::Schema;
1201        use std::collections::HashMap;
1202
1203        #[derive(Debug, Default, PartialEq)]
1204        struct Address {
1205            street: String,
1206            city: String,
1207            zip: i32,
1208        }
1209        #[derive(Debug, Default, PartialEq)]
1210        struct Company {
1211            name: String,
1212            employees: Vec<String>,
1213            metadata: HashMap<String, i32>,
1214            active: bool,
1215        }
1216        #[derive(Debug, Default, PartialEq)]
1217        struct User {
1218            id: i64,
1219            name: String,
1220            scores: Vec<f64>,
1221            address: Address,
1222            companies: Vec<Company>,
1223            tags: HashMap<String, String>,
1224        }
1225
1226        // Address members & schema
1227        static ADDR_STREET: Schema = Schema::new_member(
1228            aws_smithy_schema::shape_id!("test", "Address"),
1229            aws_smithy_schema::ShapeType::String,
1230            "street",
1231            0,
1232        );
1233        static ADDR_CITY: Schema = Schema::new_member(
1234            aws_smithy_schema::shape_id!("test", "Address"),
1235            aws_smithy_schema::ShapeType::String,
1236            "city",
1237            1,
1238        );
1239        static ADDR_ZIP: Schema = Schema::new_member(
1240            aws_smithy_schema::shape_id!("test", "Address"),
1241            aws_smithy_schema::ShapeType::Integer,
1242            "zip",
1243            2,
1244        );
1245        static ADDRESS_SCHEMA: Schema = Schema::new_struct(
1246            aws_smithy_schema::shape_id!("test", "Address"),
1247            aws_smithy_schema::ShapeType::Structure,
1248            &[&ADDR_STREET, &ADDR_CITY, &ADDR_ZIP],
1249        );
1250
1251        // Company members & schema
1252        static COMP_NAME: Schema = Schema::new_member(
1253            aws_smithy_schema::shape_id!("test", "Company"),
1254            aws_smithy_schema::ShapeType::String,
1255            "name",
1256            0,
1257        );
1258        static COMP_EMPLOYEES: Schema = Schema::new_member(
1259            aws_smithy_schema::shape_id!("test", "Company"),
1260            aws_smithy_schema::ShapeType::List,
1261            "employees",
1262            1,
1263        );
1264        static COMP_METADATA: Schema = Schema::new_member(
1265            aws_smithy_schema::shape_id!("test", "Company"),
1266            aws_smithy_schema::ShapeType::Map,
1267            "metadata",
1268            2,
1269        );
1270        static COMP_ACTIVE: Schema = Schema::new_member(
1271            aws_smithy_schema::shape_id!("test", "Company"),
1272            aws_smithy_schema::ShapeType::Boolean,
1273            "active",
1274            3,
1275        );
1276        static COMPANY_SCHEMA: Schema = Schema::new_struct(
1277            aws_smithy_schema::shape_id!("test", "Company"),
1278            aws_smithy_schema::ShapeType::Structure,
1279            &[&COMP_NAME, &COMP_EMPLOYEES, &COMP_METADATA, &COMP_ACTIVE],
1280        );
1281
1282        // User members & schema
1283        static USER_ID: Schema = Schema::new_member(
1284            aws_smithy_schema::shape_id!("test", "User"),
1285            aws_smithy_schema::ShapeType::Long,
1286            "id",
1287            0,
1288        );
1289        static USER_NAME: Schema = Schema::new_member(
1290            aws_smithy_schema::shape_id!("test", "User"),
1291            aws_smithy_schema::ShapeType::String,
1292            "name",
1293            1,
1294        );
1295        static USER_SCORES: Schema = Schema::new_member(
1296            aws_smithy_schema::shape_id!("test", "User"),
1297            aws_smithy_schema::ShapeType::List,
1298            "scores",
1299            2,
1300        );
1301        static USER_ADDRESS: Schema = Schema::new_member(
1302            aws_smithy_schema::shape_id!("test", "User"),
1303            aws_smithy_schema::ShapeType::Structure,
1304            "address",
1305            3,
1306        );
1307        static USER_COMPANIES: Schema = Schema::new_member(
1308            aws_smithy_schema::shape_id!("test", "User"),
1309            aws_smithy_schema::ShapeType::List,
1310            "companies",
1311            4,
1312        );
1313        static USER_TAGS: Schema = Schema::new_member(
1314            aws_smithy_schema::shape_id!("test", "User"),
1315            aws_smithy_schema::ShapeType::Map,
1316            "tags",
1317            5,
1318        );
1319        static USER_SCHEMA: Schema = Schema::new_struct(
1320            aws_smithy_schema::shape_id!("test", "User"),
1321            aws_smithy_schema::ShapeType::Structure,
1322            &[
1323                &USER_ID,
1324                &USER_NAME,
1325                &USER_SCORES,
1326                &USER_ADDRESS,
1327                &USER_COMPANIES,
1328                &USER_TAGS,
1329            ],
1330        );
1331
1332        fn consume_address(
1333            addr: &mut Address,
1334            schema: &Schema,
1335            deser: &mut dyn ShapeDeserializer,
1336        ) -> Result<(), SerdeError> {
1337            match schema.member_name() {
1338                Some("street") => addr.street = deser.read_string(schema)?,
1339                Some("city") => addr.city = deser.read_string(schema)?,
1340                Some("zip") => addr.zip = deser.read_integer(schema)?,
1341                _ => {}
1342            }
1343            Ok(())
1344        }
1345
1346        fn consume_company(
1347            comp: &mut Company,
1348            schema: &Schema,
1349            deser: &mut dyn ShapeDeserializer,
1350        ) -> Result<(), SerdeError> {
1351            match schema.member_name() {
1352                Some("name") => comp.name = deser.read_string(schema)?,
1353                Some("active") => comp.active = deser.read_boolean(schema)?,
1354                Some("employees") => {
1355                    let mut v = Vec::new();
1356                    deser.read_list(schema, &mut |d| {
1357                        v.push(d.read_string(dummy_schema())?);
1358                        Ok(())
1359                    })?;
1360                    comp.employees = v;
1361                }
1362                Some("metadata") => {
1363                    let mut m = HashMap::new();
1364                    deser.read_map(schema, &mut |k, d| {
1365                        m.insert(k, d.read_integer(dummy_schema())?);
1366                        Ok(())
1367                    })?;
1368                    comp.metadata = m;
1369                }
1370                _ => {}
1371            }
1372            Ok(())
1373        }
1374
1375        fn consume_user(
1376            user: &mut User,
1377            schema: &Schema,
1378            deser: &mut dyn ShapeDeserializer,
1379        ) -> Result<(), SerdeError> {
1380            match schema.member_name() {
1381                Some("id") => user.id = deser.read_long(schema)?,
1382                Some("name") => user.name = deser.read_string(schema)?,
1383                Some("scores") => {
1384                    let mut v = Vec::new();
1385                    deser.read_list(schema, &mut |d| {
1386                        v.push(d.read_double(dummy_schema())?);
1387                        Ok(())
1388                    })?;
1389                    user.scores = v;
1390                }
1391                Some("address") => {
1392                    let mut addr = Address::default();
1393                    deser.read_struct(&ADDRESS_SCHEMA, &mut |member, d| {
1394                        consume_address(&mut addr, member, d)
1395                    })?;
1396                    user.address = addr;
1397                }
1398                Some("companies") => {
1399                    let mut v = Vec::new();
1400                    deser.read_list(schema, &mut |d| {
1401                        let mut comp = Company::default();
1402                        d.read_struct(&COMPANY_SCHEMA, &mut |member, d| {
1403                            consume_company(&mut comp, member, d)
1404                        })?;
1405                        v.push(comp);
1406                        Ok(())
1407                    })?;
1408                    user.companies = v;
1409                }
1410                Some("tags") => {
1411                    let mut m = HashMap::new();
1412                    deser.read_map(schema, &mut |k, d| {
1413                        m.insert(k, d.read_string(dummy_schema())?);
1414                        Ok(())
1415                    })?;
1416                    user.tags = m;
1417                }
1418                _ => {}
1419            }
1420            Ok(())
1421        }
1422
1423        let json = br#"{
1424            "id": 12345,
1425            "name": "John Doe",
1426            "scores": [95.5, 87.3, 92.1],
1427            "address": {
1428                "street": "123 Main St",
1429                "city": "Seattle",
1430                "zip": 98101
1431            },
1432            "companies": [
1433                {
1434                    "name": "TechCorp",
1435                    "employees": ["Alice", "Bob"],
1436                    "metadata": {"founded": 2010, "size": 500},
1437                    "active": true
1438                },
1439                {
1440                    "name": "StartupInc",
1441                    "employees": ["Charlie"],
1442                    "metadata": {"founded": 2020},
1443                    "active": false
1444                }
1445            ],
1446            "tags": {"role": "admin", "level": "senior"}
1447        }"#;
1448
1449        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1450        let mut user = User::default();
1451        deser
1452            .read_struct(&USER_SCHEMA, &mut |member, d| {
1453                consume_user(&mut user, member, d)
1454            })
1455            .unwrap();
1456
1457        assert_eq!(user.id, 12345);
1458        assert_eq!(user.name, "John Doe");
1459        assert_eq!(user.scores, vec![95.5, 87.3, 92.1]);
1460        assert_eq!(user.address.street, "123 Main St");
1461        assert_eq!(user.address.city, "Seattle");
1462        assert_eq!(user.address.zip, 98101);
1463        assert_eq!(user.companies.len(), 2);
1464        assert_eq!(user.companies[0].name, "TechCorp");
1465        assert_eq!(user.companies[0].employees, vec!["Alice", "Bob"]);
1466        assert_eq!(user.companies[0].metadata.get("founded"), Some(&2010));
1467        assert_eq!(user.companies[0].metadata.get("size"), Some(&500));
1468        assert!(user.companies[0].active);
1469        assert_eq!(user.companies[1].name, "StartupInc");
1470        assert_eq!(user.companies[1].employees, vec!["Charlie"]);
1471        assert_eq!(user.companies[1].metadata.get("founded"), Some(&2020));
1472        assert!(!user.companies[1].active);
1473        assert_eq!(user.tags.get("role"), Some(&"admin".to_string()));
1474        assert_eq!(user.tags.get("level"), Some(&"senior".to_string()));
1475    }
1476
1477    #[test]
1478    fn test_json_name_deserialization() {
1479        use aws_smithy_schema::Schema;
1480
1481        static FOO_MEMBER: Schema = Schema::new_member(
1482            aws_smithy_schema::shape_id!("test", "MyStruct"),
1483            aws_smithy_schema::ShapeType::String,
1484            "foo",
1485            0,
1486        );
1487        // "bar" member has @jsonName("Baz")
1488        static BAR_MEMBER: Schema = Schema::new_member(
1489            aws_smithy_schema::shape_id!("test", "MyStruct"),
1490            aws_smithy_schema::ShapeType::Integer,
1491            "bar",
1492            1,
1493        )
1494        .with_json_name("Baz");
1495        static STRUCT_SCHEMA: Schema = Schema::new_struct(
1496            aws_smithy_schema::shape_id!("test", "MyStruct"),
1497            aws_smithy_schema::ShapeType::Structure,
1498            &[&FOO_MEMBER, &BAR_MEMBER],
1499        );
1500
1501        let json = br#"{"foo":"hello","Baz":42}"#;
1502
1503        // With use_json_name=true, "Baz" resolves to the "bar" member
1504        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1505        let (mut foo, mut bar) = (None::<String>, None::<i32>);
1506        deser
1507            .read_struct(&STRUCT_SCHEMA, &mut |member, d| {
1508                match member.member_name() {
1509                    Some("foo") => foo = Some(d.read_string(member)?),
1510                    Some("bar") => bar = Some(d.read_integer(member)?),
1511                    _ => {}
1512                }
1513                Ok(())
1514            })
1515            .unwrap();
1516        assert_eq!(foo.as_deref(), Some("hello"));
1517        assert_eq!(bar, Some(42));
1518
1519        // With use_json_name=false, "Baz" is unknown and gets skipped
1520        let mut deser = JsonDeserializer::new(
1521            json,
1522            Arc::new(JsonCodecSettings::builder().use_json_name(false).build()),
1523        );
1524        let (mut foo, mut bar) = (None::<String>, None::<i32>);
1525        deser
1526            .read_struct(&STRUCT_SCHEMA, &mut |member, d| {
1527                match member.member_name() {
1528                    Some("foo") => foo = Some(d.read_string(member)?),
1529                    Some("bar") => bar = Some(d.read_integer(member)?),
1530                    _ => {}
1531                }
1532                Ok(())
1533            })
1534            .unwrap();
1535        assert_eq!(foo.as_deref(), Some("hello"));
1536        assert_eq!(bar, None); // "Baz" not recognized without jsonName
1537    }
1538
1539    fn timestamp_schema() -> &'static aws_smithy_schema::Schema {
1540        &aws_smithy_schema::prelude::TIMESTAMP
1541    }
1542
1543    #[test]
1544    fn test_read_timestamp_positive_integer() {
1545        let mut deser =
1546            JsonDeserializer::new(b"1700000000", Arc::new(JsonCodecSettings::default()));
1547        let ts = deser.read_timestamp(timestamp_schema()).unwrap();
1548        assert_eq!(ts, DateTime::from_secs(1700000000));
1549    }
1550
1551    #[test]
1552    fn test_read_timestamp_negative_integer() {
1553        let mut deser = JsonDeserializer::new(b"-1000", Arc::new(JsonCodecSettings::default()));
1554        let ts = deser.read_timestamp(timestamp_schema()).unwrap();
1555        assert_eq!(ts, DateTime::from_secs(-1000));
1556    }
1557
1558    #[test]
1559    fn test_read_timestamp_float() {
1560        // This is the format DynamoDB uses: epoch seconds with fractional part
1561        let mut deser =
1562            JsonDeserializer::new(b"1.615218678973E9", Arc::new(JsonCodecSettings::default()));
1563        let ts = deser.read_timestamp(timestamp_schema()).unwrap();
1564        assert_eq!(ts, DateTime::from_secs_f64(1.615218678973E9));
1565    }
1566
1567    #[test]
1568    fn test_read_timestamp_float_simple() {
1569        let mut deser =
1570            JsonDeserializer::new(b"1700000000.5", Arc::new(JsonCodecSettings::default()));
1571        let ts = deser.read_timestamp(timestamp_schema()).unwrap();
1572        assert_eq!(ts, DateTime::from_secs_f64(1700000000.5));
1573    }
1574
1575    #[test]
1576    fn test_read_timestamp_string_datetime() {
1577        let mut deser = JsonDeserializer::new(
1578            br#""2023-11-14T22:13:20Z""#,
1579            Arc::new(JsonCodecSettings::default()),
1580        );
1581        let ts = deser.read_timestamp(timestamp_schema()).unwrap();
1582        assert_eq!(ts, DateTime::from_secs(1700000000));
1583    }
1584
1585    #[test]
1586    fn test_read_timestamp_invalid() {
1587        let mut deser = JsonDeserializer::new(b"true", Arc::new(JsonCodecSettings::default()));
1588        assert!(deser.read_timestamp(timestamp_schema()).is_err());
1589    }
1590
1591    #[test]
1592    fn test_skip_value_empty_array() {
1593        // Regression: skip_value failed on [] because json_token_iter can't parse ']' as a value start
1594        use aws_smithy_schema::ShapeType;
1595        static KNOWN_MEMBER: Schema = Schema::new_member(
1596            aws_smithy_schema::shape_id!("test", "S"),
1597            ShapeType::String,
1598            "known",
1599            0,
1600        );
1601        static MEMBERS: &[&Schema] = &[&KNOWN_MEMBER];
1602        static TEST_SCHEMA: Schema = Schema::new_struct(
1603            aws_smithy_schema::shape_id!("test", "S"),
1604            ShapeType::Structure,
1605            MEMBERS,
1606        );
1607
1608        let json = br#"{"known":"yes","Items":[],"extra":true}"#;
1609        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1610        let mut known_val = String::new();
1611        deser
1612            .read_struct(&TEST_SCHEMA, &mut |member, deser| {
1613                if member.member_name() == Some("known") {
1614                    known_val = deser.read_string(dummy_schema())?;
1615                }
1616                Ok(())
1617            })
1618            .unwrap();
1619        assert_eq!(known_val, "yes");
1620    }
1621
1622    #[test]
1623    fn test_skip_value_nested_objects() {
1624        use aws_smithy_schema::ShapeType;
1625        static D_MEMBER: Schema = Schema::new_member(
1626            aws_smithy_schema::shape_id!("test", "S"),
1627            ShapeType::String,
1628            "d",
1629            0,
1630        );
1631        static MEMBERS: &[&Schema] = &[&D_MEMBER];
1632        static TEST_SCHEMA: Schema = Schema::new_struct(
1633            aws_smithy_schema::shape_id!("test", "S"),
1634            ShapeType::Structure,
1635            MEMBERS,
1636        );
1637
1638        let json = br#"{"a":{"b":[1,2,{"c":3}]},"d":"ok"}"#;
1639        let mut deser = JsonDeserializer::new(json, Arc::new(JsonCodecSettings::default()));
1640        let mut d_val = String::new();
1641        deser
1642            .read_struct(&TEST_SCHEMA, &mut |member, deser| {
1643                if member.member_name() == Some("d") {
1644                    d_val = deser.read_string(dummy_schema())?;
1645                }
1646                Ok(())
1647            })
1648            .unwrap();
1649        assert_eq!(d_val, "ok");
1650    }
1651}