aws_smithy_cbor/encode.rs
1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6use aws_smithy_types::{Blob, DateTime};
7
8/// Macro for delegating method calls to the encoder.
9///
10/// This macro generates wrapper methods for calling specific encoder methods on the encoder
11/// and returning a mutable reference to self for method chaining.
12///
13/// # Example
14///
15/// ```ignore
16/// delegate_method! {
17/// /// Wrapper method for encoding method `encode_str` on the encoder.
18/// encode_str_wrapper => encode_str(data: &str);
19/// /// Wrapper method for encoding method `encode_int` on the encoder.
20/// encode_int_wrapper => encode_int(value: i32);
21/// }
22/// ```
23macro_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
39/// We always write to a `Vec<u8>`, which is infallible in `minicbor`.
40/// <https://docs.rs/minicbor/latest/minicbor/encode/write/trait.Write.html#impl-Write-for-Vec%3Cu8%3E>
41const 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 /// Used when it's not cheap to calculate the size, i.e. when the struct has one or more
52 /// `Option`al members.
53 begin_map => begin_map();
54 /// Writes a definite length string.
55 str => str(x: &str);
56 /// Writes a boolean value.
57 boolean => bool(x: bool);
58 /// Writes a byte value.
59 byte => i8(x: i8);
60 /// Writes a short value.
61 short => i16(x: i16);
62 /// Writes an integer value.
63 integer => i32(x: i32);
64 /// Writes an long value.
65 long => i64(x: i64);
66 /// Writes an float value.
67 float => f32(x: f32);
68 /// Writes an double value.
69 double => f64(x: f64);
70 /// Writes a null tag.
71 null => null();
72 /// Writes an end tag.
73 end => end();
74 }
75
76 pub fn blob(&mut self, x: &Blob) -> &mut Self {
77 self.encoder.bytes(x.as_ref()).expect(INFALLIBLE_WRITE);
78 self
79 }
80
81 /// Writes a fixed length array of given length.
82 pub fn array(&mut self, len: usize) -> &mut Self {
83 self.encoder
84 // `.expect()` safety: `From<u64> for usize` is not in the standard library,
85 // but the conversion should be infallible (unless we ever have 128-bit machines I
86 // guess). <See https://users.rust-lang.org/t/cant-convert-usize-to-u64/6243>.
87 .array(len.try_into().expect("`usize` to `u64` conversion failed"))
88 .expect(INFALLIBLE_WRITE);
89 self
90 }
91
92 /// Writes a fixed length map of given length.
93 /// Used when we know the size in advance, i.e.:
94 /// - when a struct has all non-`Option`al members.
95 /// - when serializing `union` shapes (they can only have one member set).
96 /// - when serializing a `map` shape.
97 pub fn map(&mut self, len: usize) -> &mut Self {
98 self.encoder
99 .map(len.try_into().expect("`usize` to `u64` conversion failed"))
100 .expect(INFALLIBLE_WRITE);
101 self
102 }
103
104 pub fn timestamp(&mut self, x: &DateTime) -> &mut Self {
105 self.encoder
106 .tag(minicbor::data::Tag::from(
107 minicbor::data::IanaTag::Timestamp,
108 ))
109 .expect(INFALLIBLE_WRITE);
110 self.encoder.f64(x.as_secs_f64()).expect(INFALLIBLE_WRITE);
111 self
112 }
113
114 pub fn into_writer(self) -> Vec<u8> {
115 self.encoder.into_writer()
116 }
117}