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| {
|
308 - | SerdeError::InvalidInput {
|
309 - | message: e.to_string(),
|
310 - | }
|
321 + | self.skip_whitespace();
|
322 + | let pos = self.position;
|
323 + | let input = self.input;
|
324 + | let rem = &input[pos..];
|
325 + | if rem.first() != Some(&b'"') {
|
326 + | return Err(SerdeError::TypeMismatch {
|
327 + | message: "expected string".into(),
|
328 + | });
|
329 + | }
|
330 + | // Scan for end of string, tracking whether escapes are present
|
331 + | let mut i = 1;
|
332 + | let mut has_escape = false;
|
333 + | while i < rem.len() {
|
334 + | if rem[i] == b'\\' {
|
335 + | has_escape = true;
|
336 + | i += 2;
|
337 + | } else if rem[i] == b'"' {
|
338 + | let raw = &input[pos + 1..pos + i];
|
339 + | self.position = pos + i + 1;
|
340 + | if !has_escape {
|
341 + | return std::str::from_utf8(raw).map(|s| s.to_owned()).map_err(|e| {
|
342 + | SerdeError::InvalidInput {
|
343 + | message: e.to_string(),
|
344 + | }
|
345 + | });
|
346 + | }
|
347 + | let s = std::str::from_utf8(raw).map_err(|e| SerdeError::InvalidInput {
|
348 + | message: e.to_string(),
|
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;
|
388 + | }
|
389 + | out.push(self.read_string(_schema)?);
|
390 + | }
|
391 + | Ok(out)
|
392 + | }
|
393 + |
|
394 + | fn read_blob_list(&mut self, _schema: &Schema) -> Result<Vec<Blob>, SerdeError> {
|
395 + | self.skip_whitespace();
|
396 + | if self.remaining().first() != Some(&b'[') {
|
397 + | return Err(SerdeError::TypeMismatch {
|
398 + | message: "expected array".into(),
|
399 + | });
|
400 + | }
|
401 + | self.advance_by(1);
|
402 + | let mut out = Vec::new();
|
403 + | loop {
|
404 + | self.skip_whitespace();
|
405 + | if self.remaining().first() == Some(&b']') {
|
406 + | self.advance_by(1);
|
407 + | break;
|
408 + | }
|
409 + | out.push(self.read_blob(_schema)?);
|
410 + | }
|
411 + | Ok(out)
|
412 + | }
|
413 + |
|
414 + | fn read_integer_list(&mut self, _schema: &Schema) -> Result<Vec<i32>, SerdeError> {
|
415 + | self.skip_whitespace();
|
416 + | if self.remaining().first() != Some(&b'[') {
|
417 + | return Err(SerdeError::TypeMismatch {
|
418 + | message: "expected array".into(),
|
419 + | });
|
420 + | }
|
421 + | self.advance_by(1);
|
422 + | let mut out = Vec::new();
|
423 + | loop {
|
424 + | self.skip_whitespace();
|
425 + | if self.remaining().first() == Some(&b']') {
|
426 + | self.advance_by(1);
|
427 + | break;
|
428 + | }
|
429 + | out.push(self.read_integer(_schema)?);
|
430 + | }
|
431 + | Ok(out)
|
432 + | }
|
433 + |
|
434 + | fn read_long_list(&mut self, _schema: &Schema) -> Result<Vec<i64>, SerdeError> {
|
435 + | self.skip_whitespace();
|
436 + | if self.remaining().first() != Some(&b'[') {
|
437 + | return Err(SerdeError::TypeMismatch {
|
438 + | message: "expected array".into(),
|
439 + | });
|
440 + | }
|
441 + | self.advance_by(1);
|
442 + | let mut out = Vec::new();
|
443 + | loop {
|
444 + | self.skip_whitespace();
|
445 + | if self.remaining().first() == Some(&b']') {
|
446 + | self.advance_by(1);
|
447 + | break;
|
448 + | }
|
449 + | out.push(self.read_long(_schema)?);
|
450 + | }
|
451 + | Ok(out)
|
452 + | }
|
453 + |
|
454 + | fn read_string_string_map(
|
455 + | &mut self,
|
456 + | _schema: &Schema,
|
457 + | ) -> Result<std::collections::HashMap<String, String>, SerdeError> {
|
458 + | self.skip_whitespace();
|
459 + | if self.remaining().first() != Some(&b'{') {
|
460 + | return Err(SerdeError::TypeMismatch {
|
461 + | message: "expected object".into(),
|
462 + | });
|
463 + | }
|
464 + | self.advance_by(1);
|
465 + | let mut out = std::collections::HashMap::new();
|
466 + | loop {
|
467 + | self.skip_whitespace();
|
468 + | if self.remaining().first() == Some(&b'}') {
|
469 + | self.advance_by(1);
|
470 + | break;
|
471 + | }
|
472 + | if self.remaining().first() != Some(&b'"') {
|
473 + | return Err(SerdeError::InvalidInput {
|
474 + | message: "expected key".into(),
|
475 + | });
|
339 476 | }
|
340 - | Some(Ok(Token::ValueNumber {
|
341 - | value: Number::NegInt(n),
|
342 - | ..
|
343 - | })) => {
|
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();
|
345 - | Ok(DateTime::from_secs(n))
|
522 + | let num_str =
|
523 + | std::str::from_utf8(&self.input[start..self.position]).map_err(|e| {
|
524 + | SerdeError::InvalidInput {
|
525 + | message: e.to_string(),
|
526 + | }
|
527 + | })?;
|
528 + | if num_str.contains('.') || num_str.contains('e') || num_str.contains('E') {
|
529 + | let f: f64 = num_str.parse().map_err(|e: std::num::ParseFloatError| {
|
530 + | SerdeError::InvalidInput {
|
531 + | message: e.to_string(),
|
532 + | }
|
533 + | })?;
|
534 + | Ok(DateTime::from_secs_f64(f))
|
535 + | } else if num_str.starts_with('-') {
|
536 + | let n: i64 = num_str.parse().map_err(|e: std::num::ParseIntError| {
|
537 + | SerdeError::InvalidInput {
|
538 + | message: e.to_string(),
|
539 + | }
|
540 + | })?;
|
541 + | Ok(DateTime::from_secs(n))
|
542 + | } else {
|
543 + | let n: u64 = num_str.parse().map_err(|e: std::num::ParseIntError| {
|
544 + | SerdeError::InvalidInput {
|
545 + | message: e.to_string(),
|
546 + | }
|
547 + | })?;
|
548 + | Ok(DateTime::from_secs(n as i64))
|
549 + | }
|
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 { .. })) => {
|
357 - | self.advance_by(4);
|
358 - | Ok(Document::Null)
|
558 + | self.skip_whitespace();
|
559 + | match self.remaining().first() {
|
560 + | Some(b'"') => Ok(Document::String(self.read_string(_schema)?)),
|
561 + | Some(b't') | Some(b'f') => Ok(Document::Bool(self.read_boolean(_schema)?)),
|
562 + | Some(b'n') => {
|
563 + | if self.remaining().starts_with(b"null") {
|
564 + | self.advance_by(4);
|
565 + | Ok(Document::Null)
|
566 + | } else {
|
567 + | Err(SerdeError::InvalidInput {
|
568 + | message: "unexpected token in document".into(),
|
569 + | })
|
570 + | }
|
571 + | }
|
572 + | Some(b'{') => {
|
573 + | self.advance_by(1);
|
574 + | let mut map = std::collections::HashMap::new();
|
575 + | loop {
|
576 + | self.skip_whitespace();
|
577 + | if self.remaining().first() == Some(&b'}') {
|
578 + | self.advance_by(1);
|
579 + | break;
|
580 + | }
|
581 + | if self.remaining().first() != Some(&b'"') {
|
582 + | return Err(SerdeError::InvalidInput {
|
583 + | message: "expected object key in document".into(),
|
584 + | });
|
585 + | }
|
586 + | let key = self.parse_key()?.into_owned();
|
587 + | self.skip_whitespace();
|
588 + | if self.remaining().first() != Some(&b':') {
|
589 + | return Err(SerdeError::InvalidInput {
|
590 + | message: "expected colon in document object".into(),
|
591 + | });
|
592 + | }
|
593 + | self.advance_by(1);
|
594 + | let value = self.read_document(_schema)?;
|
595 + | map.insert(key, value);
|
596 + | }
|
597 + | Ok(Document::Object(map))
|
598 + | }
|
599 + | Some(b'[') => {
|
600 + | self.advance_by(1);
|
601 + | let mut arr = Vec::new();
|
602 + | loop {
|
603 + | self.skip_whitespace();
|
604 + | if self.remaining().first() == Some(&b']') {
|
605 + | self.advance_by(1);
|
606 + | break;
|
607 + | }
|
608 + | arr.push(self.read_document(_schema)?);
|
609 + | }
|
610 + | Ok(Document::Array(arr))
|
359 611 | }
|
360 - | _ => Err(SerdeError::UnsupportedOperation {
|
361 - | message: "document deserialization not fully implemented".into(),
|
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 {
|
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 });
|
472 - | return Ok(());
|
776 + | Some(b'"') => {
|
777 + | // Skip quoted string (handles escapes)
|
778 + | let mut i = 1;
|
779 + | let rem = self.remaining();
|
780 + | while i < rem.len() {
|
781 + | if rem[i] == b'\\' {
|
782 + | i += 2; // skip escape sequence
|
783 + | } else if rem[i] == b'"' {
|
784 + | i += 1;
|
785 + | break;
|
786 + | } else {
|
787 + | i += 1;
|
788 + | }
|
789 + | }
|
790 + | self.advance_by(i);
|
791 + | // After a string inside an object, skip optional ':'
|
792 + | if depth > 0 {
|
793 + | self.skip_whitespace();
|
794 + | if self.remaining().first() == Some(&b':') {
|
795 + | self.advance_by(1);
|
796 + | continue; // read the value after the colon
|
797 + | }
|
798 + | }
|
799 + | if depth == 0 {
|
800 + | return Ok(());
|
801 + | }
|
802 + | }
|
803 + | Some(b't') => {
|
804 + | self.advance_by(4); // true
|
805 + | if depth == 0 {
|
806 + | return Ok(());
|
807 + | }
|
473 808 | }
|
474 - | Some(Ok(Token::ValueNull { .. })) if depth == 0 => {
|
475 - | self.advance_by(4);
|
476 - | return Ok(());
|
809 + | Some(b'f') => {
|
810 + | self.advance_by(5); // false
|
811 + | if depth == 0 {
|
812 + | return Ok(());
|
813 + | }
|
477 814 | }
|
478 - | Some(Ok(Token::ValueString { value, .. })) if depth == 0 => {
|
479 - | self.advance_by(value.as_escaped_str().len() + 2);
|
480 - | return Ok(());
|
815 + | Some(b'n') => {
|
816 + | self.advance_by(4); // null
|
817 + | if depth == 0 {
|
818 + | return Ok(());
|
819 + | }
|
481 820 | }
|
482 - | Some(Ok(Token::ValueNumber { .. })) if depth == 0 => {
|
821 + | Some(c) if c == b'-' || c.is_ascii_digit() => {
|
483 822 | self.consume_number();
|
484 - | return Ok(());
|
485 - | }
|
486 - | Some(Ok(Token::ObjectKey { key, .. })) => {
|
487 - | self.advance_by(key.as_escaped_str().len() + 3);
|
823 + | if depth == 0 {
|
824 + | return Ok(());
|
825 + | }
|
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 - | })
|
515 - | }
|
516 - | Some(Ok(Token::ValueNumber {
|
517 - | value: Number::NegInt(n),
|
518 - | ..
|
519 - | })) => {
|
520 - | self.consume_number();
|
521 - | Ok(n)
|
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;
|
522 850 | }
|
523 - | _ => Err(SerdeError::TypeMismatch {
|
851 + | }
|
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)
|
538 - | }
|
539 - | Some(Ok(Token::ValueNumber {
|
540 - | value: Number::PosInt(n),
|
541 - | ..
|
542 - | })) => {
|
543 - | self.consume_number();
|
544 - | Ok(n as f64)
|
545 - | }
|
546 - | Some(Ok(Token::ValueNumber {
|
547 - | value: Number::NegInt(n),
|
548 - | ..
|
549 - | })) => {
|
550 - | self.consume_number();
|
551 - | Ok(n as f64)
|
868 + | self.skip_whitespace();
|
869 + | let rem = self.remaining();
|
870 + | // Handle string-encoded special float values: "NaN", "Infinity", "-Infinity"
|
871 + | if rem.first() == Some(&b'"') {
|
872 + | let s = self.read_string(&aws_smithy_schema::prelude::STRING)?;
|
873 + | return match s.as_str() {
|
874 + | "NaN" => Ok(f64::NAN),
|
875 + | "Infinity" => Ok(f64::INFINITY),
|
876 + | "-Infinity" => Ok(f64::NEG_INFINITY),
|
877 + | _ => s.parse::<f64>().map_err(|e| SerdeError::InvalidInput {
|
878 + | message: e.to_string(),
|
879 + | }),
|
880 + | };
|
881 + | }
|
882 + | let mut len = 0;
|
883 + | for &b in rem {
|
884 + | if b.is_ascii_digit() || b == b'-' || b == b'+' || b == b'.' || b == b'e' || b == b'E' {
|
885 + | len += 1;
|
886 + | } else {
|
887 + | break;
|
552 888 | }
|
553 - | _ => Err(SerdeError::TypeMismatch {
|
889 + | }
|
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 | }
|
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]
|
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 | }
|