AWS SDK

AWS SDK

rev. e063993ca0ab793f44c575dbe707d50a5e3e2406 (ignoring whitespace)

Files changed:

tmp-codegen-diff/aws-sdk/sdk/aws-config/Cargo.toml

@@ -19,19 +106,110 @@
   39     39   
url = "2.5.4"
   40     40   
fastrand = "2.3.0"
   41     41   
   42     42   
[dependencies.aws-credential-types]
   43     43   
path = "../aws-credential-types"
   44     44   
features = ["test-util"]
   45     45   
version = "1.2.14"
   46     46   
   47     47   
[dependencies.aws-runtime]
   48     48   
path = "../aws-runtime"
   49         -
version = "1.7.3"
          49  +
version = "1.7.4"
   50     50   
   51     51   
[dependencies.aws-sdk-sts]
   52     52   
path = "../sts"
   53     53   
default-features = false
   54     54   
version = "0.0.0-local"
   55     55   
   56     56   
[dependencies.aws-smithy-async]
   57     57   
path = "../aws-smithy-async"
   58     58   
version = "1.2.14"
   59     59   
   60     60   
[dependencies.aws-smithy-http]
   61     61   
path = "../aws-smithy-http"
   62     62   
version = "0.63.6"
   63     63   
   64     64   
[dependencies.aws-smithy-json]
   65     65   
path = "../aws-smithy-json"
   66     66   
version = "0.62.6"
   67     67   
   68     68   
[dependencies.aws-smithy-runtime]
   69     69   
path = "../aws-smithy-runtime"
   70     70   
features = ["client"]
   71         -
version = "1.10.3"
          71  +
version = "1.10.4"
   72     72   
   73     73   
[dependencies.aws-smithy-runtime-api]
   74     74   
path = "../aws-smithy-runtime-api"
   75     75   
features = ["client"]
   76         -
version = "1.11.6"
          76  +
version = "1.11.7"
          77  +
          78  +
[dependencies.aws-smithy-schema]
          79  +
path = "../aws-smithy-schema"
          80  +
version = "1.0.0"
   77     81   
   78     82   
[dependencies.aws-smithy-types]
   79     83   
path = "../aws-smithy-types"
   80     84   
version = "1.4.7"
   81     85   
   82     86   
[dependencies.aws-types]
   83     87   
path = "../aws-types"
   84     88   
version = "1.4.0"
   85     89   
   86     90   
[dependencies.time]
@@ -136,140 +187,191 @@
  156    160   
version = "1.2.14"
  157    161   
  158    162   
[dev-dependencies.aws-smithy-http-client]
  159    163   
path = "../aws-smithy-http-client"
  160    164   
features = ["default-client", "test-util"]
  161    165   
version = "1.1.12"
  162    166   
  163    167   
[dev-dependencies.aws-smithy-runtime]
  164    168   
path = "../aws-smithy-runtime"
  165    169   
features = ["client", "test-util"]
  166         -
version = "1.10.3"
         170  +
version = "1.10.4"
  167    171   
  168    172   
[dev-dependencies.aws-smithy-runtime-api]
  169    173   
path = "../aws-smithy-runtime-api"
  170    174   
features = ["test-util"]
  171         -
version = "1.11.6"
         175  +
version = "1.11.7"
  172    176   
  173    177   
[dev-dependencies.futures-util]
  174    178   
version = "0.3.29"
  175    179   
default-features = false
  176    180   
  177    181   
[dev-dependencies.tracing-subscriber]
  178    182   
version = "0.3.16"
  179    183   
features = ["fmt", "json"]
  180    184   
  181    185   
[dev-dependencies.tokio]

tmp-codegen-diff/aws-sdk/sdk/aws-config/external-types.toml

