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}