use crate::Result;
use byteorder::{ByteOrder, LittleEndian};
use std::{
any::{Any, TypeId},
ptr,
};
pub(crate) fn serialize_bytes<T: 'static>(value: &T) -> Result<Vec<u8>>
where
T: serde::Serialize,
{
Ok(match parse_as_str(value) {
Some(s) => bincode::serialize(&s)?.into_iter().skip(8).collect(),
None => bincode::serialize(value)?,
})
}
pub(crate) fn deserialize_bytes<T>(bytes: &[u8]) -> Result<T>
where
T: serde::de::DeserializeOwned + 'static,
{
Ok(if can_as_str::<T>() {
let mut buf = Vec::with_capacity(8 + bytes.len());
buf.append(&mut vec![0; 8]);
LittleEndian::write_u64(&mut buf, bytes.len() as u64);
for b in bytes {
buf.push(*b);
}
try_parse_number(&buf)?
} else {
bincode::deserialize(bytes)?
})
}
fn try_parse_number<T>(bytes: &[u8]) -> Result<T>
where
T: serde::de::DeserializeOwned + 'static,
{
let t_id = TypeId::of::<T>();
macro_rules! downcast {
($($ty:ty,)*) => {
$(if t_id == TypeId::of::<$ty>() {
let s: String = bincode::deserialize(&bytes)?;
let num: $ty = s.trim().parse()?;
let p = &num as *const $ty as *const T;
return Ok(unsafe { ptr::read(p) });
})*
};
}
downcast![u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64,];
Ok(bincode::deserialize(&bytes)?)
}
fn parse_as_str<T: 'static>(value: &T) -> Option<String> {
macro_rules! downcast {
($($ty:ty,)*) => {
$(if let Some(t) = Any::downcast_ref::<$ty>(value) {
return Some(t.to_string());
})*
};
}
downcast![String, &str, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, bool, f32, f64,];
None
}
fn can_as_str<T: 'static>() -> bool {
let t_id = TypeId::of::<T>();
macro_rules! downcast {
($($ty:ty,)*) => {
$(if t_id == TypeId::of::<$ty>() {
return true;
})*
};
}
downcast![String, &str, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, bool, f32, f64,];
false
}