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