1use base64::DecodeError;
2use derive_more::{From, Into};
3use fmt::Display;
4use serde::{
5 de::{self, Visitor},
6 Deserialize, Deserializer, Serialize, Serializer,
7};
8use std::{
9 fmt::{self, Formatter},
10 str::FromStr,
11};
12
13#[derive(Debug, Clone, From, Into, Ord, PartialOrd, Eq, PartialEq)]
14pub struct Binary(Box<[u8]>);
15
16struct X;
17impl<'de> Visitor<'de> for X {
18 type Value = Binary;
19 fn expecting(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
20 f.write_str("binary data (possibly base64-encoded)")
21 }
22 fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
23 Ok(Binary(v.into()))
24 }
25 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
26 let bytes = base64::decode(v).map_err(|e| E::custom(e.to_string()))?;
27 Ok(Binary(bytes.into()))
28 }
29}
30
31impl<'de> Deserialize<'de> for Binary {
32 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
33 deserializer.deserialize_any(X)
34 }
35}
36
37impl Serialize for Binary {
38 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
39 if serializer.is_human_readable() {
40 serializer.serialize_str(base64::encode(&*self.0).as_str())
41 } else {
42 serializer.serialize_bytes(&self.0)
43 }
44 }
45}
46
47impl FromStr for Binary {
48 type Err = DecodeError;
49 fn from_str(s: &str) -> Result<Self, Self::Err> {
50 let bytes = base64::decode(s)?;
51 Ok(Binary(bytes.into()))
52 }
53}
54
55impl AsRef<[u8]> for Binary {
56 fn as_ref(&self) -> &[u8] {
57 &self.0
58 }
59}
60
61impl Display for Binary {
62 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
63 f.write_str(base64::encode(&*self.0).as_str())
64 }
65}
66
67impl From<&[u8]> for Binary {
68 fn from(v: &[u8]) -> Self {
69 Binary(v.into())
70 }
71}
72
73impl From<Vec<u8>> for Binary {
74 fn from(v: Vec<u8>) -> Self {
75 Binary(v.into())
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn must_serialize_json() {
85 let binary = Binary((&[1, 2, 3, 255][..]).into());
86 let text = serde_json::to_string(&binary).unwrap();
87 assert_eq!(text, r#""AQID/w==""#);
88 assert_eq!(serde_json::from_str::<Binary>(&text).unwrap(), binary);
89 }
90
91 #[test]
92 fn must_serialize_cbor() {
93 let binary = Binary((&[1, 2, 3][..]).into());
94 let cbor = serde_cbor::to_vec(&binary).unwrap();
95 assert_eq!(cbor, vec![67, 1, 2, 3]);
96 assert_eq!(serde_cbor::from_slice::<Binary>(&cbor).unwrap(), binary);
97 }
98}