base64_serde/
lib.rs

1/// Create a type with appropriate `serialize` and `deserialize` functions to use with
2/// serde when specifying how to serialize a particular field.
3///
4/// Once the type is defined, you can use `#[serde(with = "YourTypeNameHere")]` on a `Vec<u8>`
5/// field that you wished to serialize to base64 or deserialize from base64.
6///
7/// If you want to change resulting type's visibility, prefix the desired type
8/// name with appropiate visibility, for example:
9///
10/// ```
11/// use base64_serde::base64_serde_type;
12///
13/// base64_serde_type!(pub IWillBeAPublicType, base64::engine::general_purpose::STANDARD);
14/// base64_serde_type!(pub(crate) IWillBeACrateType, base64::engine::general_purpose::STANDARD);
15/// ```
16///
17/// # Examples
18///
19/// Existing engine:
20///
21/// ```
22/// use base64_serde::base64_serde_type;
23///
24/// base64_serde_type!(Base64Standard, base64::engine::general_purpose::STANDARD);
25///
26/// #[derive(serde::Serialize, serde::Deserialize)]
27/// struct ByteHolder {
28///     #[serde(with = "Base64Standard")]
29///     bytes: Vec<u8>,
30/// }
31/// ```
32///
33/// Custom engine:
34///
35/// ```
36/// use base64_serde::base64_serde_type;
37///
38/// const BCRYPT_NO_PAD: base64::engine::GeneralPurpose =
39///     base64::engine::GeneralPurpose::new(
40///         &base64::alphabet::BCRYPT,
41///         base64::engine::general_purpose::NO_PAD
42///     );
43///
44/// base64_serde_type!(Base64BcryptNoPad, BCRYPT_NO_PAD);
45/// ```
46#[macro_export]
47macro_rules! base64_serde_type {
48    ($visibility:vis $typename:ident, $engine:expr) => {
49        $visibility enum $typename {}
50        base64_serde_type!(impl_only, $typename, $engine);
51    };
52    (impl_only, $typename:ident, $engine:expr) => {
53        impl $typename {
54            pub fn serialize<S, Input>(
55                bytes: Input,
56                serializer: S,
57            ) -> ::std::result::Result<S::Ok, S::Error>
58            where
59                S: serde::Serializer,
60                Input: AsRef<[u8]>,
61            {
62                use base64::Engine as _;
63                serializer.serialize_str(&$engine.encode(bytes.as_ref()))
64            }
65
66            pub fn deserialize<'de, D, Output>(
67                deserializer: D,
68            ) -> ::std::result::Result<Output, D::Error>
69            where
70                D: serde::Deserializer<'de>,
71                Output: From<Vec<u8>>,
72            {
73                struct Base64Visitor;
74
75                impl<'de> serde::de::Visitor<'de> for Base64Visitor {
76                    type Value = Vec<u8>;
77
78                    fn expecting(
79                        &self,
80                        formatter: &mut ::std::fmt::Formatter,
81                    ) -> ::std::fmt::Result {
82                        write!(formatter, "base64 ASCII text")
83                    }
84
85                    fn visit_str<E>(self, v: &str) -> ::std::result::Result<Self::Value, E>
86                    where
87                        E: serde::de::Error,
88                    {
89                        use base64::Engine as _;
90                        $engine.decode(v).map_err(serde::de::Error::custom)
91                    }
92                }
93
94                deserializer
95                    .deserialize_str(Base64Visitor)
96                    .map(|vec| Output::from(vec))
97            }
98        }
99    };
100}