1use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime};
7
8macro_rules! delegate_method {
24 ($($(#[$meta:meta])* $wrapper_name:ident => $encoder_name:ident($($param_name:ident : $param_type:ty),*);)+) => {
25 $(
26 pub fn $wrapper_name(&mut self, $($param_name: $param_type),*) -> &mut Self {
27 self.encoder.$encoder_name($($param_name)*).expect(INFALLIBLE_WRITE);
28 self
29 }
30 )+
31 };
32}
33
34#[derive(Debug, Clone)]
35pub struct Encoder {
36 encoder: minicbor::Encoder<Vec<u8>>,
37}
38
39const INFALLIBLE_WRITE: &str = "write failed";
42
43impl Encoder {
44 pub fn new(writer: Vec<u8>) -> Self {
45 Self {
46 encoder: minicbor::Encoder::new(writer),
47 }
48 }
49
50 delegate_method! {
51 begin_map => begin_map();
54 begin_array => begin_array();
56 boolean => bool(x: bool);
58 byte => i8(x: i8);
60 short => i16(x: i16);
62 integer => i32(x: i32);
64 long => i64(x: i64);
66 float => f32(x: f32);
68 double => f64(x: f64);
70 null => null();
72 end => end();
74 }
75
76 const MAX_HEADER_LEN: usize = 9;
78
79 #[inline]
88 fn write_type_len(writer: &mut Vec<u8>, major: u8, len: usize) {
89 let mut buf = [0u8; Self::MAX_HEADER_LEN];
90 let n = match len {
91 0..=23 => {
92 buf[0] = major | len as u8;
93 1
94 }
95 24..=0xff => {
96 buf[0] = major | 24;
97 buf[1] = len as u8;
98 2
99 }
100 0x100..=0xffff => {
101 buf[0] = major | 25;
102 buf[1..3].copy_from_slice(&(len as u16).to_be_bytes());
103 3
104 }
105 0x1_0000..=0xffff_ffff => {
106 buf[0] = major | 26;
107 buf[1..5].copy_from_slice(&(len as u32).to_be_bytes());
108 5
109 }
110 _ => {
111 buf[0] = major | 27;
112 buf[1..9].copy_from_slice(&(len as u64).to_be_bytes());
113 9
114 }
115 };
116 writer.extend_from_slice(&buf[..n]);
117 }
118
119 pub fn str(&mut self, x: &str) -> &mut Self {
121 let writer = self.encoder.writer_mut();
122 let len = x.len();
123 writer.reserve(Self::MAX_HEADER_LEN + len);
124 Self::write_type_len(writer, 0x60, len);
125 writer.extend_from_slice(x.as_bytes());
126 self
127 }
128
129 pub fn big_integer(&mut self, value: &BigInteger) -> &mut Self {
136 let value = value
137 .as_ref()
138 .parse()
139 .expect("BigInteger contains invalid value");
140 self.bigint(&value)
141 }
142
143 pub fn big_decimal(&mut self, value: &BigDecimal) -> &mut Self {
149 let value: bigdecimal::BigDecimal = value
150 .as_ref()
151 .parse()
152 .expect("BigDecimal contains invalid value");
153 let (mantissa, scale) = value.into_bigint_and_scale();
154 let exponent = scale
155 .checked_neg()
156 .expect("BigDecimal exponent is outside the supported range");
157
158 self.encoder
159 .tag(minicbor::data::Tag::new(4))
160 .expect(INFALLIBLE_WRITE);
161 self.array(2);
162 self.encoder.i64(exponent).expect(INFALLIBLE_WRITE);
163 self.bigint(&mantissa)
164 }
165
166 fn bigint(&mut self, value: &num_bigint::BigInt) -> &mut Self {
167 use num_bigint::{BigInt, Sign};
168
169 let (sign, magnitude) = value.to_bytes_be();
170
171 match sign {
172 Sign::Plus | Sign::NoSign => {
173 if magnitude.len() <= 8 {
175 let mut buf = [0u8; 8];
176 buf[8 - magnitude.len()..].copy_from_slice(&magnitude);
177 let val = u64::from_be_bytes(buf);
178 self.encoder.u64(val).expect(INFALLIBLE_WRITE);
179 } else {
180 self.encoder
181 .tag(minicbor::data::Tag::new(2))
182 .expect(INFALLIBLE_WRITE);
183 let stripped = strip_leading_zeroes(&magnitude);
185 self.encoder.bytes(stripped).expect(INFALLIBLE_WRITE);
186 }
187 }
188 Sign::Minus => {
189 let one = BigInt::from(1u8);
191 let n = (-value) - one;
192 let (_, n_bytes) = n.to_bytes_be();
193
194 if n_bytes.len() <= 8 {
196 let mut buf = [0u8; 8];
197 buf[8 - n_bytes.len()..].copy_from_slice(&n_bytes);
198 let val = u64::from_be_bytes(buf);
199 let neg = -1i128 - (val as i128);
203 let int_val = minicbor::data::Int::try_from(neg)
204 .expect("value fits in CBOR integer range");
205 self.encoder.int(int_val).expect(INFALLIBLE_WRITE);
206 } else {
207 self.encoder
208 .tag(minicbor::data::Tag::new(3))
209 .expect(INFALLIBLE_WRITE);
210 let stripped = strip_leading_zeroes(&n_bytes);
211 self.encoder.bytes(stripped).expect(INFALLIBLE_WRITE);
212 }
213 }
214 }
215 self
216 }
217
218 pub fn blob_bytes(&mut self, data: &[u8]) -> &mut Self {
226 let writer = self.encoder.writer_mut();
227 let len = data.len();
228 writer.reserve(Self::MAX_HEADER_LEN + len);
229 Self::write_type_len(writer, 0x40, len);
230 writer.extend_from_slice(data);
231 self
232 }
233
234 pub fn blob(&mut self, x: &Blob) -> &mut Self {
236 self.blob_bytes(x.as_ref())
237 }
238
239 pub fn array(&mut self, len: usize) -> &mut Self {
241 Self::write_type_len(self.encoder.writer_mut(), 0x80, len);
242 self
243 }
244
245 pub fn map(&mut self, len: usize) -> &mut Self {
251 Self::write_type_len(self.encoder.writer_mut(), 0xa0, len);
252 self
253 }
254
255 pub fn timestamp(&mut self, x: &DateTime) -> &mut Self {
256 self.encoder
257 .tag(minicbor::data::Tag::from(
258 minicbor::data::IanaTag::Timestamp,
259 ))
260 .expect(INFALLIBLE_WRITE);
261 self.encoder.f64(x.as_secs_f64()).expect(INFALLIBLE_WRITE);
262 self
263 }
264
265 pub fn into_writer(self) -> Vec<u8> {
266 self.encoder.into_writer()
267 }
268}
269
270fn strip_leading_zeroes(bytes: &[u8]) -> &[u8] {
272 let start = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len());
273 &bytes[start..]
274}
275
276#[cfg(test)]
277mod tests {
278 use super::*;
279 use aws_smithy_types::Blob;
280
281 #[test]
283 fn str_matches_minicbor() {
284 let cases = [
285 "", "a", "hello world!! test str", "this is exactly 24 char", &"x".repeat(0xff), &"y".repeat(0x100), &"z".repeat(0x1_0000), ];
293 for input in &cases {
294 let mut ours = Encoder::new(Vec::new());
295 ours.str(input);
296
297 let mut theirs = minicbor::Encoder::new(Vec::new());
298 theirs.str(input).unwrap();
299
300 assert_eq!(
301 ours.into_writer(),
302 theirs.into_writer(),
303 "str mismatch for input len={}",
304 input.len()
305 );
306 }
307 }
308
309 #[test]
311 fn blob_matches_minicbor() {
312 let cases: Vec<Vec<u8>> = vec![
313 vec![], vec![0x42], vec![0xAB; 23], vec![0xCD; 24], vec![0xEF; 0xff], vec![0x01; 0x100], vec![0x02; 0x1_0000], ];
321 for input in &cases {
322 let mut ours = Encoder::new(Vec::new());
323 ours.blob(&Blob::new(input.clone()));
324
325 let mut theirs = minicbor::Encoder::new(Vec::new());
326 theirs.bytes(input).unwrap();
327
328 assert_eq!(
329 ours.into_writer(),
330 theirs.into_writer(),
331 "blob mismatch for input len={}",
332 input.len()
333 );
334 }
335 }
336
337 #[test]
339 fn str_chained_matches_minicbor() {
340 let mut ours = Encoder::new(Vec::new());
341 ours.str("key1").str("value1").str("key2").str("value2");
342
343 let mut theirs = minicbor::Encoder::new(Vec::new());
344 theirs
345 .str("key1")
346 .unwrap()
347 .str("value1")
348 .unwrap()
349 .str("key2")
350 .unwrap()
351 .str("value2")
352 .unwrap();
353
354 assert_eq!(ours.into_writer(), theirs.into_writer());
355 }
356
357 #[test]
359 fn str_inside_map_matches_minicbor() {
360 let mut ours = Encoder::new(Vec::new());
361 ours.begin_map().str("TableName").str("my-table").end();
362
363 let mut theirs = minicbor::Encoder::new(Vec::new());
364 theirs
365 .begin_map()
366 .unwrap()
367 .str("TableName")
368 .unwrap()
369 .str("my-table")
370 .unwrap()
371 .end()
372 .unwrap();
373
374 assert_eq!(ours.into_writer(), theirs.into_writer());
375 }
376
377 #[test]
379 fn str_utf8_matches_minicbor() {
380 let cases = [
381 "café", "日本語", "🦀🔥", "mixed: aé日🦀", ];
386 for input in &cases {
387 let mut ours = Encoder::new(Vec::new());
388 ours.str(input);
389
390 let mut theirs = minicbor::Encoder::new(Vec::new());
391 theirs.str(input).unwrap();
392
393 assert_eq!(
394 ours.into_writer(),
395 theirs.into_writer(),
396 "str UTF-8 mismatch for {:?}",
397 input
398 );
399 }
400 }
401
402 #[test]
403 fn preferred_serialization_small_positive() {
404 let mut encoder = Encoder::new(Vec::new());
406 encoder.big_integer(&"0".parse().unwrap());
407 assert_eq!(encoder.into_writer(), vec![0x00]); let mut encoder = Encoder::new(Vec::new());
410 encoder.big_integer(&"23".parse().unwrap());
411 assert_eq!(encoder.into_writer(), vec![0x17]); let mut encoder = Encoder::new(Vec::new());
414 encoder.big_integer(&"256".parse().unwrap());
415 assert_eq!(encoder.into_writer(), vec![0x19, 0x01, 0x00]);
417 }
418
419 #[test]
420 fn preferred_serialization_small_negative() {
421 let mut encoder = Encoder::new(Vec::new());
424 encoder.big_integer(&"-1".parse().unwrap());
425 assert_eq!(encoder.into_writer(), vec![0x20]); let mut encoder = Encoder::new(Vec::new());
428 encoder.big_integer(&"-42".parse().unwrap());
429 assert_eq!(encoder.into_writer(), vec![0x38, 0x29]);
431 }
432
433 #[test]
434 fn preferred_serialization_u64_max() {
435 let mut encoder = Encoder::new(Vec::new());
437 encoder.big_integer(&"18446744073709551615".parse().unwrap());
438 let bytes = encoder.into_writer();
439 assert_eq!(bytes[0], 0x1b); assert_eq!(
441 &bytes[1..],
442 &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
443 );
444 }
445
446 #[test]
447 fn tag2_for_values_exceeding_u64() {
448 let mut encoder = Encoder::new(Vec::new());
451 encoder.big_integer(&"18446744073709551616".parse().unwrap());
452 let bytes = encoder.into_writer();
453 assert_eq!(
454 bytes,
455 vec![0xc2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
456 );
457 }
458
459 #[test]
460 fn tag3_negative_bignum_rfc8949_example() {
461 let mut encoder = Encoder::new(Vec::new());
464 encoder.big_integer(&"-18446744073709551617".parse().unwrap());
465 let bytes = encoder.into_writer();
466 assert_eq!(
467 bytes,
468 vec![0xc3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
469 );
470 }
471
472 #[test]
473 fn negative_at_major_type_1_boundary() {
474 let mut encoder = Encoder::new(Vec::new());
477 encoder.big_integer(&"-18446744073709551616".parse().unwrap());
478 let bytes = encoder.into_writer();
479 assert_eq!(bytes[0], 0x3b); assert_eq!(
481 &bytes[1..],
482 &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
483 );
484 }
485
486 #[test]
487 fn tag2_strips_leading_zeroes() {
488 let mut encoder = Encoder::new(Vec::new());
490 let large = "123456789012345678901234567890";
491 encoder.big_integer(&large.parse().unwrap());
492 let bytes = encoder.into_writer();
493 assert_eq!(bytes[0], 0xc2); let payload_start = if bytes[1] < 0x58 { 2 } else { 3 };
497 assert_ne!(bytes[payload_start], 0x00);
498 }
499
500 #[test]
501 fn decimal_fraction_rfc8949_example() {
502 let mut encoder = Encoder::new(Vec::new());
504 encoder.big_decimal(&"273.15".parse().unwrap());
505 assert_eq!(
506 encoder.into_writer(),
507 vec![0xc4, 0x82, 0x21, 0x19, 0x6a, 0xb3]
508 );
509 }
510
511 #[test]
512 fn decimal_fraction_scientific_notation() {
513 let mut encoder = Encoder::new(Vec::new());
514 encoder.big_decimal(&"1.23e10".parse().unwrap());
515 assert_eq!(encoder.into_writer(), vec![0xc4, 0x82, 0x08, 0x18, 0x7b]);
517 }
518
519 #[test]
520 fn decimal_fraction_preserves_scale() {
521 let mut encoder = Encoder::new(Vec::new());
522 encoder.big_decimal(&"1.2300".parse().unwrap());
523 assert_eq!(
525 encoder.into_writer(),
526 vec![0xc4, 0x82, 0x23, 0x19, 0x30, 0x0c]
527 );
528 }
529
530 #[test]
531 fn decimal_fraction_uses_bignum_mantissa() {
532 let mut encoder = Encoder::new(Vec::new());
533 encoder.big_decimal(&"18446744073709551616".parse().unwrap());
534 assert_eq!(
535 encoder.into_writer(),
536 vec![
537 0xc4, 0x82, 0x00, 0xc2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538 ]
539 );
540 }
541
542 #[test]
543 fn valid_big_decimal_can_be_encoded() {
544 for value in [
545 "0",
546 "+5",
547 "-0.0",
548 ".5",
549 "-.5",
550 "5.",
551 "1.5E+3",
552 "00123",
553 "00.1",
554 "0.123456789012345678901234567890",
555 "1.234e500",
556 "1e9223372036854775807",
557 "1e-9223372036854775807",
558 ] {
559 let mut encoder = Encoder::new(Vec::new());
560 encoder.big_decimal(&value.parse().unwrap());
561 }
562 }
563}