pub mod hex_bytes {
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S, T>(x: T, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
s.serialize_str(&format!("0x{encoded}", encoded = hex::encode(x.as_ref())))
}
pub fn deserialize<'de, T, D>(d: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: From<Vec<u8>>,
{
let value = String::deserialize(d)?;
if let Some(value) = value.strip_prefix("0x") {
hex::decode(value)
} else {
hex::decode(&value)
}
.map(Into::into)
.map_err(|e| serde::de::Error::custom(e.to_string()))
}
}
pub mod hex_bytes_option {
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S, T>(x: &Option<T>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
if let Some(x) = x {
s.serialize_str(&format!("0x{encoded}", encoded = hex::encode(x.as_ref())))
} else {
s.serialize_none()
}
}
pub fn deserialize<'de, T, D>(d: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
T: From<Vec<u8>>,
{
let value: Option<String> = Option::deserialize(d)?;
match value {
Some(val) => {
let val = if let Some(stripped) = val.strip_prefix("0x") { stripped } else { &val };
hex::decode(val)
.map(Into::into)
.map(Some)
.map_err(|e| serde::de::Error::custom(e.to_string()))
}
None => Ok(None),
}
}
}
#[macro_export]
macro_rules! impl_non_serializable_protocol {
($type:ty, $msg:expr) => {
impl serde::Serialize for $type {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Err(serde::ser::Error::custom($msg))
}
}
impl<'de> serde::Deserialize<'de> for $type {
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Err(serde::de::Error::custom($msg))
}
}
};
}
#[cfg(test)]
mod tests {
use serde::{Deserialize, Serialize};
use serde_json;
use super::*;
#[derive(Debug, Serialize, Deserialize)]
struct TestStruct {
#[serde(with = "hex_bytes")]
bytes: Vec<u8>,
#[serde(with = "hex_bytes_option")]
bytes_option: Option<Vec<u8>>,
}
#[test]
fn hex_bytes_serialize_deserialize() {
let test_struct = TestStruct { bytes: vec![0u8; 10], bytes_option: Some(vec![0u8; 10]) };
let serialized = serde_json::to_string(&test_struct).unwrap();
assert_eq!(
serialized,
"{\"bytes\":\"0x00000000000000000000\",\"bytes_option\":\"0x00000000000000000000\"}"
);
let deserialized: TestStruct = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized.bytes, vec![0u8; 10]);
assert_eq!(deserialized.bytes_option, Some(vec![0u8; 10]));
}
#[test]
fn hex_bytes_option_none() {
let test_struct = TestStruct { bytes: vec![0u8; 10], bytes_option: None };
let serialized = serde_json::to_string(&test_struct).unwrap();
assert_eq!(serialized, "{\"bytes\":\"0x00000000000000000000\",\"bytes_option\":null}");
let deserialized: TestStruct = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized.bytes, vec![0u8; 10]);
assert_eq!(deserialized.bytes_option, None);
}
}