1use aws_smithy_schema::serde::ShapeDeserializer;
9use aws_smithy_schema::Schema;
10use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime, Document, Number};
11use std::fmt;
12
13use crate::codec::JsonCodecSettings;
14use crate::deserialize::{json_token_iter, Token};
15
16#[derive(Debug)]
18pub enum JsonDeserializerError {
19 ParseError(String),
21}
22
23impl fmt::Display for JsonDeserializerError {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 Self::ParseError(msg) => write!(f, "JSON parse error: {}", msg),
27 }
28 }
29}
30
31impl std::error::Error for JsonDeserializerError {}
32
33pub struct JsonDeserializer {
35 input: Vec<u8>,
36 position: usize,
37 _settings: JsonCodecSettings,
38}
39
40impl JsonDeserializer {
41 pub fn new(input: &[u8], settings: JsonCodecSettings) -> Self {
43 Self {
44 input: input.to_vec(),
45 position: 0,
46 _settings: settings,
47 }
48 }
49
50 fn remaining(&self) -> &[u8] {
51 &self.input[self.position..]
52 }
53
54 fn advance_by(&mut self, n: usize) {
55 self.position += n;
56 }
57}
58
59impl ShapeDeserializer for JsonDeserializer {
60 type Error = JsonDeserializerError;
61
62 fn read_struct<T, F>(
63 &mut self,
64 schema: &dyn Schema,
65 mut state: T,
66 mut consumer: F,
67 ) -> Result<T, Self::Error>
68 where
69 F: FnMut(T, &dyn Schema, &mut Self) -> Result<T, Self::Error>,
70 {
71 self.skip_whitespace();
73 if self.remaining().first() != Some(&b'{') {
74 return Err(JsonDeserializerError::ParseError("Expected object".into()));
75 }
76 self.advance_by(1);
77
78 loop {
79 self.skip_whitespace();
80
81 if self.remaining().first() == Some(&b'}') {
83 self.advance_by(1);
84 break;
85 }
86
87 if self.remaining().first() != Some(&b'"') {
89 return Err(JsonDeserializerError::ParseError(
90 "Expected object key".into(),
91 ));
92 }
93
94 let mut iter = json_token_iter(self.remaining());
96 let key_str = match iter.next() {
97 Some(Ok(Token::ValueString { value, .. })) => {
98 let key_len = value.as_escaped_str().len();
99 let key = value
100 .to_unescaped()
101 .map_err(|e| JsonDeserializerError::ParseError(e.to_string()))?
102 .into_owned();
103 self.advance_by(key_len + 2);
105 key
106 }
107 _ => {
108 return Err(JsonDeserializerError::ParseError(
109 "Expected object key".into(),
110 ))
111 }
112 };
113
114 self.skip_whitespace();
116 if self.remaining().first() != Some(&b':') {
117 return Err(JsonDeserializerError::ParseError(
118 "Expected colon after key".into(),
119 ));
120 }
121 self.advance_by(1);
122 self.skip_whitespace();
123
124 if let Some(member_schema) = schema.member_schema(&key_str) {
126 state = consumer(state, member_schema, self)?;
127 } else {
128 self.skip_value()?;
129 }
130 }
131
132 Ok(state)
133 }
134
135 fn read_list<T, F>(
136 &mut self,
137 _schema: &dyn Schema,
138 mut state: T,
139 mut consumer: F,
140 ) -> Result<T, Self::Error>
141 where
142 F: FnMut(T, &mut Self) -> Result<T, Self::Error>,
143 {
144 self.skip_whitespace();
145 if self.remaining().first() != Some(&b'[') {
146 return Err(JsonDeserializerError::ParseError("Expected array".into()));
147 }
148 self.advance_by(1);
149
150 loop {
151 self.skip_whitespace();
152 if self.remaining().first() == Some(&b']') {
153 self.advance_by(1);
154 break;
155 }
156 state = consumer(state, self)?;
157 }
158
159 Ok(state)
160 }
161
162 fn read_map<T, F>(
163 &mut self,
164 _schema: &dyn Schema,
165 mut state: T,
166 mut consumer: F,
167 ) -> Result<T, Self::Error>
168 where
169 F: FnMut(T, String, &mut Self) -> Result<T, Self::Error>,
170 {
171 self.skip_whitespace();
172 if self.remaining().first() != Some(&b'{') {
173 return Err(JsonDeserializerError::ParseError("Expected object".into()));
174 }
175 self.advance_by(1);
176
177 loop {
178 self.skip_whitespace();
179 if self.remaining().first() == Some(&b'}') {
180 self.advance_by(1);
181 break;
182 }
183
184 if self.remaining().first() != Some(&b'"') {
185 return Err(JsonDeserializerError::ParseError("Expected key".into()));
186 }
187
188 let mut iter = json_token_iter(self.remaining());
189 let key = match iter.next() {
190 Some(Ok(Token::ValueString { value, .. })) => {
191 let len = value.as_escaped_str().len();
192 let key = value
193 .to_unescaped()
194 .map_err(|e| JsonDeserializerError::ParseError(e.to_string()))?
195 .into_owned();
196 self.advance_by(len + 2);
197 key
198 }
199 _ => return Err(JsonDeserializerError::ParseError("Expected key".into())),
200 };
201
202 self.skip_whitespace();
203 if self.remaining().first() != Some(&b':') {
204 return Err(JsonDeserializerError::ParseError("Expected colon".into()));
205 }
206 self.advance_by(1);
207 self.skip_whitespace();
208
209 state = consumer(state, key, self)?;
210 }
211
212 Ok(state)
213 }
214
215 fn read_boolean(&mut self, _schema: &dyn Schema) -> Result<bool, Self::Error> {
216 let mut iter = json_token_iter(self.remaining());
217 match iter.next() {
218 Some(Ok(Token::ValueBool { value, .. })) => {
219 self.advance_by(if value { 4 } else { 5 });
220 Ok(value)
221 }
222 _ => Err(JsonDeserializerError::ParseError("Expected boolean".into())),
223 }
224 }
225
226 fn read_byte(&mut self, _schema: &dyn Schema) -> Result<i8, Self::Error> {
227 self.read_integer_value().and_then(|n| {
228 i8::try_from(n).map_err(|_| {
229 JsonDeserializerError::ParseError("Value out of range for byte".into())
230 })
231 })
232 }
233
234 fn read_short(&mut self, _schema: &dyn Schema) -> Result<i16, Self::Error> {
235 self.read_integer_value().and_then(|n| {
236 i16::try_from(n).map_err(|_| {
237 JsonDeserializerError::ParseError("Value out of range for short".into())
238 })
239 })
240 }
241
242 fn read_integer(&mut self, _schema: &dyn Schema) -> Result<i32, Self::Error> {
243 self.read_integer_value().and_then(|n| {
244 i32::try_from(n).map_err(|_| {
245 JsonDeserializerError::ParseError("Value out of range for integer".into())
246 })
247 })
248 }
249
250 fn read_long(&mut self, _schema: &dyn Schema) -> Result<i64, Self::Error> {
251 self.read_integer_value()
252 }
253
254 fn read_float(&mut self, _schema: &dyn Schema) -> Result<f32, Self::Error> {
255 self.read_float_value().map(|f| f as f32)
256 }
257
258 fn read_double(&mut self, _schema: &dyn Schema) -> Result<f64, Self::Error> {
259 self.read_float_value()
260 }
261
262 fn read_big_integer(&mut self, _schema: &dyn Schema) -> Result<BigInteger, Self::Error> {
263 use std::str::FromStr;
264 let mut iter = json_token_iter(self.remaining());
265 match iter.next() {
266 Some(Ok(Token::ValueNumber { .. })) => {
267 self.consume_number();
268 BigInteger::from_str("0")
269 .map_err(|e| JsonDeserializerError::ParseError(e.to_string()))
270 }
271 _ => Err(JsonDeserializerError::ParseError("Expected number".into())),
272 }
273 }
274
275 fn read_big_decimal(&mut self, _schema: &dyn Schema) -> Result<BigDecimal, Self::Error> {
276 use std::str::FromStr;
277 let mut iter = json_token_iter(self.remaining());
278 match iter.next() {
279 Some(Ok(Token::ValueNumber { .. })) => {
280 self.consume_number();
281 BigDecimal::from_str("0")
282 .map_err(|e| JsonDeserializerError::ParseError(e.to_string()))
283 }
284 _ => Err(JsonDeserializerError::ParseError("Expected number".into())),
285 }
286 }
287
288 fn read_string(&mut self, _schema: &dyn Schema) -> Result<String, Self::Error> {
289 let mut iter = json_token_iter(self.remaining());
290 match iter.next() {
291 Some(Ok(Token::ValueString { value, .. })) => {
292 let len = value.as_escaped_str().len();
293 let result = value
294 .to_unescaped()
295 .map(|s| s.into_owned())
296 .map_err(|e| JsonDeserializerError::ParseError(e.to_string()))?;
297 self.advance_by(len + 2);
298 Ok(result)
299 }
300 _ => Err(JsonDeserializerError::ParseError("Expected string".into())),
301 }
302 }
303
304 fn read_blob(&mut self, _schema: &dyn Schema) -> Result<Blob, Self::Error> {
305 let s = self.read_string(_schema)?;
306 Ok(Blob::new(s.into_bytes()))
307 }
308
309 fn read_timestamp(&mut self, _schema: &dyn Schema) -> Result<DateTime, Self::Error> {
310 let mut iter = json_token_iter(self.remaining());
311 match iter.next() {
312 Some(Ok(Token::ValueNumber {
313 value: Number::PosInt(n),
314 ..
315 })) => {
316 self.consume_number();
317 Ok(DateTime::from_secs(n as i64))
318 }
319 Some(Ok(Token::ValueNumber {
320 value: Number::NegInt(n),
321 ..
322 })) => {
323 self.consume_number();
324 Ok(DateTime::from_secs(n))
325 }
326 _ => Err(JsonDeserializerError::ParseError(
327 "Expected timestamp".into(),
328 )),
329 }
330 }
331
332 fn read_document(&mut self, _schema: &dyn Schema) -> Result<Document, Self::Error> {
333 let mut iter = json_token_iter(self.remaining());
334 match iter.next() {
335 Some(Ok(Token::ValueNull { .. })) => {
336 self.advance_by(4);
337 Ok(Document::Null)
338 }
339 _ => Err(JsonDeserializerError::ParseError(
340 "Document deserialization not fully implemented".into(),
341 )),
342 }
343 }
344
345 fn is_null(&self) -> bool {
346 let mut iter = json_token_iter(self.remaining());
347 matches!(iter.next(), Some(Ok(Token::ValueNull { .. })))
348 }
349
350 fn container_size(&self) -> Option<usize> {
351 let mut iter = json_token_iter(self.remaining());
352 match iter.next()? {
353 Ok(Token::StartArray { .. }) => {
354 let mut count = 0;
355 let mut depth = 1;
356 for token in iter {
357 match token {
358 Ok(Token::StartArray { .. }) | Ok(Token::StartObject { .. }) => {
359 if depth == 1 {
360 count += 1;
361 }
362 depth += 1;
363 }
364 Ok(Token::EndArray { .. }) | Ok(Token::EndObject { .. }) => {
365 depth -= 1;
366 if depth == 0 {
367 return Some(count);
368 }
369 }
370 Ok(Token::ValueBool { .. })
371 | Ok(Token::ValueNull { .. })
372 | Ok(Token::ValueString { .. })
373 | Ok(Token::ValueNumber { .. })
374 if depth == 1 =>
375 {
376 count += 1
377 }
378 _ => {}
379 }
380 }
381 None
382 }
383 Ok(Token::StartObject { .. }) => {
384 let mut count = 0;
385 let mut depth = 1;
386 for token in iter {
387 match token {
388 Ok(Token::StartArray { .. }) | Ok(Token::StartObject { .. }) => depth += 1,
389 Ok(Token::EndArray { .. }) | Ok(Token::EndObject { .. }) => {
390 depth -= 1;
391 if depth == 0 {
392 return Some(count);
393 }
394 }
395 Ok(Token::ObjectKey { .. }) if depth == 1 => count += 1,
396 _ => {}
397 }
398 }
399 None
400 }
401 _ => None,
402 }
403 }
404}
405
406impl JsonDeserializer {
407 fn skip_whitespace(&mut self) {
408 while self.position < self.input.len() {
409 match self.input[self.position] {
410 b' ' | b'\t' | b'\n' | b'\r' | b',' => self.position += 1,
411 _ => break,
412 }
413 }
414 }
415
416 fn consume_number(&mut self) {
417 let mut len = 0;
418 for &b in self.remaining() {
419 if b.is_ascii_digit() || b == b'-' || b == b'.' || b == b'e' || b == b'E' || b == b'+' {
420 len += 1;
421 } else {
422 break;
423 }
424 }
425 self.advance_by(len);
426 }
427
428 fn skip_value(&mut self) -> Result<(), JsonDeserializerError> {
429 let mut depth = 0;
430 loop {
431 let mut iter = json_token_iter(self.remaining());
432 match iter.next() {
433 Some(Ok(Token::StartObject { .. })) | Some(Ok(Token::StartArray { .. })) => {
434 self.advance_by(1);
435 depth += 1;
436 }
437 Some(Ok(Token::EndObject { .. })) | Some(Ok(Token::EndArray { .. })) => {
438 self.advance_by(1);
439 if depth == 0 {
440 return Err(JsonDeserializerError::ParseError(
441 "Unexpected end token".into(),
442 ));
443 }
444 depth -= 1;
445 if depth == 0 {
446 return Ok(());
447 }
448 }
449 Some(Ok(Token::ValueBool { value, .. })) if depth == 0 => {
450 self.advance_by(if value { 4 } else { 5 });
451 return Ok(());
452 }
453 Some(Ok(Token::ValueNull { .. })) if depth == 0 => {
454 self.advance_by(4);
455 return Ok(());
456 }
457 Some(Ok(Token::ValueString { value, .. })) if depth == 0 => {
458 self.advance_by(value.as_escaped_str().len() + 2);
459 return Ok(());
460 }
461 Some(Ok(Token::ValueNumber { .. })) if depth == 0 => {
462 self.consume_number();
463 return Ok(());
464 }
465 Some(Ok(Token::ObjectKey { key, .. })) => {
466 self.advance_by(key.as_escaped_str().len() + 3);
467 }
468 Some(Ok(_)) => {}
469 Some(Err(e)) => return Err(JsonDeserializerError::ParseError(e.to_string())),
470 None => {
471 return Err(JsonDeserializerError::ParseError(
472 "Unexpected end of input".into(),
473 ))
474 }
475 }
476 }
477 }
478
479 fn read_integer_value(&mut self) -> Result<i64, JsonDeserializerError> {
480 let mut iter = json_token_iter(self.remaining());
481 match iter.next() {
482 Some(Ok(Token::ValueNumber {
483 value: Number::PosInt(n),
484 ..
485 })) => {
486 self.consume_number();
487 i64::try_from(n)
488 .map_err(|_| JsonDeserializerError::ParseError("Value out of range".into()))
489 }
490 Some(Ok(Token::ValueNumber {
491 value: Number::NegInt(n),
492 ..
493 })) => {
494 self.consume_number();
495 Ok(n)
496 }
497 _ => Err(JsonDeserializerError::ParseError("Expected integer".into())),
498 }
499 }
500
501 fn read_float_value(&mut self) -> Result<f64, JsonDeserializerError> {
502 let mut iter = json_token_iter(self.remaining());
503 match iter.next() {
504 Some(Ok(Token::ValueNumber {
505 value: Number::Float(f),
506 ..
507 })) => {
508 self.consume_number();
509 Ok(f)
510 }
511 Some(Ok(Token::ValueNumber {
512 value: Number::PosInt(n),
513 ..
514 })) => {
515 self.consume_number();
516 Ok(n as f64)
517 }
518 Some(Ok(Token::ValueNumber {
519 value: Number::NegInt(n),
520 ..
521 })) => {
522 self.consume_number();
523 Ok(n as f64)
524 }
525 _ => Err(JsonDeserializerError::ParseError("Expected number".into())),
526 }
527 }
528}
529
530#[cfg(test)]
531mod tests {
532 use super::*;
533
534 fn dummy_schema() -> &'static impl aws_smithy_schema::Schema {
535 &aws_smithy_schema::prelude::STRING
536 }
537
538 #[test]
539 fn test_read_boolean() {
540 let mut deser = JsonDeserializer::new(b"true", JsonCodecSettings::default());
541 assert_eq!(deser.read_boolean(dummy_schema()).unwrap(), true);
542
543 let mut deser = JsonDeserializer::new(b"false", JsonCodecSettings::default());
544 assert_eq!(deser.read_boolean(dummy_schema()).unwrap(), false);
545 }
546
547 #[test]
548 fn test_read_integer() {
549 let mut deser = JsonDeserializer::new(b"42", JsonCodecSettings::default());
550 assert_eq!(deser.read_integer(dummy_schema()).unwrap(), 42);
551
552 let mut deser = JsonDeserializer::new(b"-123", JsonCodecSettings::default());
553 assert_eq!(deser.read_integer(dummy_schema()).unwrap(), -123);
554 }
555
556 #[test]
557 fn test_read_long() {
558 let mut deser = JsonDeserializer::new(b"9223372036854775807", JsonCodecSettings::default());
559 assert_eq!(deser.read_long(dummy_schema()).unwrap(), i64::MAX);
560 }
561
562 #[test]
563 fn test_read_float() {
564 let mut deser = JsonDeserializer::new(b"3.14", JsonCodecSettings::default());
565 assert!((deser.read_float(dummy_schema()).unwrap() - 3.14).abs() < 0.01);
566 }
567
568 #[test]
569 fn test_read_double() {
570 let mut deser = JsonDeserializer::new(b"2.718", JsonCodecSettings::default());
571 assert!((deser.read_double(dummy_schema()).unwrap() - 2.718).abs() < 0.001);
572 }
573
574 #[test]
575 fn test_read_string() {
576 let mut deser = JsonDeserializer::new(br#""hello world""#, JsonCodecSettings::default());
577 assert_eq!(deser.read_string(dummy_schema()).unwrap(), "hello world");
578
579 let mut deser = JsonDeserializer::new(br#""hello\nworld""#, JsonCodecSettings::default());
580 assert_eq!(deser.read_string(dummy_schema()).unwrap(), "hello\nworld");
581 }
582
583 #[test]
584 fn test_is_null() {
585 let deser = JsonDeserializer::new(b"null", JsonCodecSettings::default());
586 assert!(deser.is_null());
587
588 let deser = JsonDeserializer::new(b"42", JsonCodecSettings::default());
589 assert!(!deser.is_null());
590 }
591
592 #[test]
593 fn test_read_byte_range() {
594 let mut deser = JsonDeserializer::new(b"127", JsonCodecSettings::default());
595 assert_eq!(deser.read_byte(dummy_schema()).unwrap(), 127);
596
597 let mut deser = JsonDeserializer::new(b"128", JsonCodecSettings::default());
598 assert!(deser.read_byte(dummy_schema()).is_err());
599 }
600
601 #[test]
602 fn test_read_struct() {
603 use aws_smithy_schema::{prelude, Schema, ShapeId, ShapeType, TraitMap};
604
605 #[derive(Debug, Default, PartialEq)]
606 struct Person {
607 first_name: String,
608 last_name: String,
609 age: i32,
610 }
611
612 struct MemberSchema {
613 name: &'static str,
614 target: &'static dyn Schema,
615 }
616
617 impl Schema for MemberSchema {
618 fn shape_id(&self) -> &ShapeId {
619 self.target.shape_id()
620 }
621 fn shape_type(&self) -> ShapeType {
622 self.target.shape_type()
623 }
624 fn traits(&self) -> &TraitMap {
625 self.target.traits()
626 }
627 fn member_name(&self) -> Option<&str> {
628 Some(self.name)
629 }
630 }
631
632 static FIRST_NAME: MemberSchema = MemberSchema {
633 name: "firstName",
634 target: &prelude::STRING,
635 };
636 static LAST_NAME: MemberSchema = MemberSchema {
637 name: "lastName",
638 target: &prelude::STRING,
639 };
640 static AGE: MemberSchema = MemberSchema {
641 name: "age",
642 target: &prelude::INTEGER,
643 };
644
645 struct TestSchema;
646 impl Schema for TestSchema {
647 fn shape_id(&self) -> &ShapeId {
648 static ID: std::sync::LazyLock<ShapeId> =
649 std::sync::LazyLock::new(|| ShapeId::from_static("test#Test", "test", "Test"));
650 &ID
651 }
652 fn shape_type(&self) -> ShapeType {
653 ShapeType::Structure
654 }
655 fn traits(&self) -> &TraitMap {
656 static MAP: std::sync::LazyLock<TraitMap> = std::sync::LazyLock::new(TraitMap::new);
657 &MAP
658 }
659 fn member_schema(&self, name: &str) -> Option<&dyn Schema> {
660 match name {
661 "firstName" => Some(&FIRST_NAME),
662 "lastName" => Some(&LAST_NAME),
663 "age" => Some(&AGE),
664 _ => None,
665 }
666 }
667 fn member_schema_by_index(&self, index: usize) -> Option<(&str, &dyn Schema)> {
668 match index {
669 0 => Some(("firstName", &FIRST_NAME)),
670 1 => Some(("lastName", &LAST_NAME)),
671 2 => Some(("age", &AGE)),
672 _ => None,
673 }
674 }
675 }
676
677 fn consume_person(
678 mut person: Person,
679 schema: &dyn Schema,
680 deser: &mut JsonDeserializer,
681 ) -> Result<Person, JsonDeserializerError> {
682 match schema.member_name() {
683 Some("firstName") => person.first_name = deser.read_string(schema)?,
684 Some("lastName") => person.last_name = deser.read_string(schema)?,
685 Some("age") => person.age = deser.read_integer(schema)?,
686 _ => {}
687 }
688 Ok(person)
689 }
690
691 let json = br#"{"lastName":"Smithy","firstName":"Alice","age":30}"#;
692 let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
693 let person = deser
694 .read_struct(&TestSchema, Person::default(), consume_person)
695 .unwrap();
696 assert_eq!(
697 person,
698 Person {
699 first_name: "Alice".to_string(),
700 last_name: "Smithy".to_string(),
701 age: 30
702 }
703 );
704
705 let json =
706 br#"{"firstName": "Alice","age":12345678, "lastName":"\"Smithy\""}"#;
707 let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
708 let person = deser
709 .read_struct(&TestSchema, Person::default(), consume_person)
710 .unwrap();
711 assert_eq!(
712 person,
713 Person {
714 first_name: "Alice".to_string(),
715 last_name: "\"Smithy\"".to_string(),
716 age: 12345678
717 }
718 );
719 }
720
721 #[test]
722 fn test_read_list() {
723 let json = b"[1, 2, 3, 4, 5]";
724 let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
725 let capacity = deser.container_size().unwrap_or(0);
726 let container = Vec::with_capacity(capacity);
727 let allocated_capacity = container.capacity();
728 let result = deser
729 .read_list(dummy_schema(), container, |mut vec, deser| {
730 vec.push(deser.read_integer(dummy_schema())?);
731 Ok(vec)
732 })
733 .unwrap();
734 assert_eq!(result, vec![1, 2, 3, 4, 5]);
735 assert_eq!(result.capacity(), allocated_capacity);
737
738 let json = b"[]";
739 let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
740 let capacity = deser.container_size().unwrap_or(0);
741 let container = Vec::with_capacity(capacity);
742 let allocated_capacity = container.capacity();
743 let result = deser
744 .read_list(dummy_schema(), container, |mut vec, deser| {
745 vec.push(deser.read_integer(dummy_schema())?);
746 Ok(vec)
747 })
748 .unwrap();
749 assert_eq!(result, Vec::<i32>::new());
750 assert_eq!(result.capacity(), allocated_capacity);
752
753 let json = br#"["hello", "world"]"#;
754 let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
755 let capacity = deser.container_size().unwrap_or(0);
756 let container = Vec::with_capacity(capacity);
757 let allocated_capacity = container.capacity();
758 let result = deser
759 .read_list(dummy_schema(), container, |mut vec, deser| {
760 vec.push(deser.read_string(dummy_schema())?);
761 Ok(vec)
762 })
763 .unwrap();
764 assert_eq!(result, vec!["hello", "world"]);
765 assert_eq!(result.capacity(), allocated_capacity);
767 }
768
769 #[test]
770 fn test_container_size() {
771 let deser = JsonDeserializer::new(b"[1, 2, 3, 4, 5]", JsonCodecSettings::default());
772 assert_eq!(deser.container_size(), Some(5));
773
774 let deser = JsonDeserializer::new(b"[]", JsonCodecSettings::default());
775 assert_eq!(deser.container_size(), Some(0));
776
777 let deser =
778 JsonDeserializer::new(br#"{"a": 1, "b": 2, "c": 3}"#, JsonCodecSettings::default());
779 assert_eq!(deser.container_size(), Some(3));
780
781 let deser = JsonDeserializer::new(b"{}", JsonCodecSettings::default());
782 assert_eq!(deser.container_size(), Some(0));
783
784 let deser =
785 JsonDeserializer::new(b"[[1, 2], [3, 4], [5, 6]]", JsonCodecSettings::default());
786 assert_eq!(deser.container_size(), Some(3));
787
788 let deser = JsonDeserializer::new(b"42", JsonCodecSettings::default());
789 assert_eq!(deser.container_size(), None);
790 }
791
792 #[test]
793 fn test_read_map() {
794 use std::collections::HashMap;
795
796 let json = br#"{"a": 1, "b": 2, "c": 3}"#;
797 let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
798 let calculated_capacity = deser.container_size().unwrap_or(0);
799 let container = HashMap::with_capacity(calculated_capacity);
800 let allocated_capacity = container.capacity();
801 let result = deser
802 .read_map(dummy_schema(), container, |mut map, key, deser| {
803 map.insert(key, deser.read_integer(dummy_schema())?);
804 Ok(map)
805 })
806 .unwrap();
807 assert_eq!(result.len(), 3);
808 assert_eq!(result.get("a"), Some(&1));
809 assert_eq!(result.get("b"), Some(&2));
810 assert_eq!(result.get("c"), Some(&3));
811 assert_eq!(result.capacity(), allocated_capacity);
813
814 let json = b"{}";
815 let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
816 let calculated_capacity = deser.container_size().unwrap_or(0);
817 let container = HashMap::with_capacity(calculated_capacity);
818 let allocated_capacity = container.capacity();
819 let result = deser
820 .read_map(dummy_schema(), container, |mut map, key, deser| {
821 map.insert(key, deser.read_integer(dummy_schema())?);
822 Ok(map)
823 })
824 .unwrap();
825 assert_eq!(result, HashMap::<String, i32>::new());
826 assert_eq!(result.capacity(), allocated_capacity);
828
829 let json = br#"{"name": "Alice", "city": "Seattle"}"#;
830 let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
831 let calculated_capacity = deser.container_size().unwrap_or(0);
832 let container = HashMap::with_capacity(calculated_capacity);
833 let allocated_capacity = container.capacity();
834 let result = deser
835 .read_map(dummy_schema(), container, |mut map, key, deser| {
836 map.insert(key, deser.read_string(dummy_schema())?);
837 Ok(map)
838 })
839 .unwrap();
840 assert_eq!(result.len(), 2);
841 assert_eq!(result.get("name"), Some(&"Alice".to_string()));
842 assert_eq!(result.get("city"), Some(&"Seattle".to_string()));
843 assert_eq!(result.capacity(), allocated_capacity);
845 }
846
847 #[test]
848 fn test_nested_complex_deserialization() {
849 use aws_smithy_schema::{prelude, Schema, ShapeId, ShapeType, TraitMap};
850 use std::collections::HashMap;
851
852 #[derive(Debug, Default, PartialEq)]
853 struct Address {
854 street: String,
855 city: String,
856 zip: i32,
857 }
858
859 #[derive(Debug, Default, PartialEq)]
860 struct Company {
861 name: String,
862 employees: Vec<String>,
863 metadata: HashMap<String, i32>,
864 active: bool,
865 }
866
867 #[derive(Debug, Default, PartialEq)]
868 struct User {
869 id: i64,
870 name: String,
871 scores: Vec<f64>,
872 address: Address,
873 companies: Vec<Company>,
874 tags: HashMap<String, String>,
875 }
876
877 struct MemberSchema {
878 name: &'static str,
879 target: &'static dyn Schema,
880 }
881
882 impl Schema for MemberSchema {
883 fn shape_id(&self) -> &ShapeId {
884 self.target.shape_id()
885 }
886 fn shape_type(&self) -> ShapeType {
887 self.target.shape_type()
888 }
889 fn traits(&self) -> &TraitMap {
890 self.target.traits()
891 }
892 fn member_name(&self) -> Option<&str> {
893 Some(self.name)
894 }
895 }
896
897 static ADDR_STREET: MemberSchema = MemberSchema {
898 name: "street",
899 target: &prelude::STRING,
900 };
901 static ADDR_CITY: MemberSchema = MemberSchema {
902 name: "city",
903 target: &prelude::STRING,
904 };
905 static ADDR_ZIP: MemberSchema = MemberSchema {
906 name: "zip",
907 target: &prelude::INTEGER,
908 };
909
910 struct AddressSchema;
911 impl Schema for AddressSchema {
912 fn shape_id(&self) -> &ShapeId {
913 static ID: std::sync::LazyLock<ShapeId> = std::sync::LazyLock::new(|| {
914 ShapeId::from_static("test#Address", "test", "Address")
915 });
916 &ID
917 }
918 fn shape_type(&self) -> ShapeType {
919 ShapeType::Structure
920 }
921 fn traits(&self) -> &TraitMap {
922 static MAP: std::sync::LazyLock<TraitMap> = std::sync::LazyLock::new(TraitMap::new);
923 &MAP
924 }
925 fn member_schema(&self, name: &str) -> Option<&dyn Schema> {
926 match name {
927 "street" => Some(&ADDR_STREET),
928 "city" => Some(&ADDR_CITY),
929 "zip" => Some(&ADDR_ZIP),
930 _ => None,
931 }
932 }
933 fn member_schema_by_index(&self, index: usize) -> Option<(&str, &dyn Schema)> {
934 match index {
935 0 => Some(("street", &ADDR_STREET)),
936 1 => Some(("city", &ADDR_CITY)),
937 2 => Some(("zip", &ADDR_ZIP)),
938 _ => None,
939 }
940 }
941 }
942
943 static COMP_NAME: MemberSchema = MemberSchema {
944 name: "name",
945 target: &prelude::STRING,
946 };
947 static COMP_ACTIVE: MemberSchema = MemberSchema {
948 name: "active",
949 target: &prelude::BOOLEAN,
950 };
951 static COMP_EMPLOYEES: MemberSchema = MemberSchema {
952 name: "employees",
953 target: &prelude::STRING,
954 };
955 static COMP_METADATA: MemberSchema = MemberSchema {
956 name: "metadata",
957 target: &prelude::STRING,
958 };
959
960 struct CompanySchema;
961 impl Schema for CompanySchema {
962 fn shape_id(&self) -> &ShapeId {
963 static ID: std::sync::LazyLock<ShapeId> = std::sync::LazyLock::new(|| {
964 ShapeId::from_static("test#Company", "test", "Company")
965 });
966 &ID
967 }
968 fn shape_type(&self) -> ShapeType {
969 ShapeType::Structure
970 }
971 fn traits(&self) -> &TraitMap {
972 static MAP: std::sync::LazyLock<TraitMap> = std::sync::LazyLock::new(TraitMap::new);
973 &MAP
974 }
975 fn member_schema(&self, name: &str) -> Option<&dyn Schema> {
976 match name {
977 "name" => Some(&COMP_NAME),
978 "active" => Some(&COMP_ACTIVE),
979 "employees" => Some(&COMP_EMPLOYEES),
980 "metadata" => Some(&COMP_METADATA),
981 _ => None,
982 }
983 }
984 fn member_schema_by_index(&self, index: usize) -> Option<(&str, &dyn Schema)> {
985 match index {
986 0 => Some(("name", &COMP_NAME)),
987 1 => Some(("active", &COMP_ACTIVE)),
988 _ => None,
989 }
990 }
991 }
992
993 static USER_ID: MemberSchema = MemberSchema {
994 name: "id",
995 target: &prelude::LONG,
996 };
997 static USER_NAME: MemberSchema = MemberSchema {
998 name: "name",
999 target: &prelude::STRING,
1000 };
1001 static USER_SCORES: MemberSchema = MemberSchema {
1002 name: "scores",
1003 target: &prelude::STRING,
1004 };
1005 static USER_ADDRESS: MemberSchema = MemberSchema {
1006 name: "address",
1007 target: &prelude::STRING,
1008 };
1009 static USER_COMPANIES: MemberSchema = MemberSchema {
1010 name: "companies",
1011 target: &prelude::STRING,
1012 };
1013 static USER_TAGS: MemberSchema = MemberSchema {
1014 name: "tags",
1015 target: &prelude::STRING,
1016 };
1017
1018 struct UserSchema;
1019 impl Schema for UserSchema {
1020 fn shape_id(&self) -> &ShapeId {
1021 static ID: std::sync::LazyLock<ShapeId> =
1022 std::sync::LazyLock::new(|| ShapeId::from_static("test#User", "test", "User"));
1023 &ID
1024 }
1025 fn shape_type(&self) -> ShapeType {
1026 ShapeType::Structure
1027 }
1028 fn traits(&self) -> &TraitMap {
1029 static MAP: std::sync::LazyLock<TraitMap> = std::sync::LazyLock::new(TraitMap::new);
1030 &MAP
1031 }
1032 fn member_schema(&self, name: &str) -> Option<&dyn Schema> {
1033 match name {
1034 "id" => Some(&USER_ID),
1035 "name" => Some(&USER_NAME),
1036 "scores" => Some(&USER_SCORES),
1037 "address" => Some(&USER_ADDRESS),
1038 "companies" => Some(&USER_COMPANIES),
1039 "tags" => Some(&USER_TAGS),
1040 _ => None,
1041 }
1042 }
1043 fn member_schema_by_index(&self, index: usize) -> Option<(&str, &dyn Schema)> {
1044 match index {
1045 0 => Some(("id", &USER_ID)),
1046 1 => Some(("name", &USER_NAME)),
1047 _ => None,
1048 }
1049 }
1050 }
1051
1052 fn consume_address(
1053 mut addr: Address,
1054 schema: &dyn Schema,
1055 deser: &mut JsonDeserializer,
1056 ) -> Result<Address, JsonDeserializerError> {
1057 match schema.member_name() {
1058 Some("street") => addr.street = deser.read_string(schema)?,
1059 Some("city") => addr.city = deser.read_string(schema)?,
1060 Some("zip") => addr.zip = deser.read_integer(schema)?,
1061 _ => {}
1062 }
1063 Ok(addr)
1064 }
1065
1066 fn consume_company(
1067 mut comp: Company,
1068 schema: &dyn Schema,
1069 deser: &mut JsonDeserializer,
1070 ) -> Result<Company, JsonDeserializerError> {
1071 match schema.member_name() {
1072 Some("name") => comp.name = deser.read_string(schema)?,
1073 Some("active") => comp.active = deser.read_boolean(schema)?,
1074 Some("employees") => {
1075 comp.employees = deser.read_list(schema, Vec::new(), |mut v, d| {
1076 v.push(d.read_string(dummy_schema())?);
1077 Ok(v)
1078 })?
1079 }
1080 Some("metadata") => {
1081 comp.metadata = deser.read_map(schema, HashMap::new(), |mut m, k, d| {
1082 m.insert(k, d.read_integer(dummy_schema())?);
1083 Ok(m)
1084 })?
1085 }
1086 _ => {}
1087 }
1088 Ok(comp)
1089 }
1090
1091 fn consume_user(
1092 mut user: User,
1093 schema: &dyn Schema,
1094 deser: &mut JsonDeserializer,
1095 ) -> Result<User, JsonDeserializerError> {
1096 match schema.member_name() {
1097 Some("id") => user.id = deser.read_long(schema)?,
1098 Some("name") => user.name = deser.read_string(schema)?,
1099 Some("scores") => {
1100 user.scores = deser.read_list(schema, Vec::new(), |mut v, d| {
1101 v.push(d.read_double(dummy_schema())?);
1102 Ok(v)
1103 })?
1104 }
1105 Some("address") => {
1106 user.address =
1107 deser.read_struct(&AddressSchema, Address::default(), consume_address)?
1108 }
1109 Some("companies") => {
1110 user.companies = deser.read_list(schema, Vec::new(), |mut v, d| {
1111 v.push(d.read_struct(
1112 &CompanySchema,
1113 Company::default(),
1114 consume_company,
1115 )?);
1116 Ok(v)
1117 })?
1118 }
1119 Some("tags") => {
1120 user.tags = deser.read_map(schema, HashMap::new(), |mut m, k, d| {
1121 m.insert(k, d.read_string(dummy_schema())?);
1122 Ok(m)
1123 })?
1124 }
1125 _ => {}
1126 }
1127 Ok(user)
1128 }
1129
1130 let json = br#"{
1131 "id": 12345,
1132 "name": "John Doe",
1133 "scores": [95.5, 87.3, 92.1],
1134 "address": {
1135 "street": "123 Main St",
1136 "city": "Seattle",
1137 "zip": 98101
1138 },
1139 "companies": [
1140 {
1141 "name": "TechCorp",
1142 "employees": ["Alice", "Bob"],
1143 "metadata": {"founded": 2010, "size": 500},
1144 "active": true
1145 },
1146 {
1147 "name": "StartupInc",
1148 "employees": ["Charlie"],
1149 "metadata": {"founded": 2020},
1150 "active": false
1151 }
1152 ],
1153 "tags": {"role": "admin", "level": "senior"}
1154 }"#;
1155
1156 let mut deser = JsonDeserializer::new(json, JsonCodecSettings::default());
1157 let user = deser
1158 .read_struct(&UserSchema, User::default(), consume_user)
1159 .unwrap();
1160
1161 assert_eq!(user.id, 12345);
1162 assert_eq!(user.name, "John Doe");
1163 assert_eq!(user.scores, vec![95.5, 87.3, 92.1]);
1164 assert_eq!(user.address.street, "123 Main St");
1165 assert_eq!(user.address.city, "Seattle");
1166 assert_eq!(user.address.zip, 98101);
1167 assert_eq!(user.companies.len(), 2);
1168 assert_eq!(user.companies[0].name, "TechCorp");
1169 assert_eq!(user.companies[0].employees, vec!["Alice", "Bob"]);
1170 assert_eq!(user.companies[0].metadata.get("founded"), Some(&2010));
1171 assert_eq!(user.companies[0].metadata.get("size"), Some(&500));
1172 assert_eq!(user.companies[0].active, true);
1173 assert_eq!(user.companies[1].name, "StartupInc");
1174 assert_eq!(user.companies[1].employees, vec!["Charlie"]);
1175 assert_eq!(user.companies[1].metadata.get("founded"), Some(&2020));
1176 assert_eq!(user.companies[1].active, false);
1177 assert_eq!(user.tags.get("role"), Some(&"admin".to_string()));
1178 assert_eq!(user.tags.get("level"), Some(&"senior".to_string()));
1179 }
1180}