1//! Custom serde helpers for bytes::Bytes using serde_bytes
2
3use base64::{
4 Engine,
5 prelude::{BASE64_STANDARD, BASE64_STANDARD_NO_PAD, BASE64_URL_SAFE, BASE64_URL_SAFE_NO_PAD},
6};
7use bytes::Bytes;
8use core::fmt;
9use serde::{
10 Deserializer, Serializer,
11 de::{self, MapAccess, Visitor},
12};
13
14/// Serialize Bytes as a CBOR byte string
15pub fn serialize<S>(bytes: &Option<Bytes>, serializer: S) -> Result<S::Ok, S::Error>
16where
17 S: Serializer,
18{
19 if let Some(bytes) = bytes {
20 if serializer.is_human_readable() {
21 // JSON: {"$bytes": "base64 string"}
22 use serde::ser::SerializeMap;
23 let mut map = serializer.serialize_map(Some(1))?;
24 map.serialize_entry("$bytes", &BASE64_STANDARD.encode(bytes))?;
25 map.end()
26 } else {
27 // CBOR: raw bytes
28 serde_bytes::serialize(bytes.as_ref(), serializer)
29 }
30 } else {
31 serializer.serialize_none()
32 }
33}
34
35/// Deserialize Bytes from a CBOR byte string
36pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Bytes>, D::Error>
37where
38 D: Deserializer<'de>,
39{
40 if deserializer.is_human_readable() {
41 Ok(deserializer.deserialize_any(OptBytesVisitor)?)
42 } else {
43 let vec: Option<Vec<u8>> = serde_bytes::deserialize(deserializer)?;
44 Ok(vec.map(Bytes::from))
45 }
46}
47
48struct OptBytesVisitor;
49
50impl<'de> Visitor<'de> for OptBytesVisitor {
51 type Value = Option<Bytes>;
52
53 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
54 formatter.write_str("a base64-encoded string")
55 }
56
57 fn visit_none<E>(self) -> Result<Self::Value, E>
58 where
59 E: de::Error,
60 {
61 Ok(None)
62 }
63
64 fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
65 where
66 D: Deserializer<'de>,
67 {
68 let vec: Vec<u8> = serde_bytes::deserialize(deserializer)?;
69 Ok(Some(Bytes::from(vec)))
70 }
71
72 fn visit_unit<E>(self) -> Result<Self::Value, E> {
73 Ok(None)
74 }
75
76 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
77 where
78 A: MapAccess<'de>,
79 {
80 let mut bytes = None;
81
82 while let Some(key) = map.next_key()? {
83 match key {
84 "$bytes" => {
85 if bytes.is_some() {
86 return Err(de::Error::duplicate_field("$bytes"));
87 }
88 let bytes_str: String = map.next_value()?;
89 // First one should just work. rest are insurance.
90 bytes = if let Ok(bytes) = BASE64_STANDARD.decode(&bytes_str) {
91 Some(Bytes::from_owner(bytes))
92 } else if let Ok(bytes) = BASE64_STANDARD_NO_PAD.decode(&bytes_str) {
93 Some(Bytes::from_owner(bytes))
94 } else if let Ok(bytes) = BASE64_URL_SAFE.decode(&bytes_str) {
95 Some(Bytes::from_owner(bytes))
96 } else if let Ok(bytes) = BASE64_URL_SAFE_NO_PAD.decode(&bytes_str) {
97 Some(Bytes::from_owner(bytes))
98 } else {
99 return Err(de::Error::custom("invalid base64 string"));
100 }
101 }
102 _ => {
103 return Err(de::Error::unknown_field(key, &["$bytes"]));
104 }
105 }
106 }
107
108 Ok(bytes)
109 }
110}