1use aws_smithy_schema::serde::{capped_container_size, SerdeError, ShapeDeserializer};
9use aws_smithy_schema::{Schema, ShapeType};
10use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime, Document};
11
12use crate::data::Type;
13
14pub struct CborDeserializer<'a> {
20 decoder: crate::Decoder<'a>,
21 input_len: usize,
22 depth: u32,
23 max_depth: u32,
24 enforce_strictness: bool,
25}
26
27impl<'a> CborDeserializer<'a> {
28 pub(crate) fn new(input: &'a [u8], max_depth: u32) -> Self {
29 Self {
30 decoder: crate::Decoder::new(input),
31 input_len: input.len(),
32 depth: 0,
33 max_depth,
34 enforce_strictness: false,
35 }
36 }
37
38 pub fn position(&self) -> usize {
42 self.decoder.position()
43 }
44
45 pub(crate) fn with_strictness(mut self, value: bool) -> Self {
46 self.enforce_strictness = value;
47 self
48 }
49
50 fn leave_container(&mut self) -> Result<(), SerdeError> {
51 self.depth -= 1;
52 if self.enforce_strictness && self.depth == 0 && self.decoder.position() != self.input_len {
53 return Err(SerdeError::invalid_input("trailing bytes after CBOR value"));
54 }
55 Ok(())
56 }
57
58 fn prealloc(declared: u64, remaining: usize, min_bytes_per_element: usize) -> usize {
63 let declared = usize::try_from(declared).unwrap_or(usize::MAX);
64 capped_container_size(declared.min(remaining / min_bytes_per_element))
65 }
66
67 fn remaining(&self) -> usize {
68 self.input_len.saturating_sub(self.decoder.position())
69 }
70
71 fn check_depth(&mut self) -> Result<(), SerdeError> {
72 self.depth += 1;
73 if self.depth > self.max_depth {
74 return Err(SerdeError::custom("maximum nesting depth exceeded"));
75 }
76 Ok(())
77 }
78
79 fn is_break(&self) -> bool {
81 matches!(self.decoder.datatype(), Ok(Type::Break))
82 }
83
84 fn consume_break(&mut self) -> Result<(), SerdeError> {
86 self.decoder.skip().map_err(deser_err)
87 }
88
89 fn read_list_items<T>(
92 &mut self,
93 mut read_element: impl FnMut(&mut crate::Decoder<'_>) -> Result<T, SerdeError>,
94 ) -> Result<Vec<T>, SerdeError> {
95 self.check_depth()?;
96 let len = self.decoder.list().map_err(deser_err)?;
97 let is_indefinite = len.is_none();
98 let count = len.unwrap_or(0) as usize;
99 let mut out = Vec::with_capacity(Self::prealloc(len.unwrap_or(0), self.remaining(), 1));
100 let mut i = 0;
101 loop {
102 if !is_indefinite && i >= count {
103 break;
104 }
105 if is_indefinite && self.is_break() {
106 self.consume_break()?;
107 break;
108 }
109 out.push(read_element(&mut self.decoder)?);
110 i += 1;
111 }
112 self.leave_container()?;
113 Ok(out)
114 }
115}
116
117impl ShapeDeserializer for CborDeserializer<'_> {
118 fn read_struct(
119 &mut self,
120 schema: &Schema<'_>,
121 consumer: &mut dyn FnMut(&Schema<'_>, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
122 ) -> Result<(), SerdeError> {
123 if self.decoder.position() >= self.input_len {
125 if self.enforce_strictness && self.depth != 0 {
126 return Err(SerdeError::invalid_input("truncated CBOR structure"));
127 }
128 return Ok(());
129 }
130 self.check_depth()?;
131 let len = self.decoder.map().map_err(deser_err)?;
132 let is_indefinite = len.is_none();
133 let count = len.unwrap_or(0) as usize;
134
135 let is_union = schema.shape_type() == ShapeType::Union;
136 let mut i = 0;
137 loop {
138 if !is_indefinite && i >= count {
139 break;
140 }
141 if is_indefinite && self.is_break() {
142 self.consume_break()?;
143 break;
144 }
145 let key = self.decoder.str().map_err(deser_err)?;
146 if self.enforce_strictness && !is_union && self.is_null() {
147 self.read_null()?;
152 } else if let Some(member_schema) = schema.member_schema(&key) {
153 consumer(member_schema, self)?;
154 } else if &*key == "__type" || self.is_null() {
155 self.decoder.skip().map_err(deser_err)?;
158 } else {
159 let start = self.decoder.position();
164 consumer(&aws_smithy_schema::prelude::DOCUMENT, self)?;
165 if self.decoder.position() == start {
166 self.decoder.skip().map_err(deser_err)?;
167 }
168 }
169 i += 1;
170 }
171 self.leave_container()?;
172 Ok(())
173 }
174
175 fn read_list(
176 &mut self,
177 _schema: &Schema<'_>,
178 consumer: &mut dyn FnMut(&mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
179 ) -> Result<(), SerdeError> {
180 self.check_depth()?;
181 let len = self.decoder.list().map_err(deser_err)?;
182 let is_indefinite = len.is_none();
183 let count = len.unwrap_or(0) as usize;
184
185 let mut i = 0;
186 loop {
187 if !is_indefinite && i >= count {
188 break;
189 }
190 if is_indefinite && self.is_break() {
191 self.consume_break()?;
192 break;
193 }
194 consumer(self)?;
195 i += 1;
196 }
197 self.leave_container()?;
198 Ok(())
199 }
200
201 fn read_map(
202 &mut self,
203 _schema: &Schema<'_>,
204 consumer: &mut dyn FnMut(String, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
205 ) -> Result<(), SerdeError> {
206 self.check_depth()?;
207 let len = self.decoder.map().map_err(deser_err)?;
208 let is_indefinite = len.is_none();
209 let count = len.unwrap_or(0) as usize;
210
211 let mut i = 0;
212 loop {
213 if !is_indefinite && i >= count {
214 break;
215 }
216 if is_indefinite && self.is_break() {
217 self.consume_break()?;
218 break;
219 }
220 let key = self.decoder.str().map_err(deser_err)?.into_owned();
221 consumer(key, self)?;
222 i += 1;
223 }
224 self.leave_container()?;
225 Ok(())
226 }
227
228 fn read_boolean(&mut self, _schema: &Schema<'_>) -> Result<bool, SerdeError> {
229 self.decoder.boolean().map_err(deser_err)
230 }
231
232 fn read_byte(&mut self, _schema: &Schema<'_>) -> Result<i8, SerdeError> {
233 self.decoder.byte().map_err(deser_err)
234 }
235
236 fn read_short(&mut self, _schema: &Schema<'_>) -> Result<i16, SerdeError> {
237 self.decoder.short().map_err(deser_err)
238 }
239
240 fn read_integer(&mut self, _schema: &Schema<'_>) -> Result<i32, SerdeError> {
241 self.decoder.integer().map_err(deser_err)
242 }
243
244 fn read_long(&mut self, _schema: &Schema<'_>) -> Result<i64, SerdeError> {
245 self.decoder.long().map_err(deser_err)
246 }
247
248 fn read_float(&mut self, _schema: &Schema<'_>) -> Result<f32, SerdeError> {
249 self.decoder.float().map_err(deser_err)
250 }
251
252 fn read_double(&mut self, _schema: &Schema<'_>) -> Result<f64, SerdeError> {
253 self.decoder.double().map_err(deser_err)
254 }
255
256 fn read_big_integer(&mut self, _schema: &Schema<'_>) -> Result<BigInteger, SerdeError> {
257 self.decoder.big_integer().map_err(deser_err)
258 }
259
260 fn read_big_decimal(&mut self, _schema: &Schema<'_>) -> Result<BigDecimal, SerdeError> {
261 self.decoder.big_decimal().map_err(deser_err)
262 }
263
264 fn read_string(&mut self, _schema: &Schema<'_>) -> Result<String, SerdeError> {
265 self.decoder
266 .str()
267 .map(|cow| cow.into_owned())
268 .map_err(deser_err)
269 }
270
271 fn read_blob(&mut self, _schema: &Schema<'_>) -> Result<Blob, SerdeError> {
272 self.decoder.blob().map_err(deser_err)
273 }
274
275 fn read_timestamp(&mut self, _schema: &Schema<'_>) -> Result<DateTime, SerdeError> {
276 self.decoder.timestamp().map_err(deser_err)
277 }
278
279 fn read_document(&mut self, _schema: &Schema<'_>) -> Result<Document, SerdeError> {
280 Err(SerdeError::unsupported(
281 "document types are not supported by rpcv2Cbor protocol",
282 ))
283 }
284
285 fn is_null(&self) -> bool {
286 matches!(self.decoder.datatype(), Ok(Type::Null))
287 }
288
289 fn read_null(&mut self) -> Result<(), SerdeError> {
290 self.decoder.null().map_err(deser_err)
291 }
292
293 fn skip_value(&mut self) -> Result<(), SerdeError> {
297 self.decoder.skip().map_err(deser_err)
298 }
299
300 fn container_size(&self) -> Option<usize> {
301 let mut peek = self.decoder.clone();
302 match peek.datatype().ok()? {
303 Type::Array | Type::ArrayIndef => peek.list().ok()?.map(|n| {
304 let remaining = self.input_len.saturating_sub(peek.position());
305 Self::prealloc(n, remaining, 1)
306 }),
307 Type::Map | Type::MapIndef => peek.map().ok()?.map(|n| {
308 let remaining = self.input_len.saturating_sub(peek.position());
309 Self::prealloc(n, remaining, 2)
310 }),
311 _ => None,
312 }
313 }
314
315 fn read_string_list(&mut self, _schema: &Schema<'_>) -> Result<Vec<String>, SerdeError> {
316 self.read_list_items(|dec| dec.str().map(|c| c.into_owned()).map_err(deser_err))
317 }
318
319 fn read_blob_list(&mut self, _schema: &Schema<'_>) -> Result<Vec<Blob>, SerdeError> {
320 self.read_list_items(|dec| dec.blob().map_err(deser_err))
321 }
322
323 fn read_integer_list(&mut self, _schema: &Schema<'_>) -> Result<Vec<i32>, SerdeError> {
324 self.read_list_items(|dec| dec.integer().map_err(deser_err))
325 }
326
327 fn read_long_list(&mut self, _schema: &Schema<'_>) -> Result<Vec<i64>, SerdeError> {
328 self.read_list_items(|dec| dec.long().map_err(deser_err))
329 }
330
331 fn read_string_string_map(
332 &mut self,
333 _schema: &Schema<'_>,
334 ) -> Result<std::collections::HashMap<String, String>, SerdeError> {
335 self.check_depth()?;
336 let len = self.decoder.map().map_err(deser_err)?;
337 let is_indefinite = len.is_none();
338 let count = len.unwrap_or(0) as usize;
339 let mut out = std::collections::HashMap::with_capacity(Self::prealloc(
340 len.unwrap_or(0),
341 self.remaining(),
342 2,
344 ));
345 let mut i = 0;
346 loop {
347 if !is_indefinite && i >= count {
348 break;
349 }
350 if is_indefinite && self.is_break() {
351 self.consume_break()?;
352 break;
353 }
354 let key = self
355 .decoder
356 .str()
357 .map(|c| c.into_owned())
358 .map_err(deser_err)?;
359 let val = self
360 .decoder
361 .str()
362 .map(|c| c.into_owned())
363 .map_err(deser_err)?;
364 out.insert(key, val);
365 i += 1;
366 }
367 self.leave_container()?;
368 Ok(out)
369 }
370}
371
372fn deser_err(e: crate::decode::DeserializeError) -> SerdeError {
373 SerdeError::invalid_input(e.to_string())
374}
375
376#[cfg(test)]
377mod tests {
378 use super::*;
379 use aws_smithy_schema::codec::Codec;
380 use aws_smithy_schema::prelude::*;
381 use aws_smithy_schema::serde::{SerializableStruct, ShapeSerializer};
382 use aws_smithy_schema::{shape_id, ShapeType};
383
384 use crate::codec::{CborCodec, CborCodecSettings};
385
386 fn make_deser(f: impl FnOnce(&mut crate::codec::CborSerializer)) -> Vec<u8> {
388 use aws_smithy_schema::codec::FinishSerializer;
389 let codec = CborCodec::default();
390 let mut ser = codec.create_serializer();
391 f(&mut ser);
392 ser.finish()
393 }
394
395 #[test]
396 fn strict_null_struct_members_are_skipped_as_absent() {
397 static X: Schema =
398 Schema::new_member(shape_id!("test", "S", "x"), ShapeType::Integer, "x", 0);
399 static S: Schema = Schema::new_struct(shape_id!("test", "S"), ShapeType::Structure, &[&X]);
400 for strict in [false, true] {
401 let codec = CborCodec::new(CborCodecSettings::default().enforce_strictness(strict));
402 let mut visited = false;
406 let result = codec.create_deserializer(b"\xa1\x61x\xf6").read_struct(
407 &S,
408 &mut |member, deser| {
409 visited = true;
410 deser.read_integer(member).map(|_| ())
411 },
412 );
413 assert_eq!(result.is_ok(), strict);
414 assert_eq!(visited, !strict);
415 }
416 }
417
418 #[test]
419 fn strict_top_level_containers() {
420 for input in [
421 vec![0xa0],
422 vec![0xbf, 0xff],
423 vec![0xa1, 0x61, b'x', 0x81, 0xa0],
424 vec![0xbf, 0x61, b'x', 0x9f, 0xbf, 0xff, 0xff, 0xff],
425 ] {
426 for strict in [false, true] {
427 let mut de = CborDeserializer::new(&input, 128).with_strictness(strict);
428 de.read_struct(&STRING, &mut |_, _| Ok(())).unwrap();
429 let mut trailing = input.clone();
430 trailing.push(0);
431 let mut de = CborDeserializer::new(&trailing, 128).with_strictness(strict);
432 assert_eq!(de.read_struct(&STRING, &mut |_, _| Ok(())).is_err(), strict);
433 }
434 }
435 }
436
437 #[test]
440 fn container_preallocation_is_bounded_by_remaining_input() {
441 for (header, element_bytes) in [(0x9bu8, 1usize), (0xbb, 2)] {
443 let mut bytes = vec![header];
444 bytes.extend_from_slice(&u64::MAX.to_be_bytes());
445 let de = CborDeserializer::new(&bytes, 128);
446 assert_eq!(de.container_size(), Some(0), "header {header:#x}");
447 bytes.extend_from_slice(&[0u8; 10]);
449 let de = CborDeserializer::new(&bytes, 128);
450 assert_eq!(
451 de.container_size(),
452 Some(10 / element_bytes),
453 "header {header:#x}"
454 );
455 }
456 let mut enc = crate::Encoder::new(Vec::new());
458 enc.array(3);
459 for i in 0..3 {
460 enc.integer(i);
461 }
462 let bytes = enc.into_writer();
463 let de = CborDeserializer::new(&bytes, 128);
464 assert_eq!(de.container_size(), Some(3));
465 let mut truncated = vec![0x9b];
467 truncated.extend_from_slice(&u64::MAX.to_be_bytes());
468 let mut de = CborDeserializer::new(&truncated, 128);
469 assert!(de.read_integer_list(&INTEGER).is_err());
470 assert_eq!(CborDeserializer::prealloc(u64::MAX, usize::MAX, 1), 10_000);
471 }
472
473 #[test]
474 fn test_read_boolean() {
475 let bytes = make_deser(|s| s.write_boolean(&BOOLEAN, true).unwrap());
476 let mut de = CborDeserializer::new(&bytes, 128);
477 assert!(de.read_boolean(&BOOLEAN).unwrap());
478 }
479
480 #[test]
481 fn test_read_byte() {
482 let bytes = make_deser(|s| s.write_byte(&BYTE, -42).unwrap());
483 let mut de = CborDeserializer::new(&bytes, 128);
484 assert_eq!(de.read_byte(&BYTE).unwrap(), -42);
485 }
486
487 #[test]
488 fn test_read_short() {
489 let bytes = make_deser(|s| s.write_short(&SHORT, 1234).unwrap());
490 let mut de = CborDeserializer::new(&bytes, 128);
491 assert_eq!(de.read_short(&SHORT).unwrap(), 1234);
492 }
493
494 #[test]
495 fn test_read_integer() {
496 let bytes = make_deser(|s| s.write_integer(&INTEGER, -99999).unwrap());
497 let mut de = CborDeserializer::new(&bytes, 128);
498 assert_eq!(de.read_integer(&INTEGER).unwrap(), -99999);
499 }
500
501 #[test]
502 fn test_read_long() {
503 let bytes = make_deser(|s| s.write_long(&LONG, i64::MIN).unwrap());
504 let mut de = CborDeserializer::new(&bytes, 128);
505 assert_eq!(de.read_long(&LONG).unwrap(), i64::MIN);
506 }
507
508 #[test]
509 fn test_read_float_nan() {
510 let bytes = make_deser(|s| s.write_float(&FLOAT, f32::NAN).unwrap());
511 let mut de = CborDeserializer::new(&bytes, 128);
512 assert!(de.read_float(&FLOAT).unwrap().is_nan());
513 }
514
515 #[test]
516 fn test_read_double_neg_infinity() {
517 let bytes = make_deser(|s| s.write_double(&DOUBLE, f64::NEG_INFINITY).unwrap());
518 let mut de = CborDeserializer::new(&bytes, 128);
519 assert_eq!(de.read_double(&DOUBLE).unwrap(), f64::NEG_INFINITY);
520 }
521
522 #[test]
523 fn test_read_big_integer() {
524 let value = "18446744073709551616".parse().unwrap();
525 let bytes = make_deser(|s| s.write_big_integer(&BIG_INTEGER, &value).unwrap());
526 let mut de = CborDeserializer::new(&bytes, 128);
527 assert_eq!(de.read_big_integer(&BIG_INTEGER).unwrap(), value);
528 }
529
530 #[test]
531 fn test_read_big_decimal() {
532 let value = "273.15".parse().unwrap();
533 let bytes = make_deser(|s| s.write_big_decimal(&BIG_DECIMAL, &value).unwrap());
534 let mut de = CborDeserializer::new(&bytes, 128);
535 assert_eq!(de.read_big_decimal(&BIG_DECIMAL).unwrap(), value);
536 }
537
538 #[test]
539 fn test_read_string() {
540 let bytes = make_deser(|s| s.write_string(&STRING, "hello world").unwrap());
541 let mut de = CborDeserializer::new(&bytes, 128);
542 assert_eq!(de.read_string(&STRING).unwrap(), "hello world");
543 }
544
545 #[test]
546 fn test_read_blob() {
547 let blob = Blob::new(b"binary");
548 let bytes = make_deser(|s| s.write_blob(&BLOB, blob.clone()).unwrap());
549 let mut de = CborDeserializer::new(&bytes, 128);
550 assert_eq!(de.read_blob(&BLOB).unwrap(), blob);
551 }
552
553 #[test]
554 fn test_read_timestamp() {
555 let ts = DateTime::from_secs_f64(1700000000.123);
556 let bytes = make_deser(|s| s.write_timestamp(&TIMESTAMP, &ts).unwrap());
557 let mut de = CborDeserializer::new(&bytes, 128);
558 let decoded = de.read_timestamp(&TIMESTAMP).unwrap();
559 assert_eq!(decoded.subsec_nanos() % 1_000_000, 0);
561 }
562
563 #[test]
564 fn test_is_null() {
565 let bytes = make_deser(|s| s.write_null(&STRING).unwrap());
566 let de = CborDeserializer::new(&bytes, 128);
567 assert!(de.is_null());
568 }
569
570 #[test]
571 fn test_read_null() {
572 let bytes = make_deser(|s| s.write_null(&STRING).unwrap());
573 let mut de = CborDeserializer::new(&bytes, 128);
574 de.read_null().unwrap();
575 }
576
577 #[test]
578 fn test_read_struct() {
579 static NAME: Schema =
580 Schema::new_member(shape_id!("test", "S"), ShapeType::String, "name", 0);
581 static AGE: Schema =
582 Schema::new_member(shape_id!("test", "S"), ShapeType::Integer, "age", 1);
583 static SCHEMA: Schema =
584 Schema::new_struct(shape_id!("test", "S"), ShapeType::Structure, &[&NAME, &AGE]);
585
586 struct TestStruct;
587 impl SerializableStruct for TestStruct {
588 fn schema(&self) -> &Schema<'_> {
589 &SCHEMA
590 }
591
592 fn serialize_members(&self, s: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
593 s.write_string(&NAME, "Bob")?;
594 s.write_integer(&AGE, 25)?;
595 Ok(())
596 }
597 }
598
599 let bytes = make_deser(|s| s.write_struct(&SCHEMA, &TestStruct).unwrap());
600 let mut de = CborDeserializer::new(&bytes, 128);
601 let mut name = String::new();
602 let mut age = 0i32;
603 de.read_struct(&SCHEMA, &mut |member, d| {
604 match member.member_name() {
605 Some("name") => name = d.read_string(member)?,
606 Some("age") => age = d.read_integer(member)?,
607 _ => {}
608 }
609 Ok(())
610 })
611 .unwrap();
612 assert_eq!(name, "Bob");
613 assert_eq!(age, 25);
614 }
615
616 #[test]
617 fn test_read_struct_unknown_members_skipped() {
618 let mut enc = crate::Encoder::new(Vec::new());
620 enc.begin_map()
621 .str("name")
622 .str("Alice")
623 .str("unknown_field")
624 .integer(999)
625 .str("age")
626 .integer(30)
627 .end();
628 let bytes = enc.into_writer();
629
630 static NAME: Schema =
631 Schema::new_member(shape_id!("test", "S"), ShapeType::String, "name", 0);
632 static AGE: Schema =
633 Schema::new_member(shape_id!("test", "S"), ShapeType::Integer, "age", 1);
634 static SCHEMA: Schema =
635 Schema::new_struct(shape_id!("test", "S"), ShapeType::Structure, &[&NAME, &AGE]);
636
637 let mut de = CborDeserializer::new(&bytes, 128);
638 let mut name = String::new();
639 let mut age = 0i32;
640 de.read_struct(&SCHEMA, &mut |member, d| {
641 match member.member_name() {
642 Some("name") => name = d.read_string(member)?,
643 Some("age") => age = d.read_integer(member)?,
644 _ => {}
645 }
646 Ok(())
647 })
648 .unwrap();
649 assert_eq!(name, "Alice");
650 assert_eq!(age, 30);
651 }
652
653 #[test]
654 fn test_read_struct_definite_length_map() {
655 let mut enc = crate::Encoder::new(Vec::new());
657 enc.map(1).str("name").str("Charlie");
658 let bytes = enc.into_writer();
659
660 static NAME: Schema =
661 Schema::new_member(shape_id!("test", "S"), ShapeType::String, "name", 0);
662 static SCHEMA: Schema =
663 Schema::new_struct(shape_id!("test", "S"), ShapeType::Structure, &[&NAME]);
664
665 let mut de = CborDeserializer::new(&bytes, 128);
666 let mut name = String::new();
667 de.read_struct(&SCHEMA, &mut |member, d| {
668 if member.member_name() == Some("name") {
669 name = d.read_string(member)?;
670 }
671 Ok(())
672 })
673 .unwrap();
674 assert_eq!(name, "Charlie");
675 }
676
677 #[test]
678 fn test_read_list() {
679 let bytes = make_deser(|s| {
680 let schema = Schema::new(shape_id!("test", "L"), ShapeType::List);
681 s.write_list(&schema, &|s| {
682 s.write_integer(&INTEGER, 10)?;
683 s.write_integer(&INTEGER, 20)?;
684 Ok(())
685 })
686 .unwrap()
687 });
688 let list_schema = Schema::new(shape_id!("test", "L"), ShapeType::List);
689 let mut de = CborDeserializer::new(&bytes, 128);
690 let mut items = Vec::new();
691 de.read_list(&list_schema, &mut |d| {
692 items.push(d.read_integer(&INTEGER)?);
693 Ok(())
694 })
695 .unwrap();
696 assert_eq!(items, vec![10, 20]);
697 }
698
699 #[test]
700 fn test_read_map() {
701 let bytes = make_deser(|s| {
702 let schema = Schema::new(shape_id!("test", "M"), ShapeType::Map);
703 s.write_map(&schema, &|s| {
704 s.write_string(&STRING, "k1")?;
705 s.write_string(&STRING, "v1")?;
706 s.write_string(&STRING, "k2")?;
707 s.write_string(&STRING, "v2")?;
708 Ok(())
709 })
710 .unwrap()
711 });
712 let map_schema = Schema::new(shape_id!("test", "M"), ShapeType::Map);
713 let mut de = CborDeserializer::new(&bytes, 128);
714 let mut map = std::collections::HashMap::new();
715 de.read_map(&map_schema, &mut |key, d| {
716 map.insert(key, d.read_string(&STRING)?);
717 Ok(())
718 })
719 .unwrap();
720 assert_eq!(map.get("k1").unwrap(), "v1");
721 assert_eq!(map.get("k2").unwrap(), "v2");
722 }
723
724 #[test]
725 fn test_empty_input_treated_as_empty_struct() {
726 static SCHEMA: Schema =
727 Schema::new_struct(shape_id!("test", "S"), ShapeType::Structure, &[]);
728 let mut de = CborDeserializer::new(&[], 128);
729 de.read_struct(&SCHEMA, &mut |_, _| Ok(())).unwrap();
730 }
731
732 #[test]
733 fn test_container_size_definite() {
734 let mut enc = crate::Encoder::new(Vec::new());
735 enc.array(5);
736 for i in 0..5 {
737 enc.integer(i);
738 }
739 let bytes = enc.into_writer();
740 let de = CborDeserializer::new(&bytes, 128);
741 assert_eq!(de.container_size(), Some(5));
742 }
743
744 #[test]
745 fn test_container_size_indefinite_returns_none() {
746 let mut enc = crate::Encoder::new(Vec::new());
747 enc.begin_array();
748 let bytes = enc.into_writer();
749 let de = CborDeserializer::new(&bytes, 128);
750 assert_eq!(de.container_size(), None);
751 }
752
753 #[test]
754 fn test_depth_limit_rejects_deeply_nested() {
755 let mut enc = crate::Encoder::new(Vec::new());
757 for _ in 0..200 {
758 enc.begin_map().str("a");
759 }
760 enc.begin_map().end(); for _ in 0..200 {
762 enc.end();
763 }
764 let bytes = enc.into_writer();
765
766 static MEMBER: Schema =
767 Schema::new_member(shape_id!("test", "R"), ShapeType::Structure, "a", 0);
768 static SCHEMA: Schema =
769 Schema::new_struct(shape_id!("test", "R"), ShapeType::Structure, &[&MEMBER]);
770
771 let mut de = CborDeserializer::new(&bytes, 128);
772 fn recursive_consumer(
773 _member: &Schema<'_>,
774 deser: &mut dyn ShapeDeserializer,
775 ) -> Result<(), SerdeError> {
776 static MEMBER: Schema =
777 Schema::new_member(shape_id!("test", "R"), ShapeType::Structure, "a", 0);
778 static SCHEMA: Schema =
779 Schema::new_struct(shape_id!("test", "R"), ShapeType::Structure, &[&MEMBER]);
780 deser.read_struct(&SCHEMA, &mut recursive_consumer)
781 }
782 let result = de.read_struct(&SCHEMA, &mut recursive_consumer);
783 assert!(result.is_err());
784 assert!(result.unwrap_err().to_string().contains("depth"));
785 }
786
787 #[test]
788 fn test_depth_limit_accepts_under_limit() {
789 let mut enc = crate::Encoder::new(Vec::new());
791 for _ in 0..10 {
792 enc.begin_map().str("a");
793 }
794 enc.begin_map().end();
795 for _ in 0..10 {
796 enc.end();
797 }
798 let bytes = enc.into_writer();
799
800 static MEMBER: Schema =
801 Schema::new_member(shape_id!("test", "R"), ShapeType::Structure, "a", 0);
802 static SCHEMA: Schema =
803 Schema::new_struct(shape_id!("test", "R"), ShapeType::Structure, &[&MEMBER]);
804
805 let mut de = CborDeserializer::new(&bytes, 128);
806 fn recursive_consumer(
807 _member: &Schema<'_>,
808 deser: &mut dyn ShapeDeserializer,
809 ) -> Result<(), SerdeError> {
810 static MEMBER: Schema =
811 Schema::new_member(shape_id!("test", "R"), ShapeType::Structure, "a", 0);
812 static SCHEMA: Schema =
813 Schema::new_struct(shape_id!("test", "R"), ShapeType::Structure, &[&MEMBER]);
814 deser.read_struct(&SCHEMA, &mut recursive_consumer)
815 }
816 de.read_struct(&SCHEMA, &mut recursive_consumer).unwrap();
817 }
818
819 #[test]
820 fn test_read_struct_with_null_optional_members() {
821 let mut enc = crate::Encoder::new(Vec::new());
823 enc.begin_map()
824 .str("name")
825 .str("Alice")
826 .str("age")
827 .null()
828 .end();
829 let bytes = enc.into_writer();
830
831 static NAME: Schema =
832 Schema::new_member(shape_id!("test", "S"), ShapeType::String, "name", 0);
833 static AGE: Schema =
834 Schema::new_member(shape_id!("test", "S"), ShapeType::Integer, "age", 1);
835 static SCHEMA: Schema =
836 Schema::new_struct(shape_id!("test", "S"), ShapeType::Structure, &[&NAME, &AGE]);
837
838 let mut de = CborDeserializer::new(&bytes, 128);
839 let mut name: Option<String> = None;
840 let mut age: Option<i32> = None;
841 de.read_struct(&SCHEMA, &mut |member, d| {
842 match member.member_name() {
843 Some("name") => {
844 if !d.is_null() {
845 name = Some(d.read_string(member)?);
846 } else {
847 d.read_null()?;
848 }
849 }
850 Some("age") => {
851 if !d.is_null() {
852 age = Some(d.read_integer(member)?);
853 } else {
854 d.read_null()?;
855 }
856 }
857 _ => {}
858 }
859 Ok(())
860 })
861 .unwrap();
862 assert_eq!(name, Some("Alice".to_string()));
863 assert_eq!(age, None);
864 }
865
866 #[test]
867 fn test_read_sparse_list_with_nulls() {
868 let mut enc = crate::Encoder::new(Vec::new());
870 enc.begin_array().integer(1).null().integer(3).end();
871 let bytes = enc.into_writer();
872
873 let list_schema = Schema::new(shape_id!("test", "L"), ShapeType::List);
874 let mut de = CborDeserializer::new(&bytes, 128);
875 let mut items: Vec<Option<i32>> = Vec::new();
876 de.read_list(&list_schema, &mut |d| {
877 if d.is_null() {
878 d.read_null()?;
879 items.push(None);
880 } else {
881 items.push(Some(d.read_integer(&INTEGER)?));
882 }
883 Ok(())
884 })
885 .unwrap();
886 assert_eq!(items, vec![Some(1), None, Some(3)]);
887 }
888
889 #[test]
890 fn test_read_sparse_map_with_nulls() {
891 let mut enc = crate::Encoder::new(Vec::new());
893 enc.begin_map().str("a").str("hello").str("b").null().end();
894 let bytes = enc.into_writer();
895
896 let map_schema = Schema::new(shape_id!("test", "M"), ShapeType::Map);
897 let mut de = CborDeserializer::new(&bytes, 128);
898 let mut map: std::collections::HashMap<String, Option<String>> =
899 std::collections::HashMap::new();
900 de.read_map(&map_schema, &mut |key, d| {
901 if d.is_null() {
902 d.read_null()?;
903 map.insert(key, None);
904 } else {
905 map.insert(key, Some(d.read_string(&STRING)?));
906 }
907 Ok(())
908 })
909 .unwrap();
910 assert_eq!(map.get("a"), Some(&Some("hello".to_string())));
911 assert_eq!(map.get("b"), Some(&None));
912 }
913
914 static U_INNER_LAMBDA: Schema = Schema::new_member(
926 shape_id!("test", "InnerUnion"),
927 ShapeType::String,
928 "lambda",
929 0,
930 );
931 static U_INNER_SCHEMA: Schema = Schema::new_struct(
932 shape_id!("test", "InnerUnion"),
933 ShapeType::Union,
934 &[&U_INNER_LAMBDA],
935 );
936 static U_OUTER_MCP: Schema =
937 Schema::new_member(shape_id!("test", "OuterUnion"), ShapeType::Union, "mcp", 0);
938 static U_OUTER_SCHEMA: Schema = Schema::new_struct(
939 shape_id!("test", "OuterUnion"),
940 ShapeType::Union,
941 &[&U_OUTER_MCP],
942 );
943
944 #[derive(Debug, PartialEq)]
945 enum InnerUnion {
946 Lambda(String),
947 Unknown,
948 }
949 #[derive(Debug, PartialEq)]
950 enum OuterUnion {
951 Mcp(InnerUnion),
952 Unknown,
953 }
954
955 fn deser_inner_union(deser: &mut dyn ShapeDeserializer) -> Result<InnerUnion, SerdeError> {
956 let mut result: Option<InnerUnion> = None;
957 deser.read_struct(&U_INNER_SCHEMA, &mut |member, d| {
958 result = Some(match member.member_index() {
959 Some(0) => InnerUnion::Lambda(d.read_string(member)?),
960 _ => InnerUnion::Unknown,
961 });
962 Ok(())
963 })?;
964 result.ok_or_else(|| SerdeError::custom("expected a union variant"))
965 }
966
967 fn deser_outer_union(deser: &mut dyn ShapeDeserializer) -> Result<OuterUnion, SerdeError> {
968 let mut result: Option<OuterUnion> = None;
969 deser.read_struct(&U_OUTER_SCHEMA, &mut |member, d| {
970 result = Some(match member.member_index() {
971 Some(0) => OuterUnion::Mcp(deser_inner_union(d)?),
973 _ => OuterUnion::Unknown,
974 });
975 Ok(())
976 })?;
977 result.ok_or_else(|| SerdeError::custom("expected a union variant"))
978 }
979
980 #[test]
981 fn union_in_union_definite_map() {
982 let mut e = crate::Encoder::new(Vec::new());
984 e.map(1)
985 .str("mcp")
986 .map(1)
987 .str("lambda")
988 .str("arn:aws:lambda:fn");
989 let bytes = e.into_writer();
990 let mut de = CborDeserializer::new(&bytes, 128);
991 assert_eq!(
992 deser_outer_union(&mut de).expect("union-in-union must deserialize"),
993 OuterUnion::Mcp(InnerUnion::Lambda("arn:aws:lambda:fn".to_string()))
994 );
995 }
996
997 #[test]
998 fn union_in_union_indefinite_map() {
999 let mut e = crate::Encoder::new(Vec::new());
1000 e.begin_map()
1001 .str("mcp")
1002 .begin_map()
1003 .str("lambda")
1004 .str("arn:aws:lambda:fn")
1005 .end()
1006 .end();
1007 let bytes = e.into_writer();
1008 let mut de = CborDeserializer::new(&bytes, 128);
1009 assert_eq!(
1010 deser_outer_union(&mut de).expect("union-in-union (indefinite) must deserialize"),
1011 OuterUnion::Mcp(InnerUnion::Lambda("arn:aws:lambda:fn".to_string()))
1012 );
1013 }
1014
1015 static U_HOLDER_CHOICE: Schema =
1016 Schema::new_member(shape_id!("test", "Holder"), ShapeType::Union, "choice", 0);
1017 static U_HOLDER_TRAILING: Schema = Schema::new_member(
1018 shape_id!("test", "Holder"),
1019 ShapeType::String,
1020 "trailing",
1021 1,
1022 );
1023 static U_HOLDER_SCHEMA: Schema = Schema::new_struct(
1024 shape_id!("test", "Holder"),
1025 ShapeType::Structure,
1026 &[&U_HOLDER_CHOICE, &U_HOLDER_TRAILING],
1027 );
1028
1029 #[test]
1030 fn nested_union_leaves_decoder_positioned_for_trailing_sibling() {
1031 let mut e = crate::Encoder::new(Vec::new());
1034 e.map(2)
1035 .str("choice")
1036 .map(1)
1037 .str("mcp")
1038 .map(1)
1039 .str("lambda")
1040 .str("x")
1041 .str("trailing")
1042 .str("ok");
1043 let bytes = e.into_writer();
1044 let mut de = CborDeserializer::new(&bytes, 128);
1045 let mut choice: Option<OuterUnion> = None;
1046 let mut trailing: Option<String> = None;
1047 de.read_struct(&U_HOLDER_SCHEMA, &mut |member, d| {
1048 match member.member_index() {
1049 Some(0) => choice = Some(deser_outer_union(d)?),
1050 Some(1) => trailing = Some(d.read_string(member)?),
1051 _ => {}
1052 }
1053 Ok(())
1054 })
1055 .expect("holder with a nested union must parse");
1056 assert_eq!(
1057 choice,
1058 Some(OuterUnion::Mcp(InnerUnion::Lambda("x".to_string())))
1059 );
1060 assert_eq!(
1061 trailing,
1062 Some("ok".to_string()),
1063 "trailing sibling must survive: the nested union read must leave the decoder positioned correctly"
1064 );
1065 }
1066
1067 #[test]
1068 fn empty_union_definite_map_yields_clean_error() {
1069 let mut e = crate::Encoder::new(Vec::new());
1070 e.map(0);
1071 let bytes = e.into_writer();
1072 let mut de = CborDeserializer::new(&bytes, 128);
1073 let err = deser_inner_union(&mut de).unwrap_err();
1074 assert!(
1075 err.to_string().contains("expected a union variant"),
1076 "empty definite union map must be a clean error, got {err:?}"
1077 );
1078 }
1079
1080 #[test]
1081 fn empty_union_indefinite_map_yields_clean_error() {
1082 let mut e = crate::Encoder::new(Vec::new());
1083 e.begin_map().end();
1084 let bytes = e.into_writer();
1085 let mut de = CborDeserializer::new(&bytes, 128);
1086 let err = deser_inner_union(&mut de).unwrap_err();
1087 assert!(
1088 err.to_string().contains("expected a union variant"),
1089 "empty indefinite union map must be a clean error, got {err:?}"
1090 );
1091 }
1092
1093 #[test]
1094 fn union_with_only_unknown_member_is_reported_to_the_consumer() {
1095 let mut e = crate::Encoder::new(Vec::new());
1099 e.map(1).str("zzz").str("ignored");
1100 let bytes = e.into_writer();
1101 let mut de = CborDeserializer::new(&bytes, 128);
1102 assert_eq!(deser_inner_union(&mut de).unwrap(), InnerUnion::Unknown);
1103 }
1104
1105 #[test]
1106 fn list_of_union_in_union() {
1107 let mut e = crate::Encoder::new(Vec::new());
1108 e.array(2)
1109 .map(1)
1110 .str("mcp")
1111 .map(1)
1112 .str("lambda")
1113 .str("a")
1114 .map(1)
1115 .str("mcp")
1116 .map(1)
1117 .str("lambda")
1118 .str("b");
1119 let bytes = e.into_writer();
1120 let list_schema = Schema::new(shape_id!("test", "L"), ShapeType::List);
1121 let mut de = CborDeserializer::new(&bytes, 128);
1122 let mut out = Vec::new();
1123 de.read_list(&list_schema, &mut |el| {
1124 out.push(deser_outer_union(el)?);
1125 Ok(())
1126 })
1127 .expect("list of union-in-union must deserialize");
1128 assert_eq!(
1129 out,
1130 vec![
1131 OuterUnion::Mcp(InnerUnion::Lambda("a".to_string())),
1132 OuterUnion::Mcp(InnerUnion::Lambda("b".to_string())),
1133 ]
1134 );
1135 }
1136
1137 #[test]
1138 fn null_valued_union_member_yields_clean_error_not_panic() {
1139 let mut e = crate::Encoder::new(Vec::new());
1147 e.map(1).str("lambda").null();
1148 let bytes = e.into_writer();
1149 let mut de = CborDeserializer::new(&bytes, 128);
1150 assert!(
1151 deser_inner_union(&mut de).is_err(),
1152 "a null-valued union member must be a clean error, not a panic"
1153 );
1154 }
1155
1156 static B_CD_ENABLED: Schema = Schema::new_member(
1164 shape_id!("test", "ConnectionDraining$enabled"),
1165 ShapeType::Boolean,
1166 "enabled",
1167 0,
1168 );
1169 static B_CD_SCHEMA: Schema = Schema::new_struct(
1170 shape_id!("test", "ConnectionDraining"),
1171 ShapeType::Structure,
1172 &[&B_CD_ENABLED],
1173 );
1174 static B_LBA_CD: Schema = Schema::new_member(
1175 shape_id!("test", "LoadBalancerAttributes$connectionDraining"),
1176 ShapeType::Structure,
1177 "connectionDraining",
1178 0,
1179 );
1180 static B_LBA_SCHEMA: Schema = Schema::new_struct(
1181 shape_id!("test", "LoadBalancerAttributes"),
1182 ShapeType::Structure,
1183 &[&B_LBA_CD],
1184 );
1185
1186 struct BConnectionDraining {
1187 enabled: bool,
1188 }
1189 impl SerializableStruct for BConnectionDraining {
1190 fn schema(&self) -> &Schema<'_> {
1191 &B_CD_SCHEMA
1192 }
1193
1194 fn serialize_members(&self, s: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1195 let val = &self.enabled;
1196 s.write_boolean(&B_CD_ENABLED, *val)
1197 }
1198 }
1199 struct BLoadBalancerAttributes {
1200 connection_draining: BConnectionDraining,
1201 }
1202 impl SerializableStruct for BLoadBalancerAttributes {
1203 fn schema(&self) -> &Schema<'_> {
1204 &B_LBA_SCHEMA
1205 }
1206
1207 fn serialize_members(&self, s: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1208 s.write_struct(&B_LBA_CD, &self.connection_draining)
1209 }
1210 }
1211
1212 #[test]
1213 fn required_value_type_false_bool_is_serialized() {
1214 let bytes = make_deser(|s| {
1215 s.write_struct(
1216 &B_LBA_SCHEMA,
1217 &BLoadBalancerAttributes {
1218 connection_draining: BConnectionDraining { enabled: false },
1219 },
1220 )
1221 .unwrap()
1222 });
1223 let mut de = CborDeserializer::new(&bytes, 128);
1226 let mut cd_seen = false;
1227 let mut enabled: Option<bool> = None;
1228 de.read_struct(&B_LBA_SCHEMA, &mut |m, d| {
1229 if m.member_name() == Some("connectionDraining") {
1230 cd_seen = true;
1231 d.read_struct(&B_CD_SCHEMA, &mut |im, id| {
1232 if im.member_name() == Some("enabled") {
1233 enabled = Some(id.read_boolean(im)?);
1234 }
1235 Ok(())
1236 })?;
1237 }
1238 Ok(())
1239 })
1240 .unwrap();
1241 assert!(cd_seen, "outer connectionDraining member must be present");
1242 assert_eq!(
1243 enabled,
1244 Some(false),
1245 "required value-type enabled=false must be serialized, not dropped"
1246 );
1247 }
1248}
1249
1250#[cfg(test)]
1255mod unknown_member_tests {
1256 use super::*;
1257 use aws_smithy_schema::{shape_id, ShapeType};
1258
1259 static A: Schema<'static> =
1260 Schema::new_member(shape_id!("test", "S"), ShapeType::String, "a", 0);
1261 static S: Schema<'static> =
1262 Schema::new_struct(shape_id!("test", "S"), ShapeType::Structure, &[&A]);
1263
1264 fn read_s(bytes: &[u8], read_unknown_value: bool) -> (Option<String>, Vec<Option<String>>) {
1267 let mut a = None;
1268 let mut unknown = Vec::new();
1269 CborDeserializer::new(bytes, 128)
1270 .read_struct(&S, &mut |member, d| {
1271 match member.member_index() {
1272 Some(0) => a = Some(d.read_string(member)?),
1273 _ => {
1274 assert_eq!(member.shape_type(), ShapeType::Document);
1275 unknown.push(if read_unknown_value {
1276 Some(d.read_string(member)?)
1277 } else {
1278 None
1279 });
1280 }
1281 }
1282 Ok(())
1283 })
1284 .unwrap();
1285 (a, unknown)
1286 }
1287
1288 #[test]
1289 fn unknown_key_is_reported_and_the_consumer_can_read_the_value() {
1290 let mut e = crate::Encoder::new(Vec::new());
1291 e.map(2).str("zzz").str("value").str("a").str("x");
1292 let (a, unknown) = read_s(&e.into_writer(), true);
1293 assert_eq!(a.as_deref(), Some("x"));
1294 assert_eq!(unknown, [Some("value".to_string())]);
1295 }
1296
1297 #[test]
1298 fn unknown_key_value_is_skipped_when_not_read_in_definite_and_indefinite_maps() {
1299 let mut e = crate::Encoder::new(Vec::new());
1300 e.map(3)
1301 .str("zzz")
1302 .map(1)
1303 .str("deep")
1304 .array(2)
1305 .integer(1)
1306 .integer(2)
1307 .str("a")
1308 .str("x")
1309 .str("yyy")
1310 .str("tail");
1311 let (a, unknown) = read_s(&e.into_writer(), false);
1312 assert_eq!(a.as_deref(), Some("x"));
1313 assert_eq!(unknown.len(), 2);
1314
1315 let mut e = crate::Encoder::new(Vec::new());
1316 e.begin_map()
1317 .str("zzz")
1318 .array(2)
1319 .integer(1)
1320 .integer(2)
1321 .str("a")
1322 .str("x")
1323 .end();
1324 let (a, unknown) = read_s(&e.into_writer(), false);
1325 assert_eq!(a.as_deref(), Some("x"));
1326 assert_eq!(unknown.len(), 1);
1327 }
1328
1329 #[test]
1330 fn type_discriminator_and_null_values_are_not_reported() {
1331 let mut e = crate::Encoder::new(Vec::new());
1332 e.map(3)
1333 .str("__type")
1334 .str("ns#Foo")
1335 .str("zzz")
1336 .null()
1337 .str("a")
1338 .str("x");
1339 let (a, unknown) = read_s(&e.into_writer(), false);
1340 assert_eq!(a.as_deref(), Some("x"));
1341 assert!(unknown.is_empty());
1342 }
1343}
1344
1345#[cfg(test)]
1352mod skip_value_contract {
1353 use super::*;
1354 use aws_smithy_schema::codec::{Codec, FinishSerializer};
1355 use aws_smithy_schema::prelude::*;
1356 use aws_smithy_schema::serde::{SerializableStruct, ShapeSerializer};
1357 use aws_smithy_schema::{shape_id, ShapeType};
1358
1359 use crate::codec::{CborCodec, CborSerializer};
1360
1361 static BOUND: Schema =
1365 Schema::new_member(shape_id!("test", "Output"), ShapeType::String, "bound", 0);
1366 static BOUND_LIST: Schema =
1367 Schema::new_member(shape_id!("test", "Output"), ShapeType::List, "bound", 0);
1368 static BOUND_MAP: Schema =
1369 Schema::new_member(shape_id!("test", "Output"), ShapeType::Map, "bound", 0);
1370 static BODY: Schema =
1371 Schema::new_member(shape_id!("test", "Output"), ShapeType::String, "body", 1);
1372 static OUTPUT: Schema = Schema::new_struct(
1373 shape_id!("test", "Output"),
1374 ShapeType::Structure,
1375 &[&BOUND, &BODY],
1376 );
1377
1378 fn skip_bound_read_body(
1382 write_bound: fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
1383 ) -> Result<Option<String>, SerdeError> {
1384 struct Out(fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>);
1385 impl SerializableStruct for Out {
1386 fn schema(&self) -> &Schema<'_> {
1387 &OUTPUT
1388 }
1389 fn serialize_members(&self, s: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1390 (self.0)(s)?;
1391 s.write_string(&BODY, "real")
1392 }
1393 }
1394 let mut ser: CborSerializer = CborCodec::default().create_serializer();
1395 ser.write_struct(&OUTPUT, &Out(write_bound))?;
1396 let bytes = ser.finish();
1397
1398 let mut de = CborDeserializer::new(&bytes, 128);
1399 let mut body = None;
1400 de.read_struct(&OUTPUT, &mut |member, d| {
1401 match member.member_index() {
1402 Some(0) => d.skip_value()?,
1403 Some(1) => body = Some(d.read_string(member)?),
1404 _ => {}
1405 }
1406 Ok(())
1407 })?;
1408 Ok(body)
1409 }
1410
1411 fn assert_skips(name: &str, write: fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>) {
1412 let got =
1413 skip_bound_read_body(write).unwrap_or_else(|e| panic!("skipping {name} failed: {e}"));
1414 assert_eq!(
1415 got.as_deref(),
1416 Some("real"),
1417 "after skipping a {name}, `body` should still be read"
1418 );
1419 }
1420
1421 #[test]
1422 fn skipping_a_scalar_member_lets_the_rest_of_the_struct_parse() {
1423 assert_skips("string", |s| s.write_string(&BOUND, "skipped"));
1424 assert_skips("empty string", |s| s.write_string(&BOUND, ""));
1425 assert_skips("integer", |s| s.write_integer(&BOUND, -12345));
1426 assert_skips("long", |s| s.write_long(&BOUND, i64::MIN));
1427 assert_skips("double", |s| s.write_double(&BOUND, 1.5e300));
1428 assert_skips("boolean", |s| s.write_boolean(&BOUND, true));
1429 assert_skips("blob", |s| {
1430 s.write_blob(&BOUND, aws_smithy_types::Blob::new(vec![1, 2, 3]))
1431 });
1432 assert_skips("null", |s| s.write_null(&BOUND));
1433 }
1434
1435 #[test]
1436 fn skipping_an_aggregate_member_consumes_the_whole_container() {
1437 assert_skips("list", |s| {
1439 s.write_list(&BOUND_LIST, &|s| {
1440 s.write_integer(&INTEGER, 1)?;
1441 s.write_integer(&INTEGER, 2)?;
1442 s.write_integer(&INTEGER, 3)
1443 })
1444 });
1445 assert_skips("empty list", |s| s.write_list(&BOUND_LIST, &|_| Ok(())));
1446 assert_skips("map", |s| {
1447 s.write_map(&BOUND_MAP, &|s| {
1448 s.write_string(&STRING, "k1")?;
1449 s.write_string(&STRING, "v1")?;
1450 s.write_string(&STRING, "k2")?;
1451 s.write_string(&STRING, "v2")
1452 })
1453 });
1454 assert_skips("empty map", |s| s.write_map(&BOUND_MAP, &|_| Ok(())));
1455 assert_skips("nested list of maps", |s| {
1456 s.write_list(&BOUND_LIST, &|s| {
1457 for _ in 0..2 {
1458 s.write_map(&BOUND_MAP, &|s| {
1459 s.write_string(&STRING, "deep")?;
1460 s.write_list(&BOUND_LIST, &|s| {
1461 s.write_integer(&INTEGER, 1)?;
1462 s.write_integer(&INTEGER, 2)
1463 })
1464 })?;
1465 }
1466 Ok(())
1467 })
1468 });
1469 assert_skips("map containing a decoy `body` key", |s| {
1472 s.write_map(&BOUND_MAP, &|s| {
1473 s.write_string(&STRING, "body")?;
1474 s.write_string(&STRING, "decoy")
1475 })
1476 });
1477 }
1478
1479 #[test]
1480 fn skip_value_on_an_unknown_member_does_not_double_skip() {
1481 static UNKNOWN: Schema =
1485 Schema::new_member(shape_id!("test", "Output"), ShapeType::List, "unknown", 0);
1486 struct Out;
1487 impl SerializableStruct for Out {
1488 fn schema(&self) -> &Schema<'_> {
1489 &OUTPUT
1490 }
1491 fn serialize_members(&self, s: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1492 s.write_list(&UNKNOWN, &|s| {
1493 s.write_integer(&INTEGER, 1)?;
1494 s.write_integer(&INTEGER, 2)
1495 })?;
1496 s.write_string(&BODY, "real")
1497 }
1498 }
1499 let mut ser: CborSerializer = CborCodec::default().create_serializer();
1500 ser.write_struct(&OUTPUT, &Out).unwrap();
1501 let bytes = ser.finish();
1502
1503 let mut de = CborDeserializer::new(&bytes, 128);
1504 let mut body = None;
1505 let mut saw_unknown = false;
1506 de.read_struct(&OUTPUT, &mut |member, d| {
1507 match member.member_index() {
1508 Some(1) => body = Some(d.read_string(member)?),
1509 None => {
1512 saw_unknown = true;
1513 d.skip_value()?;
1514 }
1515 _ => {}
1516 }
1517 Ok(())
1518 })
1519 .unwrap();
1520 assert!(saw_unknown, "unknown key should still be reported");
1521 assert_eq!(
1522 body.as_deref(),
1523 Some("real"),
1524 "`body` must not be swallowed by a second skip"
1525 );
1526 }
1527}