use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
use serde::{
de::{Deserialize, Deserializer, Error},
ser::{Serialize, Serializer},
};
pub fn serialize<S: Serializer, T: AsRef<[u8]>>(v: &T, s: S) -> Result<S::Ok, S::Error> {
if s.is_human_readable() {
BASE64.encode(v).serialize(s)
} else {
v.as_ref().serialize(s)
}
}
pub fn deserialize<'a, D: Deserializer<'a>>(d: D) -> Result<Vec<u8>, D::Error> {
if d.is_human_readable() {
Ok(BASE64
.decode(String::deserialize(d)?)
.map_err(|err| D::Error::custom(format!("invalid base64: {err}")))?)
} else {
Ok(Vec::deserialize(d)?)
}
}
#[cfg(test)]
mod test {
use crate::BASE64;
use base64::Engine;
use rand::RngCore;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
struct Test {
#[serde(with = "crate")]
bytes: Vec<u8>,
}
#[test]
fn test_bytes_serde() {
let mut rng = rand::thread_rng();
for len in [0, 1, 10, 1000] {
let mut t = Test {
bytes: vec![0; len],
};
rng.fill_bytes(&mut t.bytes);
let binary = bincode::serialize(&t).unwrap();
assert_eq!(binary[..8], (len as u64).to_le_bytes());
assert_eq!(t.bytes, binary[8..]);
assert_eq!(t, bincode::deserialize::<Test>(&binary).unwrap());
let json = serde_json::to_value(&t).unwrap();
assert_eq!(json["bytes"].as_str().unwrap(), BASE64.encode(&t.bytes));
assert_eq!(t, serde_json::from_value::<Test>(json).unwrap());
}
}
}