mod error;
pub use error::{Error, ValidateError};
#[cfg(feature = "len-u64")]
pub type LenInt = u64;
#[cfg(not(feature = "len-u64"))]
pub type LenInt = u32;
pub const LEN_INT_SIZE: usize = std::mem::size_of::<LenInt>();
pub trait AFastSerialize {
fn to_bytes(&self) -> Vec<u8>;
}
pub trait AFastDeserialize: Sized {
fn from_bytes(data: &[u8]) -> Result<(Self, usize), Error>;
}
fn read_exact<'a>(data: &'a [u8], offset: usize, n: usize) -> Result<&'a [u8], Error> {
if offset + n > data.len() {
Err(Error::deserialize(format!(
"Not enough bytes: need {} at offset {}, have {}",
n,
offset,
data.len()
)))
} else {
Ok(&data[offset..offset + n])
}
}
macro_rules! impl_serialize_int {
($t:ty, $size:expr) => {
impl AFastSerialize for $t {
fn to_bytes(&self) -> Vec<u8> {
self.to_le_bytes().to_vec()
}
}
impl AFastDeserialize for $t {
fn from_bytes(data: &[u8]) -> Result<(Self, usize), Error> {
let bytes = read_exact(data, 0, $size)?;
let arr: [u8; $size] = bytes.try_into().unwrap();
Ok((Self::from_le_bytes(arr), $size))
}
}
};
}
impl_serialize_int!(i8, 1);
impl_serialize_int!(u8, 1);
impl_serialize_int!(i16, 2);
impl_serialize_int!(u16, 2);
impl_serialize_int!(i32, 4);
impl_serialize_int!(u32, 4);
impl_serialize_int!(i64, 8);
impl_serialize_int!(u64, 8);
impl_serialize_int!(i128, 16);
impl_serialize_int!(u128, 16);
impl_serialize_int!(f32, 4);
impl_serialize_int!(f64, 8);
impl AFastSerialize for bool {
fn to_bytes(&self) -> Vec<u8> {
vec![if *self { 1 } else { 0 }]
}
}
impl AFastDeserialize for bool {
fn from_bytes(data: &[u8]) -> Result<(Self, usize), Error> {
let bytes = read_exact(data, 0, 1)?;
match bytes[0] {
0 => Ok((false, 1)),
1 => Ok((true, 1)),
v => Err(Error::deserialize(format!("Invalid bool value: {}", v))),
}
}
}
fn write_len(buf: &mut Vec<u8>, len: usize) {
let v = len as LenInt;
buf.extend(v.to_le_bytes());
}
fn read_len(data: &[u8], offset: usize) -> Result<(usize, usize), Error> {
let bytes = read_exact(data, offset, LEN_INT_SIZE)?;
let arr: [u8; LEN_INT_SIZE] = bytes.try_into().unwrap();
let len = LenInt::from_le_bytes(arr) as usize;
Ok((len, offset + LEN_INT_SIZE))
}
impl AFastSerialize for String {
fn to_bytes(&self) -> Vec<u8> {
let bytes = self.as_bytes();
let mut result = Vec::with_capacity(LEN_INT_SIZE + bytes.len());
write_len(&mut result, bytes.len());
result.extend_from_slice(bytes);
result
}
}
impl AFastDeserialize for String {
fn from_bytes(data: &[u8]) -> Result<(Self, usize), Error> {
let (len, offset) = read_len(data, 0)?;
let bytes = read_exact(data, offset, len)?;
let s = std::str::from_utf8(bytes)
.map_err(|e| Error::deserialize(format!("Invalid UTF-8: {}", e)))?;
Ok((s.to_owned(), offset + len))
}
}
impl<T: AFastSerialize> AFastSerialize for Vec<T> {
fn to_bytes(&self) -> Vec<u8> {
let mut result = Vec::new();
write_len(&mut result, self.len());
for item in self {
result.extend(item.to_bytes());
}
result
}
}
impl<T: AFastDeserialize> AFastDeserialize for Vec<T> {
fn from_bytes(data: &[u8]) -> Result<(Self, usize), Error> {
let (len, mut offset) = read_len(data, 0)?;
let mut vec = Vec::with_capacity(len);
for _ in 0..len {
let (item, new_offset) = T::from_bytes(&data[offset..])?;
vec.push(item);
offset += new_offset;
}
Ok((vec, offset))
}
}
impl<T: AFastSerialize> AFastSerialize for Option<T> {
fn to_bytes(&self) -> Vec<u8> {
match self {
Some(val) => {
let mut result = vec![1u8];
result.extend(val.to_bytes());
result
}
None => vec![0u8],
}
}
}
impl<T: AFastDeserialize> AFastDeserialize for Option<T> {
fn from_bytes(data: &[u8]) -> Result<(Self, usize), Error> {
let bytes = read_exact(data, 0, 1)?;
match bytes[0] {
0 => Ok((None, 1)),
1 => {
let (val, new_offset) = T::from_bytes(&data[1..])?;
Ok((Some(val), 1 + new_offset))
}
v => Err(Error::deserialize(format!("Invalid Option tag: {}", v))),
}
}
}
impl<T: AFastSerialize, const N: usize> AFastSerialize for [T; N] {
fn to_bytes(&self) -> Vec<u8> {
let mut result = Vec::new();
for item in self {
result.extend(item.to_bytes());
}
result
}
}
impl<T: AFastDeserialize + Default + Copy, const N: usize> AFastDeserialize for [T; N] {
fn from_bytes(data: &[u8]) -> Result<(Self, usize), Error> {
let mut arr = [T::default(); N];
let mut offset = 0;
for item in arr.iter_mut() {
let (val, new_offset) = T::from_bytes(&data[offset..])?;
*item = val;
offset += new_offset;
}
Ok((arr, offset))
}
}
impl AFastSerialize for &str {
fn to_bytes(&self) -> Vec<u8> {
let bytes = self.as_bytes();
let len = bytes.len() as LenInt;
let mut result = len.to_le_bytes().to_vec();
result.extend_from_slice(bytes);
result
}
}
#[cfg(test)]
mod tests {
use super::*;
fn roundtrip<T: AFastSerialize + AFastDeserialize + PartialEq + std::fmt::Debug>(val: &T) {
let bytes = val.to_bytes();
let (decoded, offset) = T::from_bytes(&bytes).unwrap();
assert_eq!(offset, bytes.len());
assert_eq!(*val, decoded);
}
#[test]
fn test_integers() {
roundtrip(&42i8);
roundtrip(&255u8);
roundtrip(&-1000i16);
roundtrip(&60000u16);
roundtrip(&-100_000i32);
roundtrip(&3_000_000_000u32);
roundtrip(&-1_000_000_000_000i64);
roundtrip(&18_000_000_000_000_000_000u64);
}
#[test]
fn test_floats() {
roundtrip(&3.14f32);
roundtrip(&2.718281828f64);
}
#[test]
fn test_bool() {
roundtrip(&true);
roundtrip(&false);
}
#[test]
fn test_string() {
roundtrip(&String::from("hello world"));
roundtrip(&String::from(""));
roundtrip(&String::from("你好"));
}
#[test]
fn test_vec() {
roundtrip(&vec![1i32, 2, 3, 4, 5]);
roundtrip(&Vec::<i32>::new());
roundtrip(&vec![String::from("a"), String::from("b")]);
}
#[test]
fn test_option() {
roundtrip(&Some(42i32));
roundtrip(&None::<i32>);
roundtrip(&Some(String::from("hello")));
}
#[test]
fn test_array() {
roundtrip(&[1i32, 2, 3]);
}
}