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}