AWS SDK

AWS SDK

rev. ab81cff57b466c663bde2f63be04bf37d9552334

Files changed:

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-json/src/codec.rs

@@ -55,55 +208,261 @@
   75     75   
///
   76     76   
/// let settings = JsonCodecSettings::builder()
   77     77   
///     .use_json_name(false)
   78     78   
///     .build();
   79     79   
/// ```
   80     80   
#[derive(Debug)]
   81     81   
pub struct JsonCodecSettings {
   82     82   
    field_mapper: JsonFieldMapper,
   83     83   
    default_timestamp_format: TimestampFormat,
   84     84   
    max_depth: u32,
          85  +
    /// When `true`, a timestamp must use exactly the wire form its resolved
          86  +
    /// `@timestampFormat` (or the codec default) prescribes: a JSON number for
          87  +
    /// `epoch-seconds`, an RFC 3339 string without a UTC offset for `date-time`,
          88  +
    /// and an IMF-fixdate string for `http-date`. Servers enable this so that
          89  +
    /// malformed requests are rejected. When `false` (default) the deserializer
          90  +
    /// is tolerant, as clients are: a number is always read as epoch seconds and
          91  +
    /// a string for a `date-time` or `epoch-seconds` member is parsed as an
          92  +
    /// offset-aware `date-time`.
          93  +
    strict_timestamp_formats: bool,
          94  +
    /// When `true`, a JSON key inside a union that names no member of the union
          95  +
    /// is an error (`SerdeError::UnknownMember`). Servers enable this: a request
          96  +
    /// carrying an unknown union member is malformed. When `false` (default) the
          97  +
    /// key is skipped, which is what clients need so that an unknown variant
          98  +
    /// sent by a newer service does not fail the whole response. `__type` is
          99  +
    /// never treated as a member.
         100  +
    reject_unknown_union_members: bool,
   85    101   
}
   86    102   
   87    103   
impl JsonCodecSettings {
   88    104   
    /// Creates a builder for `JsonCodecSettings`.
   89    105   
    pub fn builder() -> JsonCodecSettingsBuilder {
   90    106   
        JsonCodecSettingsBuilder::default()
   91    107   
    }
   92    108   
   93    109   
    /// Default timestamp format when not specified by `@timestampFormat` trait.
   94    110   
    pub fn default_timestamp_format(&self) -> TimestampFormat {
   95    111   
        self.default_timestamp_format
   96    112   
    }
   97    113   
   98    114   
    /// Maximum aggregate nesting depth the deserializer will accept before
   99    115   
    /// returning an error. Defends against stack overflow on recursive shapes
  100    116   
    /// and deeply-nested document payloads.
  101    117   
    pub fn max_depth(&self) -> u32 {
  102    118   
        self.max_depth
  103    119   
    }
  104    120   
         121  +
    /// Whether timestamps must use exactly the wire form their format prescribes.
         122  +
    /// See [`JsonCodecSettingsBuilder::strict_timestamp_formats`].
         123  +
    pub fn strict_timestamp_formats(&self) -> bool {
         124  +
        self.strict_timestamp_formats
         125  +
    }
         126  +
         127  +
    /// Whether a JSON key inside a union that names no member is an error.
         128  +
    /// See [`JsonCodecSettingsBuilder::reject_unknown_union_members`].
         129  +
    pub fn reject_unknown_union_members(&self) -> bool {
         130  +
        self.reject_unknown_union_members
         131  +
    }
         132  +
  105    133   
    /// Returns the JSON wire name for a member schema.
  106    134   
    pub(crate) fn member_to_field<'a>(&self, member: &'a Schema) -> Option<&'a str> {
  107    135   
        self.field_mapper.member_to_field(member)
  108    136   
    }
  109    137   
  110    138   
    /// Resolves a JSON wire field name to a member schema.
  111    139   
    pub(crate) fn field_to_member<'s>(
  112    140   
        &self,
  113    141   
        schema: &'s Schema,
  114    142   
        field_name: &str,
  115    143   
    ) -> Option<&'s Schema> {
  116    144   
        self.field_mapper.field_to_member(schema, field_name)
  117    145   
    }
  118    146   
}
  119    147   
  120    148   
impl Default for JsonCodecSettings {
  121    149   
    fn default() -> Self {
  122    150   
        Self {
  123    151   
            field_mapper: JsonFieldMapper::UseJsonName,
  124    152   
            default_timestamp_format: TimestampFormat::EpochSeconds,
  125    153   
            max_depth: crate::codec::deserializer::MAX_DESERIALIZE_DEPTH,
         154  +
            strict_timestamp_formats: false,
         155  +
            reject_unknown_union_members: false,
  126    156   
        }
  127    157   
    }
  128    158   
}
  129    159   
  130    160   
/// Builder for [`JsonCodecSettings`].
  131    161   
#[derive(Debug, Clone)]
  132    162   
pub struct JsonCodecSettingsBuilder {
  133    163   
    use_json_name: bool,
  134    164   
    default_timestamp_format: TimestampFormat,
  135    165   
    max_depth: u32,
         166  +
    strict_timestamp_formats: bool,
         167  +
    reject_unknown_union_members: bool,
  136    168   
}
  137    169   
  138    170   
impl Default for JsonCodecSettingsBuilder {
  139    171   
    fn default() -> Self {
  140    172   
        Self {
  141    173   
            use_json_name: true,
  142    174   
            default_timestamp_format: TimestampFormat::EpochSeconds,
  143    175   
            max_depth: crate::codec::deserializer::MAX_DESERIALIZE_DEPTH,
         176  +
            strict_timestamp_formats: false,
         177  +
            reject_unknown_union_members: false,
  144    178   
        }
  145    179   
    }
  146    180   
}
  147    181   
  148    182   
impl JsonCodecSettingsBuilder {
  149    183   
    /// Whether to use the `@jsonName` trait for member names.
  150    184   
    pub fn use_json_name(mut self, value: bool) -> Self {
  151    185   
        self.use_json_name = value;
  152    186   
        self
  153    187   
    }
  154    188   
  155    189   
    /// Default timestamp format when not specified by `@timestampFormat` trait.
  156    190   
    pub fn default_timestamp_format(mut self, value: TimestampFormat) -> Self {
  157    191   
        self.default_timestamp_format = value;
  158    192   
        self
  159    193   
    }
  160    194   
  161    195   
    /// Sets the maximum aggregate nesting depth the deserializer will accept
  162    196   
    /// before returning an error. Defaults to 128.
  163    197   
    pub fn max_depth(mut self, value: u32) -> Self {
  164    198   
        self.max_depth = value;
  165    199   
        self
  166    200   
    }
  167    201   
         202  +
    /// Require timestamps to use exactly the wire form their resolved format
         203  +
    /// prescribes: a JSON number for `epoch-seconds`, an RFC 3339 string without
         204  +
    /// a UTC offset for `date-time`, an IMF-fixdate string for `http-date`.
         205  +
    /// Off by default; servers turn it on so malformed requests are rejected.
         206  +
    pub fn strict_timestamp_formats(mut self, value: bool) -> Self {
         207  +
        self.strict_timestamp_formats = value;
         208  +
        self
         209  +
    }
         210  +
         211  +
    /// Treat a JSON key inside a union that names no member of the union as an
         212  +
    /// error instead of skipping it. Off by default; servers turn it on so
         213  +
    /// malformed requests are rejected.
         214  +
    pub fn reject_unknown_union_members(mut self, value: bool) -> Self {
         215  +
        self.reject_unknown_union_members = value;
         216  +
        self
         217  +
    }
         218  +
  168    219   
    /// Builds the settings.
  169    220   
    pub fn build(self) -> JsonCodecSettings {
  170    221   
        let field_mapper = if self.use_json_name {
  171    222   
            JsonFieldMapper::UseJsonName
  172    223   
        } else {
  173    224   
            JsonFieldMapper::UseMemberName
  174    225   
        };
  175    226   
        JsonCodecSettings {
  176    227   
            field_mapper,
  177    228   
            default_timestamp_format: self.default_timestamp_format,
  178    229   
            max_depth: self.max_depth,
         230  +
            strict_timestamp_formats: self.strict_timestamp_formats,
         231  +
            reject_unknown_union_members: self.reject_unknown_union_members,
  179    232   
        }
  180    233   
    }
  181    234   
}
  182    235   
  183    236   
/// JSON codec for schema-based serialization and deserialization.
  184    237   
///
  185    238   
/// # Examples
  186    239   
///
  187    240   
/// ```
  188    241   
/// use aws_smithy_json::codec::{JsonCodec, JsonCodecSettings};

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-json/src/codec/deserializer.rs

@@ -1,1 +40,40 @@
    1      1   
/*
    2      2   
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    3      3   
 * SPDX-License-Identifier: Apache-2.0
    4      4   
 */
    5      5   
    6      6   
//! JSON deserializer implementation.
    7      7   
    8      8   
use aws_smithy_schema::serde::SerdeError;
    9      9   
use aws_smithy_schema::serde::ShapeDeserializer;
   10         -
use aws_smithy_schema::Schema;
          10  +
use aws_smithy_schema::{Schema, ShapeType};
   11     11   
use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime, Document};
   12     12   
   13     13   
use crate::codec::JsonCodecSettings;
   14     14   
use crate::deserialize::{json_token_iter, Token};
   15     15   
   16     16   
use std::sync::Arc;
   17     17   
   18     18   
/// Maximum recursion depth for deserialization. Payloads nested deeper than
   19     19   
/// this will produce a [`SerdeError`] instead of risking a stack overflow.
   20     20   
