1use base64::Engine;
2use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
3
4#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
7pub struct Base64(Vec<u8>);
8
9impl Base64 {
10 #[inline]
11 pub fn into_vec(self) -> Vec<u8> {
12 self.0
13 }
14}
15
16impl AsRef<[u8]> for Base64 {
17 #[inline]
18 fn as_ref(&self) -> &[u8] {
19 &self.0
20 }
21}
22
23impl AsMut<[u8]> for Base64 {
24 #[inline]
25 fn as_mut(&mut self) -> &mut [u8] {
26 &mut self.0
27 }
28}
29
30impl From<Vec<u8>> for Base64 {
31 #[inline]
32 fn from(value: Vec<u8>) -> Self {
33 Self(value)
34 }
35}
36
37impl From<&[u8]> for Base64 {
38 #[inline]
39 fn from(value: &[u8]) -> Self {
40 Self(value.to_vec())
41 }
42}
43
44impl Serialize for Base64 {
45 #[inline]
46 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
47 let encoded = base64::engine::general_purpose::STANDARD.encode(&self.0);
48 serializer.serialize_str(&encoded)
49 }
50}
51
52impl<'de> Deserialize<'de> for Base64 {
53 #[inline]
54 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
55 use de::Error;
56 let value: &'de str = Deserialize::deserialize(deserializer)?;
57 let decoded = base64::engine::general_purpose::STANDARD
58 .decode(value)
59 .map_err(|err| D::Error::custom(Base64Error(err)))?;
60 Ok(Base64(decoded))
61 }
62}
63
64#[derive(Debug, thiserror::Error)]
65#[error("byte string contains invalid Base64: {0}")]
66pub struct Base64Error(#[from] base64::DecodeError);
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn test_serialize_empty() {
74 let byte = Base64::default();
75 let json = serde_json::to_string(&byte).unwrap();
76 assert_eq!(json, r#""""#);
77 }
78
79 #[test]
80 fn test_serialize_text_data() {
81 let byte = Base64::from(b"Hello, World!".as_slice());
82 let json = serde_json::to_string(&byte).unwrap();
83 assert_eq!(json, r#""SGVsbG8sIFdvcmxkIQ==""#);
84 }
85
86 #[test]
87 fn test_serialize_binary_data() {
88 let byte = Base64::from(vec![0x00, 0x01, 0x02, 0xff, 0xfe, 0xfd]);
89 let json = serde_json::to_string(&byte).unwrap();
90 assert_eq!(json, r#""AAEC//79""#);
91 }
92
93 #[test]
94 fn test_deserialize_empty() {
95 let byte: Base64 = serde_json::from_str(r#""""#).unwrap();
96 assert_eq!(byte.as_ref(), b"");
97 }
98
99 #[test]
100 fn test_deserialize_text_data() {
101 let byte: Base64 = serde_json::from_str(r#""SGVsbG8sIFdvcmxkIQ==""#).unwrap();
102 assert_eq!(byte.as_ref(), b"Hello, World!");
103 }
104
105 #[test]
106 fn test_deserialize_binary_data() {
107 let byte: Base64 = serde_json::from_str(r#""AAEC//79""#).unwrap();
108 assert_eq!(byte.as_ref(), &[0x00, 0x01, 0x02, 0xff, 0xfe, 0xfd]);
109 }
110
111 #[test]
112 fn test_deserialize_invalid_base64() {
113 let result: Result<Base64, _> = serde_json::from_str(r#""not valid base64!!!""#);
114 assert!(result.is_err());
115 }
116
117 #[test]
118 fn test_roundtrip() {
119 let original = Base64::from(vec![0x00, 0x7f, 0x80, 0xff, 0x42]);
120 let json = serde_json::to_string(&original).unwrap();
121 let restored: Base64 = serde_json::from_str(&json).unwrap();
122 assert_eq!(original, restored);
123 }
124}