@@ -2,2 +39,40 @@
   22     22   
   "aws_smithy_runtime_api::box_error::BoxError",
   23     23   
   "aws_smithy_runtime_api::client::behavior_version::BehaviorVersion",
   24     24   
   "aws_smithy_runtime_api::client::dns::ResolveDns",
   25     25   
   "aws_smithy_runtime_api::client::http::HttpClient",
   26     26   
   "aws_smithy_runtime_api::client::identity::ResolveCachedIdentity",
   27     27   
   "aws_smithy_runtime_api::client::identity::ResolveIdentity",
   28     28   
   "aws_smithy_runtime_api::client::orchestrator::HttpResponse",
   29     29   
   "aws_smithy_runtime_api::client::retries::classifiers::ClassifyRetry",
   30     30   
   "aws_smithy_runtime_api::client::retries::classifiers::SharedRetryClassifier",
   31     31   
   "aws_smithy_runtime_api::client::stalled_stream_protection::StalledStreamProtectionConfig",
          32  +
   "aws_smithy_schema::schema::protocol::ClientProtocol",
   32     33   
   "aws_smithy_types::checksum_config::RequestChecksumCalculation",
   33     34   
   "aws_smithy_types::checksum_config::ResponseChecksumValidation",
   34     35   
   "aws_smithy_types::retry::*",
   35     36   
   "aws_smithy_types::timeout::OperationTimeoutConfig",
   36     37   
   "aws_smithy_types::timeout::TimeoutConfig",
   37     38   
   "aws_smithy_types::timeout::TimeoutConfigBuilder",
   38     39   
   "aws_types::*",
   39     40   
]

tmp-codegen-diff/aws-sdk/sdk/aws-config/src/lib.rs

@@ -204,204 +263,264 @@
  224    224   
    use aws_credential_types::Credentials;
  225    225   
    use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep, SharedAsyncSleep};
  226    226   
    use aws_smithy_async::time::{SharedTimeSource, TimeSource};
  227    227   
    use aws_smithy_runtime::client::identity::IdentityCache;
  228    228   
    use aws_smithy_runtime_api::client::auth::AuthSchemePreference;
  229    229   
    use aws_smithy_runtime_api::client::behavior_version::BehaviorVersion;
  230    230   
    use aws_smithy_runtime_api::client::http::HttpClient;
  231    231   
    use aws_smithy_runtime_api::client::identity::{ResolveCachedIdentity, SharedIdentityCache};
  232    232   
    use aws_smithy_runtime_api::client::stalled_stream_protection::StalledStreamProtectionConfig;
  233    233   
    use aws_smithy_runtime_api::shared::IntoShared;
         234  +
    use aws_smithy_schema::protocol::{ClientProtocol, SharedClientProtocol};
  234    235   
    use aws_smithy_types::checksum_config::{
  235    236   
        RequestChecksumCalculation, ResponseChecksumValidation,
  236    237   
    };
  237    238   
    use aws_smithy_types::retry::RetryConfig;
  238    239   
    use aws_smithy_types::timeout::TimeoutConfig;
  239    240   
    use aws_types::app_name::AppName;
  240    241   
    use aws_types::docs_for;
  241    242   
    use aws_types::endpoint_config::AccountIdEndpointMode;
  242    243   
    use aws_types::origin::Origin;
  243    244   
    use aws_types::os_shim_internal::{Env, Fs};