/// Matches the default used by `serde_json`.
@@ -102,102 +301,297 @@
  122    122   
            self.depth -= 1;
  123    123   
            return Ok(());
  124    124   
        }
  125    125   
        if self.remaining().first() != Some(&b'{') {
  126    126   
            return Err(SerdeError::TypeMismatch {
  127    127   
                message: "expected object".into(),
  128    128   
            });
  129    129   
        }
  130    130   
        self.advance_by(1);
  131    131   
         132  +
        // A union holds exactly one member. Every key that names a member counts as a
         133  +
        // variant, so a second one is an error, as in the token-based parser
         134  +
        // ("encountered mixed variants in union"). `null` values are absent members and
         135  +
        // do not count; `__type` is a discriminator, never a member.
         136  +
        let is_union = matches!(schema.shape_type(), ShapeType::Union);
         137  +
        let mut variant_seen = false;
         138  +
        let mut first = true;
  132    139   
        loop {
  133         -
            self.skip_whitespace();
  134         -
  135         -
            // Check for end of object, error on end of input, otherwise
  136         -
            // fall through to parse the next key/value pair.
  137         -
            match self.remaining().first() {
  138         -
                Some(&b'}') => {
  139         -
                    self.advance_by(1);
  140         -
                    break;
  141         -
                }
  142         -
                None => {
  143         -
                    return Err(SerdeError::InvalidInput {
  144         -
                        message: "unexpected end of input in object".into(),
  145         -
                    });
  146         -
                }
  147         -
                Some(&b'"') => {}
  148         -
                Some(_) => {
  149         -
                    return Err(SerdeError::InvalidInput {
  150         -
                        message: "expected object key".into(),
  151         -
                    });
  152         -
                }
         140  +
            // Stop at the end of the object; otherwise the next key/value pair starts here.
         141  +
            if self.next_element(first, b'}', "object")? {
         142  +
                break;
         143  +
            }
         144  +
            first = false;
         145  +
            if self.remaining().first() != Some(&b'"') {
         146  +
                return Err(SerdeError::InvalidInput {
         147  +
                    message: "expected object key".into(),
         148  +
                });
  153    149   
            }
  154    150   
  155    151   
            // Parse the key directly from bytes
  156    152   
            let key_str = self.parse_key()?;
  157    153   
  158    154   
            // Skip whitespace and expect colon
  159    155   
            self.skip_whitespace();
  160    156   
            if self.remaining().first() != Some(&b':') {
  161    157   
                return Err(SerdeError::InvalidInput {
  162    158   
                    message: "expected colon after key".into(),
  163    159   
                });
  164    160   
            }
  165    161   
            self.advance_by(1);
  166    162   
            self.skip_whitespace();
  167    163   
  168    164   
            // Process the value — skip nulls (they represent absent optional members)
  169    165   
            let rem = self.remaining();
  170    166   
            if rem.starts_with(b"null") && !rem.get(4).is_some_and(|b| b.is_ascii_alphanumeric()) {
  171    167   
                self.advance_by(4);
  172    168   
            } else if let Some(member_schema) = self.resolve_member(schema, &key_str) {
         169  +
                if is_union {
         170  +
                    if variant_seen {
         171  +
                        return Err(SerdeError::InvalidInput {
         172  +
                            message: "encountered mixed variants in union".into(),
         173  +
                        });
         174  +
                    }
         175  +
                    variant_seen = true;
         176  +
                }
  173    177   
                consumer(member_schema, self)?;
         178  +
            } else if is_union
         179  +
                && &*key_str != "__type"
         180  +
                && self.settings.reject_unknown_union_members()
         181  +
            {
         182  +
                return Err(SerdeError::UnknownMember {
         183  +
                    member_name: key_str.into_owned(),
         184  +
                });
  174    185   
            } else {
  175    186   
                self.skip_value()?;
  176    187   
            }
  177    188   
        }
  178    189   
  179         -
        self.depth -= 1;
         190  +
        self.leave_container()?;
  180    191   
        Ok(())
  181    192   
    }
  182    193   
  183    194   
    fn read_list(
  184    195   
        &mut self,
  185    196   
        _schema: &Schema,
  186    197   
        consumer: &mut dyn FnMut(&mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
  187    198   
    ) -> Result<(), SerdeError> {
  188    199   
        self.depth += 1;
  189    200   
        if self.depth > self.settings.max_depth() {
  190    201   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  191    202   
        }
  192    203   
        self.skip_whitespace();
  193    204   
        if self.remaining().first() != Some(&b'[') {
  194    205   
            return Err(SerdeError::TypeMismatch {
  195    206   
                message: "expected array".into(),
  196    207   
            });
  197    208   
        }
  198    209   
        self.advance_by(1);
  199    210   
         211  +
        let mut first = true;
  200    212   
        loop {
  201         -
            self.skip_whitespace();
  202         -
            match self.remaining().first() {
  203         -
                Some(&b']') => {
  204         -
                    self.advance_by(1);
  205         -
                    break;
  206         -
                }
  207         -
                None => {
  208         -
                    return Err(SerdeError::InvalidInput {
  209         -
                        message: "unexpected end of input in array".into(),
  210         -
                    });
  211         -
                }
  212         -
                _ => consumer(self)?,
         213  +
            if self.next_element(first, b']', "array")? {
         214  +
                break;
  213    215   
            }
         216  +
            first = false;
         217  +
            consumer(self)?;
  214    218   
        }
  215    219   
  216         -
        self.depth -= 1;
         220  +
        self.leave_container()?;
  217    221   
        Ok(())
  218    222   
    }
  219    223   
  220    224   
    fn read_map(
  221    225   
        &mut self,
  222    226   
        _schema: &Schema,
  223    227   
        consumer: &mut dyn FnMut(String, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
  224    228   
    ) -> Result<(), SerdeError> {
  225    229   
        self.depth += 1;
  226    230   
        if self.depth > self.settings.max_depth() {
  227    231   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  228    232   
        }
  229    233   
        self.skip_whitespace();
  230    234   
        if self.remaining().first() != Some(&b'{') {
  231    235   
            return Err(SerdeError::TypeMismatch {
  232    236   
                message: "expected object".into(),
  233    237   
            });
  234    238   
        }
  235    239   
        self.advance_by(1);
  236    240   
         241  +
        let mut first = true;
  237    242   
        loop {
  238         -
            self.skip_whitespace();
  239         -
            match self.remaining().first() {
  240         -
                Some(&b'}') => {
  241         -
                    self.advance_by(1);
  242         -
                    break;
  243         -
                }
  244         -
                None => {
  245         -
                    return Err(SerdeError::InvalidInput {
  246         -
                        message: "unexpected end of input in object".into(),
  247         -
                    });
  248         -
                }
  249         -
                Some(&b'"') => {}
  250         -
                Some(_) => {
  251         -
                    return Err(SerdeError::InvalidInput {
  252         -
                        message: "expected key".into(),
  253         -
                    });
  254         -
                }
         243  +
            if self.next_element(first, b'}', "object")? {
         244  +
                break;
         245  +
            }
         246  +
            first = false;
         247  +
            if self.remaining().first() != Some(&b'"') {
         248  +
                return Err(SerdeError::InvalidInput {
         249  +
                    message: "expected key".into(),
         250  +
                });
  255    251   
            }
  256    252   
  257    253   
            let key = self.parse_key()?;
  258    254   
  259    255   
            self.skip_whitespace();
  260    256   
            if self.remaining().first() != Some(&b':') {
  261    257   
                return Err(SerdeError::InvalidInput {
  262    258   
                    message: "expected colon".into(),
  263    259   
                });
  264    260   
            }
  265    261   
            self.advance_by(1);
  266    262   
            self.skip_whitespace();
  267    263   
  268    264   
            consumer(key.into_owned(), self)?;
  269    265   
        }
  270    266   
  271         -
        self.depth -= 1;
         267  +
        self.leave_container()?;
  272    268   
        Ok(())
  273    269   
    }
  274    270   
  275    271   
    fn read_boolean(&mut self, _schema: &Schema) -> Result<bool, SerdeError> {
  276    272   
        self.skip_whitespace();
  277    273   
        let rem = self.remaining();
  278    274   
        if rem.starts_with(b"true") {
  279    275   
            self.advance_by(4);
  280    276   
            Ok(true)
  281    277   
        } else if rem.starts_with(b"false") {
@@ -410,406 +807,787 @@
  430    426   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  431    427   
        }
  432    428   
        self.skip_whitespace();
  433    429   
        if self.remaining().first() != Some(&b'[') {
  434    430   
            return Err(SerdeError::TypeMismatch {
  435    431   
                message: "expected array".into(),
  436    432   
            });
  437    433   
        }
  438    434   
        self.advance_by(1);
  439    435   
        let mut out = Vec::new();
         436  +
        let mut first = true;
  440    437   
        loop {
  441         -
            self.skip_whitespace();
  442         -
            match self.remaining().first() {
  443         -
                Some(&b']') => {
  444         -
                    self.advance_by(1);
  445         -
                    break;
  446         -
                }
  447         -
                None => {
  448         -
                    return Err(SerdeError::InvalidInput {
  449         -
                        message: "unexpected end of input in array".into(),
  450         -
                    })
  451         -
                }
  452         -
                _ => out.push(self.read_string(_schema)?),
         438  +
            if self.next_element(first, b']', "array")? {
         439  +
                break;
  453    440   
            }
         441  +
            first = false;
         442  +
            out.push(self.read_string(_schema)?);
  454    443   
        }
  455         -
        self.depth -= 1;
         444  +
        self.leave_container()?;
  456    445   
        Ok(out)
  457    446   
    }
  458    447   
  459    448   
    fn read_blob_list(&mut self, _schema: &Schema) -> Result<Vec<Blob>, SerdeError> {
  460    449   
        self.depth += 1;
  461    450   
        if self.depth > self.settings.max_depth() {
  462    451   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  463    452   
        }
  464    453   
        self.skip_whitespace();
  465    454   
        if self.remaining().first() != Some(&b'[') {
  466    455   
            return Err(SerdeError::TypeMismatch {
  467    456   
                message: "expected array".into(),
  468    457   
            });
  469    458   
        }
  470    459   
        self.advance_by(1);
  471    460   
        let mut out = Vec::new();
         461  +
        let mut first = true;
  472    462   
        loop {
  473         -
            self.skip_whitespace();
  474         -
            match self.remaining().first() {
  475         -
                Some(&b']') => {
  476         -
                    self.advance_by(1);
  477         -
                    break;
  478         -
                }
  479         -
                None => {
  480         -
                    return Err(SerdeError::InvalidInput {
  481         -
                        message: "unexpected end of input in array".into(),
  482         -
                    })
  483         -
                }
  484         -
                _ => out.push(self.read_blob(_schema)?),
         463  +
            if self.next_element(first, b']', "array")? {
         464  +
                break;
  485    465   
            }
         466  +
            first = false;
         467  +
            out.push(self.read_blob(_schema)?);
  486    468   
        }
  487         -
        self.depth -= 1;
         469  +
        self.leave_container()?;
  488    470   
        Ok(out)
  489    471   
    }
  490    472   
  491    473   
    fn read_integer_list(&mut self, _schema: &Schema) -> Result<Vec<i32>, SerdeError> {
  492    474   
        self.depth += 1;
  493    475   
        if self.depth > self.settings.max_depth() {
  494    476   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  495    477   
        }
  496    478   
        self.skip_whitespace();
  497    479   
        if self.remaining().first() != Some(&b'[') {
  498    480   
            return Err(SerdeError::TypeMismatch {
  499    481   
                message: "expected array".into(),
  500    482   
            });
  501    483   
        }
  502    484   
        self.advance_by(1);
  503    485   
        let mut out = Vec::new();
         486  +
        let mut first = true;
  504    487   
        loop {
  505         -
            self.skip_whitespace();
  506         -
            match self.remaining().first() {
  507         -
                Some(&b']') => {
  508         -
                    self.advance_by(1);
  509         -
                    break;
  510         -
                }
  511         -
                None => {
  512         -
                    return Err(SerdeError::InvalidInput {
  513         -
                        message: "unexpected end of input in array".into(),
  514         -
                    })
  515         -
                }
  516         -
                _ => out.push(self.read_integer(_schema)?),
         488  +
            if self.next_element(first, b']', "array")? {
         489  +
                break;
  517    490   
            }
         491  +
            first = false;
         492  +
            out.push(self.read_integer(_schema)?);
  518    493   
        }
  519         -
        self.depth -= 1;
         494  +
        self.leave_container()?;
  520    495   
        Ok(out)
  521    496   
    }
  522    497   
  523    498   
    fn read_long_list(&mut self, _schema: &Schema) -> Result<Vec<i64>, SerdeError> {
  524    499   
        self.depth += 1;
  525    500   
        if self.depth > self.settings.max_depth() {
  526    501   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  527    502   
        }
  528    503   
        self.skip_whitespace();
  529    504   
        if self.remaining().first() != Some(&b'[') {
  530    505   
            return Err(SerdeError::TypeMismatch {
  531    506   
                message: "expected array".into(),
  532    507   
            });
  533    508   
        }
  534    509   
        self.advance_by(1);
  535    510   
        let mut out = Vec::new();
         511  +
        let mut first = true;
  536    512   
        loop {
  537         -
            self.skip_whitespace();
  538         -
            match self.remaining().first() {
  539         -
                Some(&b']') => {
  540         -
                    self.advance_by(1);
  541         -
                    break;
  542         -
                }
  543         -
                None => {
  544         -
                    return Err(SerdeError::InvalidInput {
  545         -
                        message: "unexpected end of input in array".into(),
  546         -
                    })
  547         -
                }
  548         -
                _ => out.push(self.read_long(_schema)?),
         513  +
            if self.next_element(first, b']', "array")? {
         514  +
                break;
  549    515   
            }
         516  +
            first = false;
         517  +
            out.push(self.read_long(_schema)?);
  550    518   
        }
  551         -
        self.depth -= 1;
         519  +
        self.leave_container()?;
  552    520   
        Ok(out)
  553    521   
    }
  554    522   
  555    523   
    fn read_string_string_map(
  556    524   
        &mut self,
  557    525   
        _schema: &Schema,
  558    526   
    ) -> Result<std::collections::HashMap<String, String>, SerdeError> {
  559    527   
        self.depth += 1;
  560    528   
        if self.depth > self.settings.max_depth() {
  561    529   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  562    530   
        }
  563    531   
        self.skip_whitespace();
  564    532   
        if self.remaining().first() != Some(&b'{') {
  565    533   
            return Err(SerdeError::TypeMismatch {
  566    534   
                message: "expected object".into(),
  567    535   
            });
  568    536   
        }
  569    537   
        self.advance_by(1);
  570    538   
        let mut out = std::collections::HashMap::new();
         539  +
        let mut first = true;
  571    540   
        loop {
  572         -
            self.skip_whitespace();
  573         -
            if self.remaining().first() == Some(&b'}') {
  574         -
                self.advance_by(1);
         541  +
            if self.next_element(first, b'}', "object")? {
  575    542   
                break;
  576    543   
            }
         544  +
            first = false;
  577    545   
            if self.remaining().first() != Some(&b'"') {
  578    546   
                return Err(SerdeError::InvalidInput {
  579    547   
                    message: "expected key".into(),
  580    548   
                });
  581    549   
            }
  582    550   
            let key = self.parse_key()?;
  583    551   
            self.skip_whitespace();
  584    552   
            if self.remaining().first() != Some(&b':') {
  585    553   
                return Err(SerdeError::InvalidInput {
  586    554   
                    message: "expected colon".into(),
  587    555   
                });
  588    556   
            }
  589    557   
            self.advance_by(1);
  590    558   
            self.skip_whitespace();
  591    559   
            let val = self.read_string(_schema)?;
  592    560   
            out.insert(key.into_owned(), val);
  593    561   
        }
  594         -
        self.depth -= 1;
         562  +
        self.leave_container()?;
  595    563   
        Ok(out)
  596    564   
    }
  597    565   
  598    566   
    fn read_timestamp(&mut self, schema: &Schema) -> Result<DateTime, SerdeError> {
         567  +
        use aws_smithy_schema::traits::TimestampFormat;
         568  +
        use aws_smithy_types::date_time::Format;
         569  +
  599    570   
        self.skip_whitespace();
  600         -
        let rem = self.remaining();
  601         -
        match rem.first() {
         571  +
        let strict = self.settings.strict_timestamp_formats();
         572  +
        // The wire form the member prescribes: its `@timestampFormat`, else the codec default.
         573  +
        let format = match schema.timestamp_format().map(|t| t.format()) {
         574  +
            Some(TimestampFormat::EpochSeconds) => Format::EpochSeconds,
         575  +
            Some(TimestampFormat::DateTime) => Format::DateTime,
         576  +
            Some(TimestampFormat::HttpDate) => Format::HttpDate,
         577  +
            None => self.settings.default_timestamp_format(),
         578  +
        };
         579  +
        match self.remaining().first() {
  602    580   
            Some(b'"') => {
  603         -
                let s = self.read_string(schema)?;
  604         -
                // Determine parse format from @timestampFormat trait or default
  605         -
                let format = if let Some(ts_trait) = schema.timestamp_format() {
  606         -
                    match ts_trait.format() {
  607         -
                        aws_smithy_schema::traits::TimestampFormat::HttpDate => {
  608         -
                            aws_smithy_types::date_time::Format::HttpDate
  609         -
                        }
  610         -
                        aws_smithy_schema::traits::TimestampFormat::EpochSeconds => {
  611         -
                            aws_smithy_types::date_time::Format::EpochSeconds
  612         -
                        }
  613         -
                        aws_smithy_schema::traits::TimestampFormat::DateTime => {
  614         -
                            aws_smithy_types::date_time::Format::DateTimeWithOffset
  615         -
                        }
         581  +
                let string_format = if strict {
         582  +
                    // Strict: the string must be in exactly the prescribed format, and
         583  +
                    // `epoch-seconds` is never a string. This mirrors the token-based
         584  +
                    // parser's `expect_timestamp_or_null`, which the legacy server uses.
         585  +
                    if matches!(format, Format::EpochSeconds) {
         586  +
                        return Err(SerdeError::TypeMismatch {
         587  +
                            message: "expected a JSON number for an epoch-seconds timestamp".into(),
         588  +
                        });
  616    589   
                    }
         590  +
                    format
  617    591   
                } else {
  618         -
                    // Default: try date-time with offsets allowed
  619         -
                    aws_smithy_types::date_time::Format::DateTimeWithOffset
         592  +
                    // Lenient (unchanged behavior): an explicit `@timestampFormat` of
         593  +
                    // `http-date` or `epoch-seconds` is honored as written; `date-time` and
         594  +
                    // members without the trait parse as offset-aware `date-time`.
         595  +
                    match schema.timestamp_format().map(|t| t.format()) {
         596  +
                        Some(TimestampFormat::HttpDate) => Format::HttpDate,
         597  +
                        Some(TimestampFormat::EpochSeconds) => Format::EpochSeconds,
         598  +
                        _ => Format::DateTimeWithOffset,
         599  +
                    }
  620    600   
                };
  621         -
                DateTime::from_str(&s, format)
         601  +
                let s = self.read_string(schema)?;
         602  +
                DateTime::from_str(&s, string_format)
  622    603   
                    .map_err(|e| SerdeError::custom(format!("invalid timestamp string: {e}")))
  623    604   
            }
  624    605   
            Some(b'-') | Some(b'0'..=b'9') => {
  625         -
                // Numeric timestamp — epoch seconds
         606  +
                if strict && !matches!(format, Format::EpochSeconds) {
         607  +
                    return Err(SerdeError::TypeMismatch {
         608  +
                        message: "expected a JSON string for a date-time or http-date timestamp"
         609  +
                            .into(),
         610  +
                    });
         611  +
                }
         612  +
                // Numeric timestamp: epoch seconds.
  626    613   
                let start = self.position;
  627    614   
                self.consume_number();
  628    615   
                let num_str =
  629    616   
                    std::str::from_utf8(&self.input[start..self.position]).map_err(|e| {
  630    617   
                        SerdeError::InvalidInput {
  631    618   
                            message: e.to_string(),
  632    619   
                        }
  633    620   
                    })?;
  634    621   
                if num_str.contains('.') || num_str.contains('e') || num_str.contains('E') {
  635    622   
                    let f: f64 = num_str.parse().map_err(|e: std::num::ParseFloatError| {
  636    623   
                        SerdeError::InvalidInput {
  637    624   
                            message: e.to_string(),
  638    625   
                        }
  639    626   
                    })?;
  640    627   
                    Ok(DateTime::from_secs_f64(f))
  641    628   
                } else if num_str.starts_with('-') {
  642    629   
                    let n: i64 = num_str.parse().map_err(|e: std::num::ParseIntError| {
  643    630   
                        SerdeError::InvalidInput {
  644    631   
                            message: e.to_string(),
  645    632   
                        }
  646    633   
                    })?;
  647    634   
                    Ok(DateTime::from_secs(n))
  648    635   
                } else {
  649    636   
                    let n: u64 = num_str.parse().map_err(|e: std::num::ParseIntError| {
  650    637   
                        SerdeError::InvalidInput {
  651    638   
                            message: e.to_string(),
  652    639   
                        }
  653    640   
                    })?;
  654    641   
                    Ok(DateTime::from_secs(n as i64))
  655    642   
                }
  656    643   
            }
  657    644   
            _ => Err(SerdeError::TypeMismatch {
  658    645   
                message: "expected timestamp".into(),
  659    646   
            }),
  660    647   
        }
  661    648   
    }
  662    649   
  663    650   
    fn read_document(&mut self, _schema: &Schema) -> Result<Document, SerdeError> {
  664    651   
        self.depth += 1;
  665    652   
        if self.depth > self.settings.max_depth() {
  666    653   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  667    654   
        }
  668    655   
        self.skip_whitespace();
  669    656   
        let result = match self.remaining().first() {
  670    657   
            Some(b'"') => Ok(Document::String(self.read_string(_schema)?)),
  671    658   
            Some(b't') | Some(b'f') => Ok(Document::Bool(self.read_boolean(_schema)?)),
  672    659   
            Some(b'n') => {
  673    660   
                if self.remaining().starts_with(b"null") {
  674    661   
                    self.advance_by(4);
  675    662   
                    Ok(Document::Null)
  676    663   
                } else {
  677    664   
                    Err(SerdeError::InvalidInput {
  678    665   
                        message: "unexpected token in document".into(),
  679    666   
                    })
  680    667   
                }
  681    668   
            }
  682    669   
            Some(b'{') => {
  683    670   
                self.advance_by(1);
  684    671   
                let mut map = std::collections::HashMap::new();
         672  +
                let mut first = true;
  685    673   
                loop {
  686         -
                    self.skip_whitespace();
  687         -
                    if self.remaining().first() == Some(&b'}') {
  688         -
                        self.advance_by(1);
         674  +
                    if self.next_element(first, b'}', "document object")? {
  689    675   
                        break;
  690    676   
                    }
         677  +
                    first = false;
  691    678   
                    if self.remaining().first() != Some(&b'"') {
  692    679   
                        return Err(SerdeError::InvalidInput {
  693    680   
                            message: "expected object key in document".into(),
  694    681   
                        });
  695    682   
                    }
  696    683   
                    let key = self.parse_key()?.into_owned();
  697    684   
                    self.skip_whitespace();
  698    685   
                    if self.remaining().first() != Some(&b':') {
  699    686   
                        return Err(SerdeError::InvalidInput {
  700    687   
                            message: "expected colon in document object".into(),
  701    688   
                        });
  702    689   
                    }
  703    690   
                    self.advance_by(1);
  704    691   
                    let value = self.read_document(_schema)?;
  705    692   
                    map.insert(key, value);
  706    693   
                }
  707    694   
                Ok(Document::Object(map))
  708    695   
            }
  709    696   
            Some(b'[') => {
  710    697   
                self.advance_by(1);
  711    698   
                let mut arr = Vec::new();
         699  +
                let mut first = true;
  712    700   
                loop {
  713         -
                    self.skip_whitespace();
  714         -
                    match self.remaining().first() {
  715         -
                        Some(&b']') => {
  716         -
                            self.advance_by(1);
  717         -
                            break;
  718         -
                        }
  719         -
                        None => {
  720         -
                            return Err(SerdeError::InvalidInput {
  721         -
                                message: "unexpected end of input in document array".into(),
  722         -
                            })
  723         -
                        }
  724         -
                        _ => arr.push(self.read_document(_schema)?),
         701  +
                    if self.next_element(first, b']', "document array")? {
         702  +
                        break;
  725    703   
                    }
         704  +
                    first = false;
         705  +
                    arr.push(self.read_document(_schema)?);
  726    706   
                }
  727    707   
                Ok(Document::Array(arr))
  728    708   
            }
  729    709   
            Some(c) if *c == b'-' || c.is_ascii_digit() => {
  730    710   
                // Parse number — determine if integer or float
  731    711   
                let rem = self.remaining();
  732    712   
                let mut len = 0;
  733    713   
                let mut is_float = false;
  734    714   
                let mut is_negative = false;
  735    715   
                for (i, &b) in rem.iter().enumerate() {
  736    716   
                    if b == b'-' && i == 0 {
  737    717   
                        is_negative = true;
  738    718   
                        len += 1;
  739    719   
                    } else if b.is_ascii_digit() || b == b'+' {
  740    720   
                        len += 1;
  741    721   
                    } else if b == b'.' || b == b'e' || b == b'E' {
  742    722   
                        is_float = true;
  743    723   
                        len += 1;
  744    724   
                    } else {
  745    725   
                        break;
  746    726   
                    }
  747    727   
                }
  748    728   
                let pos = self.position;
  749    729   
                self.advance_by(len);
  750    730   
                let s = std::str::from_utf8(&self.input[pos..pos + len]).map_err(|e| {
  751    731   
                    SerdeError::InvalidInput {
  752    732   
                        message: e.to_string(),
  753    733   
                    }
  754    734   
                })?;
  755    735   
                if is_float {
  756    736   
                    let f = s.parse::<f64>().map_err(|e| SerdeError::InvalidInput {
  757    737   
                        message: e.to_string(),
  758    738   
                    })?;
  759    739   
                    Ok(Document::Number(aws_smithy_types::Number::Float(f)))
  760    740   
                } else if is_negative {
  761    741   
                    let n = s.parse::<i64>().map_err(|e| SerdeError::InvalidInput {
  762    742   
                        message: e.to_string(),
  763    743   
                    })?;
  764    744   
                    Ok(Document::Number(aws_smithy_types::Number::NegInt(n)))
  765    745   
                } else {
  766    746   
                    let n = s.parse::<u64>().map_err(|e| SerdeError::InvalidInput {
  767    747   
                        message: e.to_string(),
  768    748   
                    })?;
  769    749   
                    Ok(Document::Number(aws_smithy_types::Number::PosInt(n)))
  770    750   
                }
  771    751   
            }
  772    752   
            _ => Err(SerdeError::InvalidInput {
  773    753   
                message: "unexpected token in document".into(),
  774    754   
            }),
  775    755   
        };
  776    756   
        if result.is_ok() {
  777         -
            self.depth -= 1;
         757  +
            self.leave_container()?;
  778    758   
        }
  779    759   
        result
  780    760   
    }
  781    761   
  782    762   
    fn is_null(&self) -> bool {
  783    763   
        let remaining = self.remaining();
  784    764   
        remaining.len() >= 4
  785    765   
            && &remaining[..4] == b"null"
  786    766   
            && !remaining.get(4).is_some_and(|b| b.is_ascii_alphanumeric())
  787    767   
    }
@@ -827,807 +1046,1165 @@
  847    827   
            }
  848    828   
            _ => None,
  849    829   
        }
  850    830   
    }
  851    831   
}
  852    832   
  853    833   
impl<'a> JsonDeserializer<'a> {
  854    834   
    fn skip_whitespace(&mut self) {
  855    835   
        while self.position < self.input.len() {
  856    836   
            match self.input[self.position] {
  857         -
                b' ' | b'\t' | b'\n' | b'\r' | b',' => self.position += 1,
         837  +
                b' ' | b'\t' | b'\n' | b'\r' => self.position += 1,
  858    838   
                _ => break,
  859    839   
            }
  860    840   
        }
  861    841   
    }
  862    842   
         843  +
    /// Positions the deserializer at the next element of a container whose closing
         844  +
    /// delimiter is `close`, enforcing JSON's separator rules: elements are separated by
         845  +
    /// exactly one comma, and no comma may precede the closing delimiter.
         846  +
    ///
         847  +
    /// Returns `true` when the closing delimiter was reached and consumed, `false` when the
         848  +
    /// next element starts at the current position. `first` is whether no element has been
         849  +
    /// read from this container yet.
         850  +
    fn next_element(&mut self, first: bool, close: u8, what: &str) -> Result<bool, SerdeError> {
         851  +
        self.skip_whitespace();
         852  +
        match self.remaining().first().copied() {
         853  +
            Some(b) if b == close => {
         854  +
                self.advance_by(1);
         855  +
                Ok(true)
         856  +
            }
         857  +
            None => Err(SerdeError::InvalidInput {
         858  +
                message: format!("unexpected end of input in {what}"),
         859  +
            }),
         860  +
            Some(b',') if first => Err(SerdeError::InvalidInput {
         861  +
                message: format!("unexpected `,` before the first element of {what}"),
         862  +
            }),
         863  +
            Some(b',') => {
         864  +
                self.advance_by(1);
         865  +
                self.skip_whitespace();
         866  +
                match self.remaining().first().copied() {
         867  +
                    Some(b) if b == close => Err(SerdeError::InvalidInput {
         868  +
                        message: format!("trailing `,` in {what}"),
         869  +
                    }),
         870  +
                    Some(b',') => Err(SerdeError::InvalidInput {
         871  +
                        message: format!("repeated `,` in {what}"),
         872  +
                    }),
         873  +
                    None => Err(SerdeError::InvalidInput {
         874  +
                        message: format!("unexpected end of input in {what}"),
         875  +
                    }),
         876  +
                    Some(_) => Ok(false),
         877  +
                }
         878  +
            }
         879  +
            Some(_) if first => Ok(false),
         880  +
            Some(_) => Err(SerdeError::InvalidInput {
         881  +
                message: format!("expected `,` between elements of {what}"),
         882  +
            }),
         883  +
        }
         884  +
    }
         885  +
         886  +
    fn enter_container(&mut self) -> Result<(), SerdeError> {
         887  +
        self.depth += 1;
         888  +
        if self.depth > self.settings.max_depth() {
         889  +
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
         890  +
        }
         891  +
        Ok(())
         892  +
    }
         893  +
         894  +
    /// Leaves a container. When it was the outermost value of the input, nothing but
         895  +
    /// whitespace may follow it: a body such as `{"a": 1}abc` is malformed JSON and is
         896  +
    /// rejected here, matching the token-based parser's "found more JSON tokens after
         897  +
    /// completing parsing" check.
         898  +
    fn leave_container(&mut self) -> Result<(), SerdeError> {
         899  +
        self.depth -= 1;
         900  +
        if self.depth == 0 {
         901  +
            self.skip_whitespace();
         902  +
            if !self.remaining().is_empty() {
         903  +
                return Err(SerdeError::InvalidInput {
         904  +
                    message: "unexpected trailing characters after the JSON value".into(),
         905  +
                });
         906  +
            }
         907  +
        }
         908  +
        Ok(())
         909  +
    }
         910  +
         911  +
    /// Skips a JSON number, validating it against the RFC 8259 grammar
         912  +
    /// `-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?`. Whatever follows is left for the
         913  +
    /// enclosing container's separator check, so `01` fails there as "expected `,`".
         914  +
    fn skip_number(&mut self) -> Result<(), SerdeError> {
         915  +
        let rem = self.remaining();
         916  +
        let invalid = || SerdeError::InvalidInput {
         917  +
            message: "invalid number".into(),
         918  +
        };
         919  +
        let mut i = 0;
         920  +
        if rem.get(i) == Some(&b'-') {
         921  +
            i += 1;
         922  +
        }
         923  +
        match rem.get(i) {
         924  +
            Some(b'0') => i += 1,
         925  +
            Some(b'1'..=b'9') => {
         926  +
                while rem.get(i).is_some_and(|b| b.is_ascii_digit()) {
         927  +
                    i += 1;
         928  +
                }
         929  +
            }
         930  +
            _ => return Err(invalid()),
         931  +
        }
         932  +
        if rem.get(i) == Some(&b'.') {
         933  +
            i += 1;
         934  +
            let start = i;
         935  +
            while rem.get(i).is_some_and(|b| b.is_ascii_digit()) {
         936  +
                i += 1;
         937  +
            }
         938  +
            if i == start {
         939  +
                return Err(invalid());
         940  +
            }
         941  +
        }
         942  +
        if matches!(rem.get(i), Some(b'e') | Some(b'E')) {
         943  +
            i += 1;
         944  +
            if matches!(rem.get(i), Some(b'+') | Some(b'-')) {
         945  +
                i += 1;
         946  +
            }
         947  +
            let start = i;
         948  +
            while rem.get(i).is_some_and(|b| b.is_ascii_digit()) {
         949  +
                i += 1;
         950  +
            }
         951  +
            if i == start {
         952  +
                return Err(invalid());
         953  +
            }
         954  +
        }
         955  +
        self.advance_by(i);
         956  +
        Ok(())
         957  +
    }
         958  +
         959  +
    /// Skips a JSON string, accepting exactly the escape sequences `read_string` accepts.
         960  +
    fn skip_string(&mut self) -> Result<(), SerdeError> {
         961  +
        let rem = self.remaining();
         962  +
        debug_assert_eq!(rem.first(), Some(&b'"'));
         963  +
        let mut i = 1;
         964  +
        loop {
         965  +
            match rem.get(i) {
         966  +
                None => {
         967  +
                    return Err(SerdeError::InvalidInput {
         968  +
                        message: "unterminated string".into(),
         969  +
                    })
         970  +
                }
         971  +
                Some(b'"') => {
         972  +
                    i += 1;
         973  +
                    break;
         974  +
                }
         975  +
                Some(b'\\') => match rem.get(i + 1) {
         976  +
                    Some(b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't') => i += 2,
         977  +
                    Some(b'u')
         978  +
                        if rem
         979  +
                            .get(i + 2..i + 6)
         980  +
                            .is_some_and(|hex| hex.iter().all(u8::is_ascii_hexdigit)) =>
         981  +
                    {
         982  +
                        i += 6
         983  +
                    }
         984  +
                    _ => {
         985  +
                        return Err(SerdeError::InvalidInput {
         986  +
                            message: "invalid escape sequence in string".into(),
         987  +
                        })
         988  +
                    }
         989  +
                },
         990  +
                Some(_) => i += 1,
         991  +
            }
         992  +
        }
         993  +
        self.advance_by(i);
         994  +
        Ok(())
         995  +
    }
         996  +
  863    997   
    fn consume_number(&mut self) {
  864    998   
        let mut len = 0;
  865    999   
        for &b in self.remaining() {
  866   1000   
            if b.is_ascii_digit() || b == b'-' || b == b'.' || b == b'e' || b == b'E' || b == b'+' {
  867   1001   
                len += 1;
  868   1002   
            } else {
  869   1003   
                break;
  870   1004   
            }
  871   1005   
        }
  872   1006   
        self.advance_by(len);
  873   1007   
    }
  874   1008   
        1009  +
    /// Skips one JSON value, validating its syntax as it goes so that an unknown member
        1010  +
    /// cannot smuggle malformed JSON past the deserializer. Like `read_string`, raw control
        1011  +
    /// characters inside strings are not rejected.
  875   1012   
    fn skip_value(&mut self) -> Result<(), SerdeError> {
  876   1013   
        self.skip_whitespace();
  877         -
        let mut depth: usize = 0;
  878         -
        loop {
  879         -
            self.skip_whitespace();
  880         -
            match self.remaining().first().copied() {
  881         -
                Some(b'{') | Some(b'[') => {
  882         -
                    self.advance_by(1);
  883         -
                    depth += 1;
  884         -
                }
  885         -
                Some(b'}') | Some(b']') => {
  886         -
                    if depth == 0 {
  887         -
                        return Err(SerdeError::InvalidInput {
  888         -
                            message: "unexpected end token".into(),
  889         -
                        });
  890         -
                    }
  891         -
                    self.advance_by(1);
  892         -
                    depth -= 1;
  893         -
                    if depth == 0 {
  894         -
                        return Ok(());
  895         -
                    }
  896         -
                }
  897         -
                Some(b'"') => {
  898         -
                    // Skip quoted string (handles escapes)
  899         -
                    let mut i = 1;
  900         -
                    let rem = self.remaining();
  901         -
                    while i < rem.len() {
  902         -
                        if rem[i] == b'\\' {
  903         -
                            i += 2; // skip escape sequence
  904         -
                        } else if rem[i] == b'"' {
  905         -
                            i += 1;
  906         -
                            break;
  907         -
                        } else {
  908         -
                            i += 1;
  909         -
                        }
  910         -
                    }
  911         -
                    self.advance_by(i);
  912         -
                    // After a string inside an object, skip optional ':'
  913         -
                    if depth > 0 {
  914         -
                        self.skip_whitespace();
  915         -
                        if self.remaining().first() == Some(&b':') {
  916         -
                            self.advance_by(1);
  917         -
                            continue; // read the value after the colon
  918         -
                        }
  919         -
                    }
  920         -
                    if depth == 0 {
  921         -
                        return Ok(());
  922         -
                    }
  923         -
                }
  924         -
                Some(b't') => {
  925         -
                    if !self.remaining().starts_with(b"true") {
  926         -
                        return Err(SerdeError::InvalidInput {
  927         -
                            message: "expected `true`".into(),
  928         -
                        });
  929         -
                    }
  930         -
                    self.advance_by(4);
  931         -
                    if depth == 0 {
  932         -
                        return Ok(());
        1014  +
        match self.remaining().first().copied() {
        1015  +
            Some(b'{') => {
        1016  +
                self.enter_container()?;
        1017  +
                self.advance_by(1);
        1018  +
                let mut first = true;
        1019  +
                loop {
        1020  +
                    if self.next_element(first, b'}', "object")? {
        1021  +
                        break;
  933   1022   
                    }
  934         -
                }
  935         -
                Some(b'f') => {
  936         -
                    if !self.remaining().starts_with(b"false") {
        1023  +
                    first = false;
        1024  +
                    if self.remaining().first() != Some(&b'"') {
  937   1025   
                        return Err(SerdeError::InvalidInput {
  938         -
                            message: "expected `false`".into(),
        1026  +
                            message: "expected object key".into(),
  939   1027   
                        });
  940   1028   
                    }
  941         -
                    self.advance_by(5);
  942         -
                    if depth == 0 {
  943         -
                        return Ok(());
  944         -
                    }
  945         -
                }
  946         -
                Some(b'n') => {
  947         -
                    if !self.remaining().starts_with(b"null") {
        1029  +
                    self.parse_key()?;
        1030  +
                    self.skip_whitespace();
        1031  +
                    if self.remaining().first() != Some(&b':') {
  948   1032   
                        return Err(SerdeError::InvalidInput {
  949         -
                            message: "expected `null`".into(),
        1033  +
                            message: "expected colon after key".into(),
  950   1034   
                        });
  951   1035   
                    }
  952         -
                    self.advance_by(4);
  953         -
                    if depth == 0 {
  954         -
                        return Ok(());
  955         -
                    }
        1036  +
                    self.advance_by(1);
        1037  +
                    self.skip_value()?;
  956   1038   
                }
  957         -
                Some(c) if c == b'-' || c.is_ascii_digit() => {
  958         -
                    self.consume_number();
  959         -
                    if depth == 0 {
  960         -
                        return Ok(());
        1039  +
                self.depth -= 1;
        1040  +
                Ok(())
        1041  +
            }
        1042  +
            Some(b'[') => {
        1043  +
                self.enter_container()?;
        1044  +
                self.advance_by(1);
        1045  +
                let mut first = true;
        1046  +
                loop {
        1047  +
                    if self.next_element(first, b']', "array")? {
        1048  +
                        break;
  961   1049   
                    }
        1050  +
                    first = false;
        1051  +
                    self.skip_value()?;
  962   1052   
                }
  963         -
                Some(_) => {
  964         -
                    return Err(SerdeError::InvalidInput {
  965         -
                        message: "unexpected token in skip_value".into(),
  966         -
                    })
  967         -
                }
  968         -
                None => {
  969         -
                    return Err(SerdeError::InvalidInput {
  970         -
                        message: "unexpected end of input".into(),
  971         -
                    })
  972         -
                }
        1053  +
                self.depth -= 1;
        1054  +
                Ok(())
  973   1055   
            }
        1056  +
            Some(b'"') => self.skip_string(),
        1057  +
            Some(b't') => self.skip_literal(b"true"),
        1058  +
            Some(b'f') => self.skip_literal(b"false"),
        1059  +
            Some(b'n') => self.skip_literal(b"null"),
        1060  +
            Some(c) if c == b'-' || c.is_ascii_digit() => self.skip_number(),
        1061  +
            Some(_) => Err(SerdeError::InvalidInput {
        1062  +
                message: "unexpected token in skip_value".into(),
        1063  +
            }),
        1064  +
            None => Err(SerdeError::InvalidInput {
        1065  +
                message: "unexpected end of input".into(),
        1066  +
            }),
  974   1067   
        }
  975   1068   
    }
  976   1069   
        1070  +
    fn skip_literal(&mut self, literal: &'static [u8]) -> Result<(), SerdeError> {
        1071  +
        if !self.remaining().starts_with(literal) {
        1072  +
            return Err(SerdeError::InvalidInput {
        1073  +
                message: format!("expected `{}`", String::from_utf8_lossy(literal)),
        1074  +
            });
        1075  +
        }
        1076  +
        self.advance_by(literal.len());
        1077  +
        Ok(())
        1078  +
    }
        1079  +
  977   1080   
    fn read_integer_value(&mut self) -> Result<i64, SerdeError> {
  978   1081   
        self.skip_whitespace();
  979   1082   
        let rem = self.remaining();
  980   1083   
        let mut len = 0;
  981   1084   
        for &b in rem {
  982   1085   
            if b.is_ascii_digit() || b == b'-' || b == b'+' {
  983   1086   
                len += 1;
  984   1087   
            } else {
  985   1088   
                break;
  986   1089   
            }
  987   1090   
        }
  988   1091   
        if len == 0 {
  989   1092   
            return Err(SerdeError::TypeMismatch {
  990   1093   
                message: "expected integer".into(),
  991   1094   
            });
  992   1095   
        }
  993   1096   
        let s = std::str::from_utf8(&rem[..len]).map_err(|e| SerdeError::InvalidInput {
  994   1097   
            message: e.to_string(),
  995   1098   
        })?;
  996   1099   
        let n = s.parse::<i64>().map_err(|e| SerdeError::InvalidInput {
  997   1100   
            message: e.to_string(),
  998   1101   
        })?;
  999   1102   
        self.advance_by(len);
 1000   1103   
        Ok(n)
 1001   1104   
    }
 1002   1105   
 1003   1106   
    fn read_float_value(&mut self) -> Result<f64, SerdeError> {
 1004   1107   
        self.skip_whitespace();
 1005   1108   
        let rem = self.remaining();
 1006         -
        // Handle string-encoded special float values: "NaN", "Infinity", "-Infinity"
        1109  +
        // A string may only carry a non-finite value, which JSON cannot express as a number:
        1110  +
        // `"NaN"`, `"Infinity"`, `"-Infinity"`. A quoted finite number such as `"123"` is a
        1111  +
        // type mismatch; the restJson1 protocol tests
        1112  +
        // `RestJsonBodyFloatMalformedValueRejected_case0` and
        1113  +
        // `RestJsonBodyDoubleMalformedValueRejected_case0` require it to be rejected. This
        1114  +
        // mirrors the token-based parser (`expect_number_or_null`), which parses the string
        1115  +
        // with `aws_smithy_types::primitive::Parse` and then rejects finite values, so the
        1116  +
        // spellings Rust's `f64::from_str` accepts for non-finite values (e.g. `"nan"`) are
        1117  +
        // accepted here too.
 1007   1118   
        if rem.first() == Some(&b'"') {
 1008   1119   
            let s = self.read_string(&aws_smithy_schema::prelude::STRING)?;
 1009         -
            return match s.as_str() {
 1010         -
                "NaN" => Ok(f64::NAN),
 1011         -
                "Infinity" => Ok(f64::INFINITY),
 1012         -
                "-Infinity" => Ok(f64::NEG_INFINITY),
 1013         -
                _ => s.parse::<f64>().map_err(|e| SerdeError::InvalidInput {
        1120  +
            let value = match s.as_str() {
        1121  +
                "NaN" => f64::NAN,
        1122  +
                "Infinity" => f64::INFINITY,
        1123  +
                "-Infinity" => f64::NEG_INFINITY,
        1124  +
                other => other.parse::<f64>().map_err(|e| SerdeError::InvalidInput {
 1014   1125   
                    message: e.to_string(),
 1015         -
                }),
        1126  +
                })?,
 1016   1127   
            };
        1128  +
            if value.is_finite() {
        1129  +
                return Err(SerdeError::TypeMismatch {
        1130  +
                    message: format!(
        1131  +
                        "only `Infinity`, `-Infinity`, `NaN` can represent a float as a string but found `{s}`"
        1132  +
                    ),
        1133  +
                });
        1134  +
            }
        1135  +
            return Ok(value);
 1017   1136   
        }
 1018   1137   
        let mut len = 0;
 1019   1138   
        for &b in rem {
 1020   1139   
            if b.is_ascii_digit() || b == b'-' || b == b'+' || b == b'.' || b == b'e' || b == b'E' {
 1021   1140   
                len += 1;
 1022   1141   
            } else {
 1023   1142   
                break;
 1024   1143   
            }
 1025   1144   
        }
 1026   1145   
        if len == 0 {
@@ -2144,2263 +2174,2833 @@
 2164   2283   
        assert_depth_error(err);
 2165   2284   
 2166   2285   
        // 10 levels fits inside the custom limit.
 2167   2286   
        let settings_ok = JsonCodecSettings::builder().max_depth(16).build();
 2168   2287   
        let payload_ok = build_nested("[", "]", 10);
 2169   2288   
        let mut deser_ok = JsonDeserializer::new(&payload_ok, Arc::new(settings_ok));
 2170   2289   
        deser_ok
 2171   2290   
            .read_list(dummy_schema(), &mut recursive_list_consumer)
 2172   2291   
            .expect("10-level nesting should succeed under custom limit");
 2173   2292   
    }
        2293  +
        2294  +
    mod separators {
        2295  +
        //! JSON syntax the deserializer must reject: separators (exactly one `,` between
        2296  +
        //! elements, none before a closing delimiter), bytes after the top-level value, and
        2297  +
        //! malformed values inside skipped unknown members. Smithy protocol tests
        2298  +
        //! `RestJsonInvalidJsonBody_case7` (`{"int": 10,}`) and `RestJsonInvalidJsonBody_case1`
        2299  +
        //! (`{ "int": 10 }abc`) require the first two.
        2300  +
        use super::*;
        2301  +
        use aws_smithy_schema::{shape_id, ShapeType};
        2302  +
        2303  +
        static INT: Schema = Schema::new_member(
        2304  +
            shape_id!("test", "Input", "int"),
        2305  +
            ShapeType::Integer,
        2306  +
            "int",
        2307  +
            0,
        2308  +
        );
        2309  +
        static LIST: Schema = Schema::new_member(
        2310  +
            shape_id!("test", "Input", "list"),
        2311  +
            ShapeType::List,
        2312  +
            "list",
        2313  +
            1,
        2314  +
        );
        2315  +
        static INPUT: Schema = Schema::new_struct(
        2316  +
            shape_id!("test", "Input"),
        2317  +
            ShapeType::Structure,
        2318  +
            &[&INT, &LIST],
        2319  +
        );
        2320  +
        2321  +
        fn deser(input: &[u8]) -> JsonDeserializer<'_> {
        2322  +
            JsonDeserializer::new(input, Arc::new(JsonCodecSettings::default()))
        2323  +
        }
        2324  +
        2325  +
        /// Reads `INPUT` and returns `(int, list)`; unknown members are skipped.
        2326  +
        fn read_input(body: &[u8]) -> Result<(Option<i32>, Vec<i32>), SerdeError> {
        2327  +
            let mut d = deser(body);
        2328  +
            let mut int = None;
        2329  +
            let mut list = Vec::new();
        2330  +
            d.read_struct(&INPUT, &mut |member, d| {
        2331  +
                match member.member_index() {
        2332  +
                    Some(0) => int = Some(d.read_integer(member)?),
        2333  +
                    Some(1) => d.read_list(member, &mut |d| {
        2334  +
                        list.push(d.read_integer(member)?);
        2335  +
                        Ok(())
        2336  +
                    })?,
        2337  +
                    _ => {}
        2338  +
                }
        2339  +
                Ok(())
        2340  +
            })?;
        2341  +
            Ok((int, list))
        2342  +
        }
        2343  +
        2344  +
        #[test]
        2345  +
        fn well_formed_input_is_read() {
        2346  +
            assert_eq!(
        2347  +
                read_input(br#"{ "int": 10 , "list": [ 1 , 2 ] }"#).unwrap(),
        2348  +
                (Some(10), vec![1, 2])
        2349  +
            );
        2350  +
            assert_eq!(read_input(br#"{}"#).unwrap(), (None, vec![]));
        2351  +
            assert_eq!(read_input(br#"{"list":[]}"#).unwrap(), (None, vec![]));
        2352  +
            assert_eq!(
        2353  +
                read_input(b"  { \"int\": 1 }  \n").unwrap(),
        2354  +
                (Some(1), vec![])
        2355  +
            );
        2356  +
        }
        2357  +
        2358  +
        #[test]
        2359  +
        fn trailing_comma_in_object_is_rejected() {
        2360  +
            assert!(read_input(br#"{"int": 10,}"#).is_err());
        2361  +
        }
        2362  +
        2363  +
        #[test]
        2364  +
        fn leading_and_repeated_commas_in_object_are_rejected() {
        2365  +
            assert!(read_input(br#"{,"int": 10}"#).is_err());
        2366  +
            assert!(read_input(br#"{"int": 10,,"list": []}"#).is_err());
        2367  +
            assert!(read_input(br#"{"int": 10,,}"#).is_err());
        2368  +
        }
        2369  +
        2370  +
        #[test]
        2371  +
        fn missing_comma_in_object_is_rejected() {
        2372  +
            assert!(read_input(br#"{"int": 10 "list": []}"#).is_err());
        2373  +
        }
        2374  +
        2375  +
        #[test]
        2376  +
        fn commas_in_array_are_checked() {
        2377  +
            assert!(read_input(br#"{"list": [1,]}"#).is_err());
        2378  +
            assert!(read_input(br#"{"list": [,1]}"#).is_err());
        2379  +
            assert!(read_input(br#"{"list": [1,,2]}"#).is_err());
        2380  +
            assert!(read_input(br#"{"list": [1 2]}"#).is_err());
        2381  +
        }
        2382  +
        2383  +
        #[test]
        2384  +
        fn skipped_unknown_members_are_still_validated() {
        2385  +
            assert_eq!(
        2386  +
                read_input(br#"{"unknown": {"a": [1, {"b": null}], "c": "x"}, "int": 1}"#).unwrap(),
        2387  +
                (Some(1), vec![])
        2388  +
            );
        2389  +
            assert!(read_input(br#"{"unknown": [1,,2], "int": 1}"#).is_err());
        2390  +
            assert!(read_input(br#"{"unknown": {"a": 1,}, "int": 1}"#).is_err());
        2391  +
            assert!(read_input(br#"{"unknown": "unterminated, "int": 1}"#).is_err());
        2392  +
            assert!(read_input(br#"{"unknown": tru, "int": 1}"#).is_err());
        2393  +
        }
        2394  +
        2395  +
        #[test]
        2396  +
        fn trailing_characters_after_the_top_level_value_are_rejected() {
        2397  +
            assert!(read_input(br#"{ "int": 10 }abc"#).is_err());
        2398  +
            assert!(read_input(br#"{ "int": 10 },"#).is_err());
        2399  +
            assert!(read_input(br#"{ "int": 10 }{}"#).is_err());
        2400  +
            assert!(deser(br#"[1]x"#).read_integer_list(&LIST).is_err());
        2401  +
            assert!(deser(br#"{"k":"v"} {}"#)
        2402  +
                .read_string_string_map(&LIST)
        2403  +
                .is_err());
        2404  +
            assert!(deser(br#"{"a":1}]"#).read_document(&INT).is_err());
        2405  +
            assert!(deser(br#"[1,2]"#).read_document(&INT).is_ok());
        2406  +
        }
        2407  +
        2408  +
        #[test]
        2409  +
        fn skipped_numbers_must_match_the_json_grammar() {
        2410  +
            for ok in [
        2411  +
                b"0" as &[u8],
        2412  +
                b"-0",
        2413  +
                b"10",
        2414  +
                b"-1.5",
        2415  +
                b"1e3",
        2416  +
                b"1E+3",
        2417  +
                b"2.5e-7",
        2418  +
            ] {
        2419  +
                let body = [b"{\"unknown\": " as &[u8], ok, b", \"int\": 1}"].concat();
        2420  +
                assert_eq!(
        2421  +
                    read_input(&body).unwrap(),
        2422  +
                    (Some(1), vec![]),
        2423  +
                    "{}",
        2424  +
                    String::from_utf8_lossy(ok)
        2425  +
                );
        2426  +
            }
        2427  +
            for bad in [
        2428  +
                b"01" as &[u8],
        2429  +
                b"1.",
        2430  +
                b"--1",
        2431  +
                b"+1",
        2432  +
                b".5",
        2433  +
                b"1e",
        2434  +
                b"1e+",
        2435  +
                b"-",
        2436  +
                b"0x1",
        2437  +
            ] {
        2438  +
                let body = [b"{\"unknown\": " as &[u8], bad, b", \"int\": 1}"].concat();
        2439  +
                assert!(
        2440  +
                    read_input(&body).is_err(),
        2441  +
                    "{}",
        2442  +
                    String::from_utf8_lossy(bad)
        2443  +
                );
        2444  +
            }
        2445  +
        }
        2446  +
        2447  +
        #[test]
        2448  +
        fn skipped_strings_must_use_valid_escapes() {
        2449  +
            assert_eq!(
        2450  +
                read_input(br#"{"unknown": "a\"b\\c\/\b\f\n\r\t\u00e9", "int": 1}"#).unwrap(),
        2451  +
                (Some(1), vec![])
        2452  +
            );
        2453  +
            assert!(read_input(br#"{"unknown": "\q", "int": 1}"#).is_err());
        2454  +
            assert!(read_input(br#"{"unknown": "\u12", "int": 1}"#).is_err());
        2455  +
            assert!(read_input(br#"{"unknown": "\uZZZZ", "int": 1}"#).is_err());
        2456  +
            assert!(read_input(br#"{"unknown": "abc\", "int": 1}"#).is_err());
        2457  +
        }
        2458  +
        2459  +
        #[test]
        2460  +
        fn fast_path_collections_check_separators() {
        2461  +
            assert_eq!(
        2462  +
                deser(br#"["a","b"]"#).read_string_list(&LIST).unwrap(),
        2463  +
                vec!["a", "b"]
        2464  +
            );
        2465  +
            assert!(deser(br#"["a",]"#).read_string_list(&LIST).is_err());
        2466  +
            assert!(deser(br#"[,"a"]"#).read_string_list(&LIST).is_err());
        2467  +
            assert!(deser(br#"[1,,2]"#).read_integer_list(&LIST).is_err());
        2468  +
            assert!(deser(br#"[1,]"#).read_long_list(&LIST).is_err());
        2469  +
            assert!(deser(br#"["YQ==",]"#).read_blob_list(&LIST).is_err());
        2470  +
            assert_eq!(
        2471  +
                deser(br#"{"k":"v"}"#)
        2472  +
                    .read_string_string_map(&LIST)
        2473  +
                    .unwrap()
        2474  +
                    .len(),
        2475  +
                1
        2476  +
            );
        2477  +
            assert!(deser(br#"{"k":"v",}"#)
        2478  +
                .read_string_string_map(&LIST)
        2479  +
                .is_err());
        2480  +
            assert!(deser(br#"{"k":"v" "j":"w"}"#)
        2481  +
                .read_string_string_map(&LIST)
        2482  +
                .is_err());
        2483  +
        }
        2484  +
        2485  +
        #[test]
        2486  +
        fn generic_map_checks_separators() {
        2487  +
            let mut count = 0;
        2488  +
            assert!(deser(br#"{"a":1,"b":2}"#)
        2489  +
                .read_map(&LIST, &mut |_, d| {
        2490  +
                    count += 1;
        2491  +
                    d.read_integer(&INT).map(|_| ())
        2492  +
                })
        2493  +
                .is_ok());
        2494  +
            assert_eq!(count, 2);
        2495  +
            assert!(deser(br#"{"a":1,}"#)
        2496  +
                .read_map(&LIST, &mut |_, d| d.read_integer(&INT).map(|_| ()))
        2497  +
                .is_err());
        2498  +
        }
        2499  +
        2500  +
        #[test]
        2501  +
        fn documents_check_separators() {
        2502  +
            assert!(deser(br#"{"a":[1,2],"b":{"c":true}}"#)
        2503  +
                .read_document(&INT)
        2504  +
                .is_ok());
        2505  +
            assert!(deser(br#"{"a":1,}"#).read_document(&INT).is_err());
        2506  +
            assert!(deser(br#"[1,,2]"#).read_document(&INT).is_err());
        2507  +
            assert!(deser(br#"{,"a":1}"#).read_document(&INT).is_err());
        2508  +
        }
        2509  +
    }
        2510  +
        2511  +
    mod float_strings {
        2512  +
        //! A float or double member may carry a string only for a non-finite value
        2513  +
        //! (`"NaN"`, `"Infinity"`, `"-Infinity"`). Smithy protocol tests
        2514  +
        //! `RestJsonBodyFloatMalformedValueRejected_case0` and
        2515  +
        //! `RestJsonBodyDoubleMalformedValueRejected_case0` (`"123"`) require quoted finite
        2516  +
        //! numbers to be rejected.
        2517  +
        use super::*;
        2518  +
        use aws_smithy_schema::{shape_id, ShapeType};
        2519  +
        2520  +
        static F: Schema =
        2521  +
            Schema::new_member(shape_id!("test", "Input", "f"), ShapeType::Float, "f", 0);
        2522  +
        static D: Schema =
        2523  +
            Schema::new_member(shape_id!("test", "Input", "d"), ShapeType::Double, "d", 1);
        2524  +
        static INPUT: Schema =
        2525  +
            Schema::new_struct(shape_id!("test", "Input"), ShapeType::Structure, &[&F, &D]);
        2526  +
        2527  +
        fn read(body: &[u8]) -> Result<(Option<f32>, Option<f64>), SerdeError> {
        2528  +
            let mut deser = JsonDeserializer::new(body, Arc::new(JsonCodecSettings::default()));
        2529  +
            let (mut f, mut d) = (None, None);
        2530  +
            deser.read_struct(&INPUT, &mut |m, x| {
        2531  +
                match m.member_index() {
        2532  +
                    Some(0) => f = Some(x.read_float(m)?),
        2533  +
                    Some(1) => d = Some(x.read_double(m)?),
        2534  +
                    _ => {}
        2535  +
                }
        2536  +
                Ok(())
        2537  +
            })?;
        2538  +
            Ok((f, d))
        2539  +
        }
        2540  +
        2541  +
        #[test]
        2542  +
        fn numbers_and_the_three_special_strings_are_read() {
        2543  +
            assert_eq!(
        2544  +
                read(br#"{"f": 1.5, "d": -2}"#).unwrap(),
        2545  +
                (Some(1.5), Some(-2.0))
        2546  +
            );
        2547  +
            let (f, d) = read(br#"{"f": "NaN", "d": "-Infinity"}"#).unwrap();
        2548  +
            assert!(f.unwrap().is_nan());
        2549  +
            assert_eq!(d, Some(f64::NEG_INFINITY));
        2550  +
            assert_eq!(
        2551  +
                read(br#"{"f": "Infinity"}"#).unwrap().0,
        2552  +
                Some(f32::INFINITY)
        2553  +
            );
        2554  +
        }
        2555  +
        2556  +
        #[test]
        2557  +
        fn quoted_finite_numbers_are_rejected() {
        2558  +
            assert!(read(br#"{"f": "123"}"#).is_err());
        2559  +
            assert!(read(br#"{"d": "123"}"#).is_err());
        2560  +
            assert!(read(br#"{"d": "1.5e3"}"#).is_err());
        2561  +
            assert!(read(br#"{"d": "-0"}"#).is_err());
        2562  +
        }
        2563  +
        2564  +
        #[test]
        2565  +
        fn non_numeric_strings_are_rejected() {
        2566  +
            assert!(read(br#"{"d": "abc"}"#).is_err());
        2567  +
            assert!(read(br#"{"d": ""}"#).is_err());
        2568  +
            assert!(read(br#"{"d": "1 2"}"#).is_err());
        2569  +
        }
        2570  +
        2571  +
        #[test]
        2572  +
        fn alternative_non_finite_spellings_match_the_legacy_parser() {
        2573  +
            // `aws_smithy_types::primitive::Parse` falls back to `f64::from_str`, which
        2574  +
            // accepts these case-insensitively; only finite results are rejected.
        2575  +
            assert!(read(br#"{"f": "nan"}"#).unwrap().0.unwrap().is_nan());
        2576  +
            assert_eq!(read(br#"{"d": "inf"}"#).unwrap().1, Some(f64::INFINITY));
        2577  +
            assert_eq!(
        2578  +
                read(br#"{"d": "-infinity"}"#).unwrap().1,
        2579  +
                Some(f64::NEG_INFINITY)
        2580  +
            );
        2581  +
        }
        2582  +
    }
        2583  +
        2584  +
    mod timestamp_formats {
        2585  +
        //! With `strict_timestamp_formats`, a timestamp must use exactly the wire form its
        2586  +
        //! format prescribes, as the restJson1 `MalformedTimestampBody*` protocol tests require.
        2587  +
        //! Without it the lenient client behavior is unchanged.
        2588  +
        use super::*;
        2589  +
        use aws_smithy_schema::traits::TimestampFormat;
        2590  +
        use aws_smithy_schema::{shape_id, ShapeType};
        2591  +
        2592  +
        static DEFAULT: Schema =
        2593  +
            Schema::new_member(shape_id!("test", "T", "d"), ShapeType::Timestamp, "d", 0);
        2594  +
        static DATE_TIME: Schema =
        2595  +
            Schema::new_member(shape_id!("test", "T", "dt"), ShapeType::Timestamp, "dt", 1)
        2596  +
                .with_timestamp_format(TimestampFormat::DateTime);
        2597  +
        static HTTP_DATE: Schema =
        2598  +
            Schema::new_member(shape_id!("test", "T", "hd"), ShapeType::Timestamp, "hd", 2)
        2599  +
                .with_timestamp_format(TimestampFormat::HttpDate);
        2600  +
        static EPOCH: Schema =
        2601  +
            Schema::new_member(shape_id!("test", "T", "es"), ShapeType::Timestamp, "es", 3)
        2602  +
                .with_timestamp_format(TimestampFormat::EpochSeconds);
        2603  +
        2604  +
        /// 2018-01-09T20:51:21Z
        2605  +
        const T: i64 = 1515531081;
        2606  +
        2607  +
        fn read(strict: bool, schema: &Schema, input: &[u8]) -> Result<DateTime, SerdeError> {
        2608  +
            let settings = JsonCodecSettings::builder()
        2609  +
                .strict_timestamp_formats(strict)
        2610  +
                .build();
        2611  +
            JsonDeserializer::new(input, Arc::new(settings)).read_timestamp(schema)
        2612  +
        }
        2613  +
        2614  +
        fn assert_rejected(schema: &Schema, inputs: &[&[u8]]) {
        2615  +
            for input in inputs {
        2616  +
                assert!(
        2617  +
                    read(true, schema, input).is_err(),
        2618  +
                    "{} must be rejected",
        2619  +
                    String::from_utf8_lossy(input)
        2620  +
                );
        2621  +
            }
        2622  +
        }
        2623  +
        2624  +
        #[test]
        2625  +
        fn strict_epoch_seconds_default_requires_a_number() {
        2626  +
            assert_eq!(
        2627  +
                read(true, &DEFAULT, b"1515531081").unwrap(),
        2628  +
                DateTime::from_secs(T)
        2629  +
            );
        2630  +
            assert_eq!(
        2631  +
                read(true, &DEFAULT, b"1515531081.1234").unwrap(),
        2632  +
                DateTime::from_secs_f64(1515531081.1234)
        2633  +
            );
        2634  +
            assert_rejected(
        2635  +
                &DEFAULT,
        2636  +
                &[
        2637  +
                    br#""1985-04-12T23:20:50.52Z""#,
        2638  +
                    br#""1985-04-12T23:20:50Z""#,
        2639  +
                    br#""1996-12-19T16:39:57-08:00""#,
        2640  +
                    br#""1515531081""#,
        2641  +
                    br#""1515531081.1234""#,
        2642  +
                    br#""Tue, 29 Apr 2014 18:30:38 GMT""#,
        2643  +
                    br#""Infinity""#,
        2644  +
                    br#""NaN""#,
        2645  +
                    b"true",
        2646  +
                ],
        2647  +
            );
        2648  +
        }
        2649  +
        2650  +
        #[test]
        2651  +
        fn strict_explicit_epoch_seconds_requires_a_number() {
        2652  +
            assert_eq!(
        2653  +
                read(true, &EPOCH, b"1515531081").unwrap(),
        2654  +
                DateTime::from_secs(T)
        2655  +
            );
        2656  +
            assert_rejected(&EPOCH, &[br#""2018-01-09T20:51:21Z""#, br#""1515531081""#]);
        2657  +
        }
        2658  +
        2659  +
        #[test]
        2660  +
        fn strict_date_time_requires_an_rfc3339_utc_string() {
        2661  +
            assert_eq!(
        2662  +
                read(true, &DATE_TIME, br#""2018-01-09T20:51:21Z""#).unwrap(),
        2663  +
                DateTime::from_secs(T)
        2664  +
            );
        2665  +
            assert_rejected(
        2666  +
                &DATE_TIME,
        2667  +
                &[
        2668  +
                    b"1515531081",
        2669  +
                    b"1515531081.1234",
        2670  +
                    br#""1996-12-19T16:39:57-08:00""#,
        2671  +
                    br#""1996-12-19T16:39:57+00""#,
        2672  +
                    br#""1996-12-19T16:39:57""#,
        2673  +
                    br#""Tue, 29 Apr 2014 18:30:38 GMT""#,
        2674  +
                ],
        2675  +
            );
        2676  +
        }
        2677  +
        2678  +
        #[test]
        2679  +
        fn strict_http_date_requires_an_imf_fixdate_string() {
        2680  +
            assert_eq!(
        2681  +
                read(true, &HTTP_DATE, br#""Tue, 09 Jan 2018 20:51:21 GMT""#).unwrap(),
        2682  +
                DateTime::from_secs(T)
        2683  +
            );
        2684  +
            assert_rejected(
        2685  +
                &HTTP_DATE,
        2686  +
                &[
        2687  +
                    b"1515531081",
        2688  +
                    b"1515531081.1234",
        2689  +
                    br#""1985-04-12T23:20:50.52Z""#,
        2690  +
                    br#""1996-12-19T16:39:57-08:00""#,
        2691  +
                ],
        2692  +
            );
        2693  +
        }
        2694  +
        2695  +
        #[test]
        2696  +
        fn lenient_default_keeps_the_client_behavior() {
        2697  +
            // A number is epoch seconds whatever the format; a string for a `date-time`
        2698  +
            // member or a member without the trait parses as offset-aware `date-time`;
        2699  +
            // explicit `http-date` and `epoch-seconds` traits are honored for strings.
        2700  +
            assert_eq!(
        2701  +
                read(false, &DATE_TIME, b"1515531081").unwrap(),
        2702  +
                DateTime::from_secs(T)
        2703  +
            );
        2704  +
            assert_eq!(
        2705  +
                read(false, &HTTP_DATE, b"1515531081").unwrap(),
        2706  +
                DateTime::from_secs(T)
        2707  +
            );
        2708  +
            assert_eq!(
        2709  +
                read(false, &DEFAULT, br#""2018-01-09T20:51:21Z""#).unwrap(),
        2710  +
                DateTime::from_secs(T)
        2711  +
            );
        2712  +
            assert_eq!(
        2713  +
                read(false, &DATE_TIME, br#""2018-01-09T21:51:21+01:00""#).unwrap(),
        2714  +
                DateTime::from_secs(T)
        2715  +
            );
        2716  +
            assert_eq!(
        2717  +
                read(false, &HTTP_DATE, br#""Tue, 09 Jan 2018 20:51:21 GMT""#).unwrap(),
        2718  +
                DateTime::from_secs(T)
        2719  +
            );
        2720  +
            assert_eq!(
        2721  +
                read(false, &EPOCH, br#""1515531081""#).unwrap(),
        2722  +
                DateTime::from_secs(T)
        2723  +
            );
        2724  +
        }
        2725  +
    }
        2726  +
        2727  +
    mod union_members {
        2728  +
        //! A union body holds exactly one member. Mixed variants are always an error; an
        2729  +
        //! unknown key is an error only with `reject_unknown_union_members`, which servers
        2730  +
        //! enable for the restJson1 `RestJsonMalformedUnion*` protocol tests.
        2731  +
        use super::*;
        2732  +
        use aws_smithy_schema::shape_id;
        2733  +
        2734  +
        static INT: Schema =
        2735  +
            Schema::new_member(shape_id!("test", "U", "int"), ShapeType::Integer, "int", 0);
        2736  +
        static STRING: Schema = Schema::new_member(
        2737  +
            shape_id!("test", "U", "string"),
        2738  +
            ShapeType::String,
        2739  +
            "string",
        2740  +
            1,
        2741  +
        );
        2742  +
        static UNION: Schema =
        2743  +
            Schema::new_struct(shape_id!("test", "U"), ShapeType::Union, &[&INT, &STRING]);
        2744  +
        static FIELD: Schema = Schema::new_member(
        2745  +
            shape_id!("test", "S", "field"),
        2746  +
            ShapeType::Integer,
        2747  +
            "field",
        2748  +
            0,
        2749  +
        );
        2750  +
        static STRUCT: Schema =
        2751  +
            Schema::new_struct(shape_id!("test", "S"), ShapeType::Structure, &[&FIELD]);
        2752  +
        2753  +
        #[derive(Debug, PartialEq)]
        2754  +
        enum Variant {
        2755  +
            Int(i32),
        2756  +
            String(String),
        2757  +
        }
        2758  +
        2759  +
        fn read(strict: bool, body: &[u8]) -> Result<Option<Variant>, SerdeError> {
        2760  +
            let settings = JsonCodecSettings::builder()
        2761  +
                .reject_unknown_union_members(strict)
        2762  +
                .build();
        2763  +
            let mut deser = JsonDeserializer::new(body, Arc::new(settings));
        2764  +
            let mut value = None;
        2765  +
            deser.read_struct(&UNION, &mut |member, d| {
        2766  +
                value = Some(match member.member_index() {
        2767  +
                    Some(0) => Variant::Int(d.read_integer(member)?),
        2768  +
                    _ => Variant::String(d.read_string(member)?),
        2769  +
                });
        2770  +
                Ok(())
        2771  +
            })?;
        2772  +
            Ok(value)
        2773  +
        }
        2774  +
        2775  +
        #[test]
        2776  +
        fn a_single_member_is_read() {
        2777  +
            for strict in [false, true] {
        2778  +
                assert_eq!(
        2779  +
                    read(strict, br#"{"int": 2}"#).unwrap(),
        2780  +
                    Some(Variant::Int(2))
        2781  +
                );
        2782  +
                assert_eq!(
        2783  +
                    read(strict, br#"{"int": null, "string": "x"}"#).unwrap(),
        2784  +
                    Some(Variant::String("x".into()))
        2785  +
                );
        2786  +
                assert_eq!(
        2787  +
                    read(strict, br#"{"__type": "test#U", "int": 2}"#).unwrap(),
        2788  +
                    Some(Variant::Int(2))
        2789  +
                );
        2790  +
                assert_eq!(read(strict, br#"{}"#).unwrap(), None);
        2791  +
                assert_eq!(read(strict, br#"{"int": null}"#).unwrap(), None);
        2792  +
            }
        2793  +
        }
        2794  +
        2795  +
        /// RestJsonMalformedUnionMultipleFieldsSet
        2796  +
        #[test]
        2797  +
        fn mixed_variants_are_rejected() {
        2798  +
            for strict in [false, true] {
        2799  +
                assert!(read(strict, br#"{"int": 2, "string": "three"}"#).is_err());
        2800  +
                assert!(read(strict, br#"{"int": 2, "int": 3}"#).is_err());
        2801  +
            }
        2802  +
        }
        2803  +
        2804  +
        /// RestJsonMalformedUnionKnownAndUnknownFieldsSet, RestJsonMalformedUnionUnknownMember
        2805  +
        #[test]
        2806  +
        fn unknown_members_are_rejected_only_when_configured() {
        2807  +
            assert_eq!(
        2808  +
                read(false, br#"{"int": 2, "unknownField": "three"}"#).unwrap(),
        2809  +
                Some(Variant::Int(2))
        2810  +
            );
        2811  +
            assert_eq!(read(false, br#"{"unknown": "hello"}"#).unwrap(), None);
        2812  +
            assert!(read(true, br#"{"int": 2, "unknownField": "three"}"#).is_err());
        2813  +
            assert!(read(true, br#"{"unknown": "hello"}"#).is_err());
        2814  +
        }
        2815  +
        2816  +
        #[test]
        2817  +
        fn structures_still_skip_unknown_members_when_configured() {
        2818  +
            let settings = JsonCodecSettings::builder()
        2819  +
                .reject_unknown_union_members(true)
        2820  +
                .build();
        2821  +
            let mut deser =
        2822  +
                JsonDeserializer::new(br#"{"unknown": {"a": 1}, "field": 5}"#, Arc::new(settings));
        2823  +
            let mut field = None;
        2824  +
            deser
        2825  +
                .read_struct(&STRUCT, &mut |member, d| {
        2826  +
                    field = Some(d.read_integer(member)?);
        2827  +
                    Ok(())
        2828  +
                })
        2829  +
                .unwrap();
        2830  +
            assert_eq!(field, Some(5));
        2831  +
        }
        2832  +
    }
 2174   2833   
}