use epserde::prelude::*;
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::rc::Rc;
use core::ops::ControlFlow;
#[cfg(feature = "std")]
use std::{
hash::{BuildHasherDefault, DefaultHasher},
ops::{Bound, RangeBounds, RangeInclusive},
rc::Rc,
};
const TEST_STRS: &[&str] = &["abc\0\x0a🔥\u{0d2bdf}", ""];
#[test]
fn test_box_str() -> anyhow::Result<()> {
for &test_str in TEST_STRS {
let s = test_str;
{
let mut cursor = <AlignedCursor>::new();
let mut schema = unsafe { s.serialize_with_schema(&mut cursor)? };
schema.0.sort_by_key(|a| a.offset);
cursor.set_position(0);
let full_copy = unsafe { <Box<str>>::deserialize_full(&mut cursor)? };
assert_eq!(&*full_copy, s);
let eps_copy = unsafe { <Box<str>>::deserialize_eps(cursor.as_bytes())? };
assert_eq!(eps_copy, s);
let eps_copy = unsafe { String::deserialize_eps(cursor.as_bytes())? };
assert_eq!(eps_copy, s);
}
let s = test_str.to_string();
{
let mut cursor = <AlignedCursor>::new();
let mut schema = unsafe { s.serialize_with_schema(&mut cursor)? };
schema.0.sort_by_key(|a| a.offset);
cursor.set_position(0);
let full_copy = unsafe { String::deserialize_full(&mut cursor)? };
assert_eq!(full_copy, s);
let eps_copy = unsafe { <Box<str>>::deserialize_eps(cursor.as_bytes())? };
assert_eq!(eps_copy, s);
let eps_copy = unsafe { String::deserialize_eps(cursor.as_bytes())? };
assert_eq!(eps_copy, s);
}
let s = test_str.to_string().into_boxed_str();
{
let mut cursor = <AlignedCursor>::new();
unsafe { s.serialize(&mut cursor)? };
cursor.set_position(0);
let full_copy = unsafe { <Box<str>>::deserialize_full(&mut cursor)? };
assert_eq!(full_copy, s);
let eps_copy = unsafe { <Box<str>>::deserialize_eps(cursor.as_bytes())? };
assert_eq!(eps_copy, s.as_ref());
let eps_copy = unsafe { String::deserialize_eps(cursor.as_bytes())? };
assert_eq!(eps_copy, s.as_ref());
}
}
Ok(())
}
fn test_generic<T>(s: T) -> anyhow::Result<()>
where
T: Serialize + Deserialize + PartialEq + core::fmt::Debug,
for<'a> DeserType<'a, T>: PartialEq<T> + core::fmt::Debug,
{
{
let mut cursor = <AlignedCursor<Aligned16>>::new();
let mut schema = unsafe { s.serialize_with_schema(&mut cursor)? };
schema.0.sort_by_key(|a| a.offset);
cursor.set_position(0);
let full_copy = unsafe { <T>::deserialize_full(&mut cursor)? };
assert_eq!(full_copy, s);
let bytes = cursor.as_bytes();
let eps_copy = unsafe { <T>::deserialize_eps(bytes)? };
assert_eq!(eps_copy, s);
let _ = schema.to_csv();
let _ = schema.to_csv_with_data(bytes);
}
{
let mut cursor = <AlignedCursor<Aligned16>>::new();
unsafe { s.serialize(&mut cursor)? };
cursor.set_position(0);
let full_copy = unsafe { <T>::deserialize_full(&mut cursor)? };
assert_eq!(full_copy, s);
let eps_copy = unsafe { <T>::deserialize_eps(cursor.as_bytes())? };
assert_eq!(eps_copy, s);
}
Ok(())
}
#[test]
fn test_range() -> anyhow::Result<()> {
test_generic::<core::ops::Range<i32>>(0..10)?;
#[derive(Epserde, PartialEq, Debug)]
struct Data(core::ops::Range<i32>);
test_generic(Data(0..10))?;
Ok(())
}
#[test]
fn test_option() -> anyhow::Result<()> {
test_generic::<Option<i32>>(Some(42))?;
test_generic::<Option<i32>>(None)?;
let a: Option<Vec<usize>> = Some(vec![1, 2, 3]);
let mut cursor = <AlignedCursor<Aligned16>>::new();
unsafe { a.serialize(&mut cursor)? };
cursor.set_position(0);
let full = unsafe { <Option<Vec<usize>>>::deserialize_full(&mut cursor)? };
assert_eq!(full, a);
let eps = unsafe { <Option<Vec<usize>>>::deserialize_eps(cursor.as_bytes())? };
assert_eq!(eps, Some(&[1_usize, 2, 3][..]));
let a: Option<Vec<usize>> = None;
let mut cursor = <AlignedCursor<Aligned16>>::new();
unsafe { a.serialize(&mut cursor)? };
cursor.set_position(0);
let full = unsafe { <Option<Vec<usize>>>::deserialize_full(&mut cursor)? };
assert_eq!(full, a);
let eps = unsafe { <Option<Vec<usize>>>::deserialize_eps(cursor.as_bytes())? };
assert_eq!(eps, None);
Ok(())
}
#[test]
fn test_ser_rc_ref() -> anyhow::Result<()> {
let v = vec![0, 1, 2, 3];
let mut cursor = <AlignedCursor<Aligned16>>::new();
unsafe { Serialize::serialize(&Rc::new(v.as_slice()), &mut cursor)? };
cursor.set_position(0);
let s = unsafe { <Rc<Box<[i32]>>>::deserialize_eps(cursor.as_bytes())? };
assert_eq!(&*s, &v);
Ok(())
}
#[test]
fn test_ref_field() -> anyhow::Result<()> {
let v = vec![0, 1, 2, 3];
let mut cursor = <AlignedCursor<Aligned16>>::new();
#[derive(Epserde, Debug)]
struct Data<A>(A);
unsafe { Serialize::serialize(&Rc::new(Data(v.as_slice())), &mut cursor)? };
cursor.set_position(0);
let s = unsafe { <Rc<Data<Box<[i32]>>>>::deserialize_eps(cursor.as_bytes())? };
assert_eq!(s.0, &v);
Ok(())
}
#[cfg(feature = "std")]
#[test]
fn test_range_bound_deep_copy_idx() -> anyhow::Result<()> {
let r = RangeInclusive::new("a".to_string(), "b".to_string());
let mut cursor = <AlignedCursor<Aligned16>>::new();
unsafe { r.serialize(&mut cursor)? };
cursor.set_position(0);
let full = unsafe { RangeInclusive::<String>::deserialize_full(&mut cursor)? };
assert_eq!(full, r);
let eps = unsafe { RangeInclusive::<String>::deserialize_eps(cursor.as_bytes())? };
assert_eq!(eps.start_bound(), Bound::Included(&"a"));
assert_eq!(eps.end_bound(), Bound::Included(&"b"));
Ok(())
}
#[test]
fn test_control_flow() -> anyhow::Result<()> {
test_generic::<ControlFlow<i32, f64>>(ControlFlow::Break(42))?;
test_generic::<ControlFlow<i32, f64>>(ControlFlow::Continue(1.618))?;
Ok(())
}
#[test]
fn test_result() -> anyhow::Result<()> {
test_generic::<Result<i32, f64>>(Ok(42))?;
test_generic::<Result<i32, f64>>(Err(1.618))?;
Ok(())
}
#[test]
fn test_bound() -> anyhow::Result<()> {
test_generic::<core::ops::Bound<i32>>(core::ops::Bound::Unbounded)?;
test_generic::<core::ops::Bound<i32>>(core::ops::Bound::Included(42))?;
test_generic::<core::ops::Bound<i32>>(core::ops::Bound::Excluded(42))?;
Ok(())
}
#[cfg(feature = "std")]
#[test]
fn test_builder_hasher_default() -> anyhow::Result<()> {
let bhd = BuildHasherDefault::<DefaultHasher>::default();
let mut cursor = <AlignedCursor<Aligned16>>::new();
unsafe { bhd.serialize(&mut cursor)? };
cursor.set_position(0);
let full = unsafe { BuildHasherDefault::<DefaultHasher>::deserialize_full(&mut cursor)? };
assert_eq!(&full, &bhd);
let eps = unsafe { BuildHasherDefault::<DefaultHasher>::deserialize_eps(cursor.as_bytes())? };
assert_eq!(&eps, &bhd);
Ok(())
}
#[cfg(feature = "std")]
#[test]
fn test_range_inclusive_exhausted() {
let mut r = (i32::MAX - 1)..=i32::MAX;
r.next();
r.next();
assert!(r.is_empty());
assert!(matches!(r.end_bound(), Bound::Excluded(_)));
let mut cursor = <AlignedCursor<Aligned16>>::new();
assert!(unsafe { r.serialize(&mut cursor) }.is_err());
}