Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions epserde/src/impls/deref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* SPDX-FileCopyrightText: 2025 Inria
*
* SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
*/

/*!

Blanket implementations for references and single-item containers

*/

use crate::prelude::*;
use ser::*;

macro_rules! impl_ser {
($type:ty) => {
impl<T: CopyType> CopyType for $type {
type Copy = <T as CopyType>::Copy;
}

impl<T: TypeHash> TypeHash for $type {
#[inline(always)]
fn type_hash(hasher: &mut impl core::hash::Hasher) {
<T as TypeHash>::type_hash(hasher)
}
}

impl<T: AlignHash> AlignHash for $type {
#[inline(always)]
fn align_hash(hasher: &mut impl core::hash::Hasher, offset_of: &mut usize) {
<T as AlignHash>::align_hash(hasher, offset_of)
}
}

impl<T: SerializeInner> SerializeInner for $type {
type SerType = T;
const IS_ZERO_COPY: bool = <T as SerializeInner>::IS_ZERO_COPY;
const ZERO_COPY_MISMATCH: bool = <T as SerializeInner>::ZERO_COPY_MISMATCH;

#[inline(always)]
unsafe fn _serialize_inner(
&self,
backend: &mut impl WriteWithNames,
) -> ser::Result<()> {
<T as SerializeInner>::_serialize_inner(self, backend)
}
}
};
}

macro_rules! impl_all {
($type:ident) => {
impl_ser!($type<T>);

impl<T: DeserializeInner> DeserializeInner for $type<T> {
type DeserType<'a> = $type<<T as DeserializeInner>::DeserType<'a>>;

#[inline(always)]
unsafe fn _deserialize_full_inner(
backend: &mut impl ReadWithPos,
) -> deser::Result<Self> {
<T as DeserializeInner>::_deserialize_full_inner(backend).map($type::new)
}
#[inline(always)]
unsafe fn _deserialize_eps_inner<'a>(
backend: &mut SliceWithPos<'a>,
) -> deser::Result<Self::DeserType<'a>> {
<T as DeserializeInner>::_deserialize_eps_inner(backend).map($type::new)
}
}
};
}

impl_ser!(&T);
impl_ser!(&mut T);

#[cfg(any(feature = "std", feature = "alloc"))]
mod std_impl {
use super::*;

#[cfg(not(feature = "std"))]
mod imports {
pub use alloc::boxed::Box;
pub use alloc::rc::Rc;
pub use alloc::sync::Arc;
}
#[cfg(feature = "std")]
mod imports {
pub use std::rc::Rc;
pub use std::sync::Arc;
}
use imports::*;

impl_all!(Box);
impl_all!(Arc);
impl_all!(Rc);
}
1 change: 1 addition & 0 deletions epserde/src/impls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and [`DeserializeInner`](crate::deser::DeserializeInner) for standard Rust types

pub mod array;
pub mod boxed_slice;
pub mod deref;
pub mod iter;
pub mod prim;
pub mod slice;
Expand Down
42 changes: 34 additions & 8 deletions epserde/tests/test_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,22 @@
*/

use epserde::prelude::*;
use std::rc::Rc;
use std::sync::Arc;

fn test_generic<T>(s: T)
where
T: Serialize + Deserialize + PartialEq + core::fmt::Debug,
for<'a> <T as DeserializeInner>::DeserType<'a>: PartialEq<T> + core::fmt::Debug,
{
test_generic_split::<T, T, T>(s, |value| value)
}
fn test_generic_split<Ser, Deser, OwnedSer>(s: Ser, deref: impl Fn(&Ser) -> &OwnedSer)
where
Ser: Serialize,
Deser: Deserialize + PartialEq<OwnedSer> + core::fmt::Debug,
OwnedSer: core::fmt::Debug,
for<'a> <Deser as DeserializeInner>::DeserType<'a>: PartialEq<OwnedSer> + core::fmt::Debug,
{
{
let mut v = vec![];
Expand All @@ -19,11 +30,12 @@ where
schema.0.sort_by_key(|a| a.offset);

cursor.set_position(0);
let full_copy = unsafe { <T>::deserialize_full(&mut std::io::Cursor::new(&v)).unwrap() };
assert_eq!(s, full_copy);
let full_copy =
unsafe { <Deser>::deserialize_full(&mut std::io::Cursor::new(&v)).unwrap() };
assert_eq!(&full_copy, deref(&s));

let full_copy = unsafe { <T>::deserialize_eps(&v).unwrap() };
assert_eq!(full_copy, s);
let full_copy = unsafe { <Deser>::deserialize_eps(&v).unwrap() };
assert_eq!(&full_copy, deref(&s));

let _ = schema.to_csv();
let _ = schema.debug(&v);
Expand All @@ -34,11 +46,12 @@ where
unsafe { s.serialize(&mut cursor).unwrap() };

cursor.set_position(0);
let full_copy = unsafe { <T>::deserialize_full(&mut std::io::Cursor::new(&v)).unwrap() };
assert_eq!(s, full_copy);
let full_copy =
unsafe { <Deser>::deserialize_full(&mut std::io::Cursor::new(&v)).unwrap() };
assert_eq!(&full_copy, deref(&s));

let full_copy = unsafe { <T>::deserialize_eps(&v).unwrap() };
assert_eq!(full_copy, s);
let full_copy = unsafe { <Deser>::deserialize_eps(&v).unwrap() };
assert_eq!(&full_copy, deref(&s));
}
}

Expand All @@ -50,3 +63,16 @@ fn test_range() {
struct Data(std::ops::Range<i32>);
test_generic(Data(0..10));
}

#[test]
fn test_containers() {
test_generic::<Box<i32>>(Box::new(10));
test_generic::<Arc<i32>>(Arc::new(10));
test_generic::<Rc<i32>>(Rc::new(10));
}

#[test]
fn test_references() {
test_generic_split::<&i32, i32, i32>(&10, |n| *n);
test_generic_split::<&mut i32, i32, i32>(&mut 10, |n| *n);
}
Loading