@@ -276,277 +335,337 @@
  296    297   
        use_dual_stack: Option<bool>,
  297    298   
        time_source: Option<SharedTimeSource>,
  298    299   
        disable_request_compression: Option<bool>,
  299    300   
        request_min_compression_size_bytes: Option<u32>,
  300    301   
        stalled_stream_protection_config: Option<StalledStreamProtectionConfig>,
  301    302   
        env: Option<Env>,
  302    303   
        fs: Option<Fs>,
  303    304   
        behavior_version: Option<BehaviorVersion>,
  304    305   
        request_checksum_calculation: Option<RequestChecksumCalculation>,
  305    306   
        response_checksum_validation: Option<ResponseChecksumValidation>,
         307  +
        protocol: Option<SharedClientProtocol>,
  306    308   
    }
  307    309   
  308    310   
    impl ConfigLoader {
  309    311   
        /// Sets the [`BehaviorVersion`] used to build [`SdkConfig`].
  310    312   
        pub fn behavior_version(mut self, behavior_version: BehaviorVersion) -> Self {
  311    313   
            self.behavior_version = Some(behavior_version);
  312    314   
            self
  313    315   
        }
  314    316   
  315    317   
        /// Override the region used to build [`SdkConfig`].
@@ -383,385 +442,452 @@
  403    405   
        ///
  404    406   
        /// The HTTP client will be used for both AWS services and credentials providers.
  405    407   
        ///
  406    408   
        /// If you wish to use a separate HTTP client for credentials providers when creating clients,
  407    409   
        /// then override the HTTP client set with this function on the client-specific `Config`s.
  408    410   
        pub fn http_client(mut self, http_client: impl HttpClient + 'static) -> Self {
  409    411   
            self.http_client = Some(http_client.into_shared());
  410    412   
            self
  411    413   
        }
  412    414   
         415  +
        /// Sets the client protocol to use for serialization and deserialization.
         416  +
        ///
         417  +
        /// This overrides the default protocol determined by the service model.
         418  +
        pub fn protocol(mut self, protocol: impl ClientProtocol + 'static) -> Self {
         419  +
            self.protocol = Some(SharedClientProtocol::new(protocol));
         420  +
            self
         421  +
        }
         422  +
  413    423   
        #[doc = docs_for!(auth_scheme_preference)]
  414    424   
        ///
  415    425   
        /// # Examples
  416    426   
        /// ```no_run
  417    427   
        /// # use aws_smithy_runtime_api::client::auth::AuthSchemeId;
  418    428   
        /// # async fn create_config() {
  419    429   
        /// let config = aws_config::from_env()
  420    430   
        ///     // Favors a custom auth scheme over the SigV4 auth scheme.
  421    431   
        ///     // Note: This will not result in an error, even if the custom scheme is missing from the resolved auth schemes.
  422    432   
        ///     .auth_scheme_preference([AuthSchemeId::from("custom"), aws_runtime::auth::sigv4::SCHEME_ID])
@@ -963,973 +1022,1033 @@
  983    993   
                    }
  984    994   
                    // Not setting `Origin` in this arm, and that's good for now as long as we know
  985    995   
                    // it's not programmatically set in the shared config.
  986    996   
                    // We can consider adding `Origin::Default` if needed.
  987    997   
                }
  988    998   
            };
  989    999   
  990   1000   
            builder.set_endpoint_url(endpoint_url);
  991   1001   
            builder.set_behavior_version(self.behavior_version);
  992   1002   
            builder.set_http_client(self.http_client);
        1003  +
            builder.set_protocol(self.protocol);
  993   1004   
            builder.set_app_name(app_name);
  994   1005   
  995   1006   
            let identity_cache = match self.identity_cache {
  996   1007   
                None => match self.behavior_version {
  997   1008   
                    #[allow(deprecated)]
  998   1009   
                    Some(bv) if bv.is_at_least(BehaviorVersion::v2024_03_28()) => {
  999   1010   
                        Some(IdentityCache::lazy().build())
 1000   1011   
                    }
 1001   1012   
                    _ => None,
 1002   1013   
                },

tmp-codegen-diff/aws-sdk/sdk/aws-credential-types/Cargo.toml

@@ -8,8 +50,50 @@
   28     28   
path = "../aws-smithy-async"
   29     29   
version = "1.2.14"
   30     30   
   31     31   
[dependencies.aws-smithy-types]
   32     32   
path = "../aws-smithy-types"
   33     33   
version = "1.4.7"
   34     34   
   35     35   
[dependencies.aws-smithy-runtime-api]
   36     36   
path = "../aws-smithy-runtime-api"
   37     37   
features = ["client", "http-auth"]
   38         -
version = "1.11.6"
          38  +
version = "1.11.7"
   39     39   
   40     40   
[dev-dependencies]
   41     41   
async-trait = "0.1.74"
   42     42   
   43     43   
[dev-dependencies.aws-smithy-runtime-api]
   44     44   
path = "../aws-smithy-runtime-api"
   45     45   
features = ["test-util"]
   46         -
version = "1.11.6"
          46  +
version = "1.11.7"
   47     47   
   48     48   
[dev-dependencies.tokio]
   49     49   
version = "1.49.0"
   50     50   
features = ["full", "test-util", "rt"]

tmp-codegen-diff/aws-sdk/sdk/aws-runtime/Cargo.toml

@@ -1,1 +95,95 @@
    1      1   
# Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
    2      2   
[package]
    3      3   
name = "aws-runtime"
    4         -
version = "1.7.3"
           4  +
version = "1.7.4"
    5      5   
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>"]
    6      6   
description = "Runtime support code for the AWS SDK. This crate isn't intended to be used directly."
    7      7   
edition = "2021"
    8      8   
license = "Apache-2.0"
    9      9   
repository = "https://github.com/smithy-lang/smithy-rs"
   10     10   
rust-version = "1.91.1"
   11     11   
[package.metadata.docs.rs]
   12     12   
all-features = true
   13     13   
targets = ["x86_64-unknown-linux-gnu"]
   14     14   
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
   15     15   
rustdoc-args = ["--cfg", "docsrs"]
   16     16   
   17     17   
[package.metadata.smithy-rs-release-tooling]
   18     18   
stable = true
   19     19   
   20     20   
[features]
   21     21   
event-stream = ["dep:aws-smithy-eventstream", "aws-sigv4/sign-eventstream"]
   22     22   
http-02x = ["dep:http-02x", "dep:http-body-04x"]
   23     23   
http-1x = []
   24     24   
test-util = ["dep:regex-lite"]
   25     25   
sigv4a = ["aws-sigv4/sigv4a"]
   26     26   
   27     27   
[dependencies]
   28     28   
bytes = "1.11.1"
   29     29   
bytes-utils = "0.1.2"
   30     30   
fastrand = "2.3.0"
   31     31   
percent-encoding = "2.3.1"
   32     32   
pin-project-lite = "0.2.14"
   33     33   
tracing = "0.1.44"
   34     34   
   35     35   
[dependencies.aws-credential-types]
   36     36   
path = "../aws-credential-types"
   37     37   
version = "1.2.14"
   38     38   
   39     39   
[dependencies.aws-sigv4]
   40     40   
path = "../aws-sigv4"
   41     41   
features = ["http0-compat"]
   42     42   
version = "1.4.2"
   43     43   
   44     44   
[dependencies.aws-smithy-async]
   45     45   
path = "../aws-smithy-async"
   46     46   
version = "1.2.14"
   47     47   
   48     48   
[dependencies.aws-smithy-eventstream]
   49     49   
path = "../aws-smithy-eventstream"
   50     50   
optional = true
   51     51   
version = "0.60.20"
   52     52   
   53     53   
[dependencies.aws-smithy-http]
   54     54   
path = "../aws-smithy-http"
   55     55   
version = "0.63.6"
   56     56   
   57     57   
[dependencies.aws-smithy-runtime]
   58     58   
path = "../aws-smithy-runtime"
   59     59   
features = ["client"]
   60         -
version = "1.10.3"
          60  +
version = "1.10.4"
   61     61   
   62     62   
[dependencies.aws-smithy-runtime-api]
   63     63   
path = "../aws-smithy-runtime-api"
   64     64   
features = ["client", "http-1x"]
   65         -
version = "1.11.6"
          65  +
version = "1.11.7"
   66     66   
   67     67   
[dependencies.aws-smithy-types]
   68     68   
path = "../aws-smithy-types"
   69     69   
features = ["http-body-1-x"]
   70     70   
version = "1.4.7"
   71     71   
   72     72   
[dependencies.aws-types]
   73     73   
path = "../aws-types"
   74     74   
version = "1.4.0"
   75     75   
@@ -97,97 +148,148 @@
  117    117   
features = ["test-util"]
  118    118   
version = "1.2.14"
  119    119   
  120    120   
[dev-dependencies.aws-smithy-protocol-test]
  121    121   
path = "../aws-smithy-protocol-test"
  122    122   
version = "0.63.14"
  123    123   
  124    124   
[dev-dependencies.aws-smithy-runtime-api]
  125    125   
path = "../aws-smithy-runtime-api"
  126    126   
features = ["test-util", "http-1x"]
  127         -
version = "1.11.6"
         127  +
version = "1.11.7"
  128    128   
  129    129   
[dev-dependencies.aws-smithy-types]
  130    130   
path = "../aws-smithy-types"
  131    131   
features = ["test-util"]
  132    132   
version = "1.4.7"
  133    133   
  134    134   
[dev-dependencies.futures-util]
  135    135   
version = "0.3.29"
  136    136   
default-features = false
  137    137   

tmp-codegen-diff/aws-sdk/sdk/aws-sigv4/Cargo.toml

@@ -32,32 +92,92 @@
   52     52   
optional = true
   53     53   
version = "0.60.20"
   54     54   
   55     55   
[dependencies.aws-smithy-http]
   56     56   
path = "../aws-smithy-http"
   57     57   
version = "0.63.6"
   58     58   
   59     59   
[dependencies.aws-smithy-runtime-api]
   60     60   
path = "../aws-smithy-runtime-api"
   61     61   
features = ["client"]
   62         -
version = "1.11.6"
          62  +
version = "1.11.7"
   63     63   
   64     64   
[dependencies.aws-smithy-types]
   65     65   
path = "../aws-smithy-types"
   66     66   
version = "1.4.7"
   67     67   
   68     68   
[dependencies.form_urlencoded]
   69     69   
version = "1.2.1"
   70     70   
optional = true
   71     71   
   72     72   
[dependencies.http0]
@@ -95,95 +131,131 @@
  115    115   
criterion = "0.5"
  116    116   
  117    117   
[dev-dependencies.aws-credential-types]
  118    118   
path = "../aws-credential-types"
  119    119   
features = ["test-util", "hardcoded-credentials"]
  120    120   
version = "1.2.14"
  121    121   
  122    122   
[dev-dependencies.aws-smithy-runtime-api]
  123    123   
path = "../aws-smithy-runtime-api"
  124    124   
features = ["client", "test-util"]
  125         -
version = "1.11.6"
         125  +
version = "1.11.7"
  126    126   
  127    127   
[dev-dependencies.time]
  128    128   
version = "0.3.5"
  129    129   
features = ["parsing"]
  130    130   
[target."cfg(not(any(target_arch = \"powerpc\", target_arch = \"powerpc64\")))".dev-dependencies]
  131    131   
ring = "0.17.5"

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-compression/Cargo.toml

@@ -2,2 +51,51 @@
   22     22   
futures-util = "0.3"
   23     23   
pin-project-lite = "0.2.14"
   24     24   
tracing = "0.1.44"
   25     25   
   26     26   
[dependencies.aws-smithy-types]
   27     27   
path = "../aws-smithy-types"
   28     28   
version = "1.4.7"
   29     29   
   30     30   
[dependencies.aws-smithy-runtime-api]
   31     31   
path = "../aws-smithy-runtime-api"
   32         -
version = "1.11.6"
          32  +
version = "1.11.7"
   33     33   
   34     34   
[dependencies.http-1x]
   35     35   
package = "http"
   36     36   
version = "1.3.1"
   37     37   
   38     38   
[dependencies.http-body-1x]
   39     39   
package = "http-body"
   40     40   
version = "1.0.1"
   41     41   
   42     42   
[dependencies.http-body-util]

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-dns/Cargo.toml

@@ -1,1 +33,33 @@
   12     12   
all-features = true
   13     13   
targets = ["x86_64-unknown-linux-gnu"]
   14     14   
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
   15     15   
rustdoc-args = ["--cfg", "docsrs"]
   16     16   
   17     17   
[features]
   18     18   
hickory-dns = ["dep:hickory-resolver", "dep:tokio", "tokio/rt"]
   19     19   
[dependencies.aws-smithy-runtime-api]
   20     20   
path = "../aws-smithy-runtime-api"
   21     21   
features = ["client"]
   22         -
version = "1.11.6"
          22  +
version = "1.11.7"
   23     23   
   24     24   
[dependencies.tokio]
   25     25   
version = "1.49.0"
   26     26   
features = []
   27     27   
optional = true
   28     28   
[target."cfg(not(target_family = \"wasm\"))".dependencies.hickory-resolver]
   29     29   
version = "0.25.2"
   30     30   
optional = true
   31     31   
   32     32   
[dev-dependencies]

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/Cargo.toml

@@ -33,33 +93,93 @@
   53     53   
pin-project-lite = "0.2.14"
   54     54   
tracing = "0.1.44"
   55     55   
   56     56   
[dependencies.aws-smithy-async]
   57     57   
path = "../aws-smithy-async"
   58     58   
version = "1.2.14"
   59     59   
   60     60   
[dependencies.aws-smithy-runtime-api]
   61     61   
path = "../aws-smithy-runtime-api"
   62     62   
features = ["client"]
   63         -
version = "1.11.6"
          63  +
version = "1.11.7"
   64     64   
   65     65   
[dependencies.aws-smithy-types]
   66     66   
path = "../aws-smithy-types"
   67     67   
version = "1.4.7"
   68     68   
   69     69   
[dependencies.aws-smithy-protocol-test]
   70     70   
path = "../aws-smithy-protocol-test"
   71     71   
optional = true
   72     72   
version = "0.63.14"
   73     73   
@@ -184,184 +234,234 @@
  204    204   
tokio-rustls = "0.26.2"
  205    205   
  206    206   
[dev-dependencies.aws-smithy-async]
  207    207   
path = "../aws-smithy-async"
  208    208   
features = ["rt-tokio", "test-util"]
  209    209   
version = "1.2.14"
  210    210   
  211    211   
[dev-dependencies.aws-smithy-runtime-api]
  212    212   
path = "../aws-smithy-runtime-api"
  213    213   
features = ["test-util"]
  214         -
version = "1.11.6"
         214  +
version = "1.11.7"
  215    215   
  216    216   
[dev-dependencies.aws-smithy-types]
  217    217   
path = "../aws-smithy-types"
  218    218   
features = ["http-body-0-4-x", "test-util"]
  219    219   
version = "1.4.7"
  220    220   
  221    221   
[dev-dependencies.http-body-util]
  222    222   
version = "0.1.3"
  223    223   
  224    224   
[dev-dependencies.hyper-util]

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http/Cargo.toml

@@ -9,9 +69,69 @@
   29     29   
futures-core = "0.3.31"
   30     30   
   31     31   
[dependencies.aws-smithy-eventstream]
   32     32   
path = "../aws-smithy-eventstream"
   33     33   
optional = true
   34     34   
version = "0.60.20"
   35     35   
   36     36   
[dependencies.aws-smithy-runtime-api]
   37     37   
path = "../aws-smithy-runtime-api"
   38     38   
features = ["client", "http-1x"]
   39         -
version = "1.11.6"
          39  +
version = "1.11.7"
   40     40   
   41     41   
[dependencies.aws-smithy-types]
   42     42   
path = "../aws-smithy-types"
   43     43   
features = ["byte-stream-poll-next", "http-body-1-x"]
   44     44   
version = "1.4.7"
   45     45   
   46     46   
[dependencies.http-1x]
   47     47   
package = "http"
   48     48   
version = "1.3.1"
   49     49   

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-json/Cargo.toml

@@ -1,1 +0,31 @@
    6      6   
description = "Token streaming JSON parser for smithy-rs."
    7      7   
edition = "2021"
    8      8   
license = "Apache-2.0"
    9      9   
repository = "https://github.com/smithy-lang/smithy-rs"
   10     10   
rust-version = "1.91.1"
   11     11   
[package.metadata.docs.rs]
   12     12   
all-features = true
   13     13   
targets = ["x86_64-unknown-linux-gnu"]
   14     14   
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
   15     15   
rustdoc-args = ["--cfg", "docsrs"]
          16  +
[dependencies.aws-smithy-runtime-api]
          17  +
path = "../aws-smithy-runtime-api"
          18  +
features = ["client"]
          19  +
version = "1.11.7"
          20  +
   16     21   
[dependencies.aws-smithy-schema]
   17     22   
path = "../aws-smithy-schema"
   18     23   
version = "1.0.0"
   19     24   
   20     25   
[dependencies.aws-smithy-types]
   21     26   
path = "../aws-smithy-types"
   22     27   
version = "1.4.7"
   23     28   
   24     29   
[dev-dependencies]
   25     30   
proptest = "1"
   26         -
serde_json = "1.0"
          31  +
serde_json = "=1.0.146"

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

@@ -1,1 +195,183 @@
    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 codec implementation for schema-based serialization.
    7      7   
    8      8   
use aws_smithy_schema::codec::Codec;
    9      9   
use aws_smithy_schema::Schema;
   10     10   
use aws_smithy_types::date_time::Format as TimestampFormat;
   11         -
use std::collections::HashMap;
   12         -
use std::sync::Mutex;
   13         -
   14     11   
use std::sync::Arc;
   15     12   
   16     13   
mod deserializer;
   17     14   
mod serializer;
   18     15   
   19     16   
pub use deserializer::JsonDeserializer;
   20     17   
pub use serializer::JsonSerializer;
   21     18   
   22     19   
/// Maps between Smithy member names and JSON wire field names.
   23     20   
///
   24     21   
/// When `@jsonName` is enabled, the wire name may differ from the member name.
   25     22   
/// This type handles the mapping in both directions and caches the reverse
   26     23   
/// lookup (wire name → member index) per struct schema.
   27     24   
#[derive(Debug)]
   28     25   
enum JsonFieldMapper {
   29     26   
    /// Uses member names directly, ignoring `@jsonName`.
   30     27   
    UseMemberName,
   31         -
    /// Uses `@jsonName` trait values when present, with a cached reverse map.
   32         -
    UseJsonName {
   33         -
        /// Cache from schema pointer → (wire name → member index).
   34         -
        cache: Mutex<HashMap<usize, HashMap<String, usize>>>,
   35         -
    },
          28  +
    /// Uses `@jsonName` trait values when present, falling back to member name.
          29  +
    UseJsonName,
   36     30   
}
   37     31   
   38     32   
impl JsonFieldMapper {
   39     33   
    /// Returns the JSON wire name for a member schema.
   40     34   
    fn member_to_field<'a>(&self, member: &'a Schema) -> Option<&'a str> {
   41     35   
        let name = member.member_name()?;
   42     36   
        match self {
   43     37   
            JsonFieldMapper::UseMemberName => Some(name),
   44         -
            JsonFieldMapper::UseJsonName { .. } => {
          38  +
            JsonFieldMapper::UseJsonName => {
   45     39   
                if let Some(jn) = member.json_name() {
   46     40   
                    return Some(jn.value());
   47     41   
                }
   48     42   
                Some(name)
   49     43   
            }
   50     44   
        }
   51     45   
    }
   52     46   
   53     47   
    /// Resolves a JSON wire field name to a member schema within a struct schema.
   54     48   
    fn field_to_member<'s>(&self, schema: &'s Schema, field_name: &str) -> Option<&'s Schema> {
   55     49   
        match self {
   56     50   
            JsonFieldMapper::UseMemberName => schema.member_schema(field_name),
   57         -
            JsonFieldMapper::UseJsonName { cache } => {
   58         -
                let key = std::ptr::from_ref(schema) as usize;
   59         -
                let mut cache = cache.lock().unwrap();
   60         -
                let map = cache.entry(key).or_insert_with(|| {
   61         -
                    let mut map = HashMap::new();
   62         -
                    for (idx, member) in schema.members().iter().enumerate() {
          51  +
            JsonFieldMapper::UseJsonName => {
          52  +
                // Check @jsonName on each member. For typical struct sizes
          53  +
                // (< 50 members), linear scan is faster than a cached HashMap
          54  +
                // behind a Mutex.
          55  +
                for member in schema.members() {
   63     56   
                    if let Some(jn) = member.json_name() {
   64         -
                            map.insert(jn.value().to_string(), idx);
          57  +
                        if jn.value() == field_name {
          58  +
                            return Some(member);
   65     59   
                        }
          60  +
                    } else if member.member_name() == Some(field_name) {
          61  +
                        return Some(member);
   66     62   
                    }
   67         -
                    map
   68         -
                });
   69         -
                if let Some(&idx) = map.get(field_name) {
   70         -
                    return schema.member_schema_by_index(idx);
   71     63   
                }
   72         -
                schema.member_schema(field_name)
          64  +
                None
   73     65   
            }
   74     66   
        }
   75     67   
    }
   76     68   
}
   77     69   
   78     70   
/// Configuration for JSON codec behavior.
   79     71   
///
   80     72   
/// Use the builder methods to construct settings:
   81     73   
/// ```
   82     74   
/// use aws_smithy_json::codec::JsonCodecSettings;
   83     75   
///
   84     76   
/// let settings = JsonCodecSettings::builder()
   85     77   
///     .use_json_name(false)
   86     78   
///     .build();
   87     79   
/// ```
   88     80   
#[derive(Debug)]
   89     81   
pub struct JsonCodecSettings {
   90     82   
    field_mapper: JsonFieldMapper,
   91     83   
    default_timestamp_format: TimestampFormat,
   92     84   
}
   93     85   
   94     86   
impl JsonCodecSettings {
   95     87   
    /// Creates a builder for `JsonCodecSettings`.
   96     88   
    pub fn builder() -> JsonCodecSettingsBuilder {
   97     89   
        JsonCodecSettingsBuilder::default()
   98     90   
    }
   99     91   
  100     92   
    /// Default timestamp format when not specified by `@timestampFormat` trait.
  101     93   
    pub fn default_timestamp_format(&self) -> TimestampFormat {
  102     94   
        self.default_timestamp_format
  103     95   
    }
  104     96   
  105     97   
    /// Returns the JSON wire name for a member schema.
  106     98   
    pub(crate) fn member_to_field<'a>(&self, member: &'a Schema) -> Option<&'a str> {
  107     99   
        self.field_mapper.member_to_field(member)
  108    100   
    }
  109    101   
  110    102   
    /// Resolves a JSON wire field name to a member schema.
  111    103   
    pub(crate) fn field_to_member<'s>(
  112    104   
        &self,
  113    105   
        schema: &'s Schema,
  114    106   
        field_name: &str,
  115    107   
    ) -> Option<&'s Schema> {
  116    108   
        self.field_mapper.field_to_member(schema, field_name)
  117    109   
    }
  118    110   
}
  119    111   
  120    112   
