use core::fmt;
use serde_core::de;
use crate::BSize;
macro_rules! impl_serialize {
($($ty:ty),* $(,)?) => {
$(
impl serde_core::Serialize for BSize<$ty> {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where
S: serde_core::Serializer,
{
if ser.is_human_readable() {
ser.collect_str(self)
} else {
self.0.serialize(ser)
}
}
}
)*
};
}
impl_serialize!(u8, u16, u32, u64, usize);
macro_rules! impl_deserialize {
($($ty:ty),* $(,)?) => {
$(
impl<'de> serde_core::Deserialize<'de> for BSize<$ty> {
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: serde_core::Deserializer<'de>,
{
struct Visitor;
impl de::Visitor<'_> for Visitor {
type Value = BSize<$ty>;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("an integer or string")
}
fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
if let Ok(val) = u64::try_from(value) {
if val <= <$ty>::MAX as u64 {
Ok(BSize(val as $ty))
} else {
Err(E::invalid_value(
de::Unexpected::Signed(value),
&"integer overflow",
))
}
} else {
Err(E::invalid_value(
de::Unexpected::Signed(value),
&"integer overflow",
))
}
}
fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
if value <= <$ty>::MAX as u64 {
Ok(BSize(value as $ty))
} else {
Err(E::invalid_value(
de::Unexpected::Unsigned(value),
&"integer overflow",
))
}
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
if let Ok(val) = value.parse() {
Ok(val)
} else {
Err(E::invalid_value(
de::Unexpected::Str(value),
&"parsable string",
))
}
}
}
if de.is_human_readable() {
de.deserialize_any(Visitor)
} else {
de.deserialize_u64(Visitor)
}
}
}
)*
};
}
impl_deserialize!(u8, u16, u32, u64, usize);
#[cfg(test)]
mod tests {
use serde::Deserialize;
use serde::Serialize;
use super::*;
#[test]
fn test_serde() {
#[derive(Serialize, Deserialize)]
struct S {
x: BSize<usize>,
}
let s = serde_json::from_str::<S>(r#"{ "x": "5 B" }"#).unwrap();
assert_eq!(s.x, BSize::<usize>(5));
let s = serde_json::from_str::<S>(r#"{ "x": 1048576 }"#).unwrap();
assert_eq!(s.x, "1 MiB".parse::<BSize<usize>>().unwrap());
let s = toml::from_str::<S>(r#"x = "2.5 MiB""#).unwrap();
assert_eq!(s.x, "2.5 MiB".parse::<BSize<usize>>().unwrap());
let s = toml::from_str::<S>(r#"x = "9223372036854775807""#).unwrap();
assert_eq!(s.x, "9223372036854775807".parse::<BSize<usize>>().unwrap());
}
#[test]
fn test_serde_json() {
let json = serde_json::to_string(&BSize::<usize>::mib(1)).unwrap();
assert_eq!(json, "\"1048576 B\"");
let deserialized = serde_json::from_str::<BSize<usize>>(&json).unwrap();
assert_eq!(deserialized.0, 1048576);
}
}