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