impl Default for JsonCodecSettings {
  121    113   
    fn default() -> Self {
  122    114   
        Self {
  123         -
            field_mapper: JsonFieldMapper::UseJsonName {
  124         -
                cache: Mutex::new(HashMap::new()),
  125         -
            },
         115  +
            field_mapper: JsonFieldMapper::UseJsonName,
  126    116   
            default_timestamp_format: TimestampFormat::EpochSeconds,
  127    117   
        }
  128    118   
    }
  129    119   
}
  130    120   
  131    121   
/// Builder for [`JsonCodecSettings`].
  132    122   
#[derive(Debug, Clone)]
  133    123   
pub struct JsonCodecSettingsBuilder {
  134    124   
    use_json_name: bool,
  135    125   
    default_timestamp_format: TimestampFormat,
  136    126   
}
  137    127   
  138    128   
impl Default for JsonCodecSettingsBuilder {
  139    129   
    fn default() -> Self {
  140    130   
        Self {
  141    131   
            use_json_name: true,
  142    132   
            default_timestamp_format: TimestampFormat::EpochSeconds,
  143    133   
        }
  144    134   
    }
  145    135   
}
  146    136   
  147    137   
impl JsonCodecSettingsBuilder {
  148    138   
    /// Whether to use the `@jsonName` trait for member names.
  149    139   
    pub fn use_json_name(mut self, value: bool) -> Self {
  150    140   
        self.use_json_name = value;
  151    141   
        self
  152    142   
    }
  153    143   
  154    144   
    /// Default timestamp format when not specified by `@timestampFormat` trait.
  155    145   
    pub fn default_timestamp_format(mut self, value: TimestampFormat) -> Self {
  156    146   
        self.default_timestamp_format = value;
  157    147   
        self
  158    148   
    }
  159    149   
  160    150   
    /// Builds the settings.
  161    151   
    pub fn build(self) -> JsonCodecSettings {
  162    152   
        let field_mapper = if self.use_json_name {
  163         -
            JsonFieldMapper::UseJsonName {
  164         -
                cache: Mutex::new(HashMap::new()),
  165         -
            }
         153  +
            JsonFieldMapper::UseJsonName
  166    154   
        } else {
  167    155   
            JsonFieldMapper::UseMemberName
  168    156   
        };
  169    157   
        JsonCodecSettings {
  170    158   
            field_mapper,
  171    159   
            default_timestamp_format: self.default_timestamp_format,
  172    160   
        }
  173    161   
    }
  174    162   
}
  175    163   

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

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