diff --git a/README.md b/README.md index 7d40c97..28115ac 100644 --- a/README.md +++ b/README.md @@ -76,14 +76,12 @@ These are the main limitations you should be aware of before choosing to use structure you will need to couple permanently the deserialized structure with its serialized support, which is obtained by putting it in a [`MemCase`] using the convenience methods [`Deserialize::load_mem`], [`Deserialize::load_mmap`], - and [`Deserialize::mmap`]. A [`MemCase`] will deref to its contained type, so it - can be used transparently as long as fields and methods are concerned, but if - your original type is `T` the field of the new structure will have to be of type - `MemCase>`, not `T`. + and [`Deserialize::mmap`]. A [`MemCase`] provides a method that yields references + to the deserialized type associated to its contained type. - No validation or padding cleaning is performed on zero-copy types. If you plan to serialize data and distribute it, you must take care of these issues. - + ## Pros - Almost instant deserialization with minimal allocation provided that you @@ -140,7 +138,7 @@ let t: DeserType<'_, [usize; 1000]> = assert_eq!(s, *t); // This is a traditional deserialization instead -let t: [usize; 1000] = +let t: [usize; 1000] = unsafe { <[usize; 1000]>::deserialize_full( &mut std::fs::File::open(&file)? )? }; @@ -149,16 +147,10 @@ assert_eq!(s, t); // In this case we map the data structure into memory // // Note: requires the `mmap` feature. -let u: MemCase<&[usize; 1000]> = - unsafe { <[usize; 1000]>::mmap(&file, Flags::empty())? }; - -assert_eq!(s, **u); - -// When using a MemCase, the lifetime of the derived deserialization type is 'static -let u: MemCase> = +let u: MemCase<[usize; 1000]> = unsafe { <[usize; 1000]>::mmap(&file, Flags::empty())? }; -assert_eq!(s, **u); +assert_eq!(s, **u.borrow()); # Ok(()) # } ``` @@ -166,8 +158,8 @@ assert_eq!(s, **u); Note how we serialize an array, but we deserialize a reference. The reference points inside `b`, so there is no copy performed. The call to [`deserialize_full`] creates a new array instead. The third call maps the data -structure into memory and returns a [`MemCase`] that can be used transparently -as a reference to the array; moreover, the [`MemCase`] can be passed to other +structure into memory and returns a [`MemCase`] that can be used to get +a reference to the array; moreover, the [`MemCase`] can be passed to other functions or stored in a structure field, as it contains both the structure and the memory-mapped region that supports it. @@ -205,14 +197,14 @@ let t: DeserType<'_, Vec> = assert_eq!(s, *t); // This is a traditional deserialization instead -let t: Vec = +let t: Vec = unsafe { >::load_full(&file)? }; assert_eq!(s, t); // In this case we map the data structure into memory -let u: MemCase>> = +let u: MemCase> = unsafe { >::mmap(&file, Flags::empty())? }; -assert_eq!(s, **u); +assert_eq!(s, **u.borrow()); # Ok(()) # } ``` @@ -264,14 +256,14 @@ let t: DeserType<'_, Vec> = assert_eq!(s, *t); // This is a traditional deserialization instead -let t: Vec = +let t: Vec = unsafe { >::load_full(&file)? }; assert_eq!(s, t); // In this case we map the data structure into memory -let u: MemCase>> = +let u: MemCase> = unsafe { >::mmap(&file, Flags::empty())? }; -assert_eq!(s, **u); +assert_eq!(s, **u.borrow()); # Ok(()) # } ``` @@ -309,20 +301,21 @@ unsafe { s.store(&file) }; let b = std::fs::read(&file)?; // The type of t will be inferred--it is shown here only for clarity -let t: MyStruct<&[isize]> = +let t: MyStruct<&[isize]> = unsafe { >>::deserialize_eps(b.as_ref())? }; assert_eq!(s.id, t.id); assert_eq!(s.data, Vec::from(t.data)); // This is a traditional deserialization instead -let t: MyStruct> = +let t: MyStruct> = unsafe { >>::load_full(&file)? }; assert_eq!(s, t); // In this case we map the data structure into memory -let u: MemCase> = +let u: MemCase>> = unsafe { >>::mmap(&file, Flags::empty())? }; +let u: &MyStruct<&[isize]> = u.borrow(); assert_eq!(s.id, u.id); assert_eq!(s.data, u.data.as_ref()); # Ok(()) @@ -371,8 +364,9 @@ let t = unsafe { MyStruct::deserialize_eps(b.as_ref())? }; assert_eq!(s.sum(), t.sum()); let t = unsafe { ::mmap(&file, Flags::empty())? }; +let t: &MyStructParam<&[isize]> = t.borrow(); -// t works transparently as a MyStructParam<&[isize]> +// t works transparently as a &MyStructParam<&[isize]> assert_eq!(s.id, t.id); assert_eq!(s.data, t.data.as_ref()); assert_eq!(s.sum(), t.sum()); @@ -407,7 +401,7 @@ unsafe { s.store(&file) }; let b = std::fs::read(&file)?; // The type of t is unchanged -let t: MyStruct> = +let t: MyStruct> = unsafe { >>::deserialize_eps(b.as_ref())? }; # Ok(()) # } @@ -445,7 +439,7 @@ unsafe { s.store(&file) }; let b = std::fs::read(&file)?; // The type of t is unchanged -let t: &MyStruct = +let t: &MyStruct = unsafe { >::deserialize_eps(b.as_ref())? }; # Ok(()) # } @@ -480,7 +474,7 @@ let e = Enum::B(vec![0, 1, 2, 3]); let mut file = std::env::temp_dir(); file.push("serialized7"); unsafe { e.store(&file) }; -// Deserializing using just Enum will fail, as the type parameter +// Deserializing using just Enum will fail, as the type parameter // by default is Vec assert!(unsafe { ::load_full(&file) }.is_err()); # Ok(()) @@ -513,7 +507,7 @@ let t: &[i32] = unsafe { >::deserialize_eps(b.as_ref())? }; let t: Vec = unsafe { >::deserialize_full( &mut std::fs::File::open(&file)? )? }; -let t: MemCase<&[i32]> = unsafe { >::mmap(&file, Flags::empty())? }; +let t: MemCase> = unsafe { >::mmap(&file, Flags::empty())? }; // Within a structure #[derive(Epserde, Debug, PartialEq, Eq, Default, Clone)] @@ -532,7 +526,7 @@ let t: Data<&[i32]> = unsafe { >>::deserialize_eps(b.as_ref())? }; let t: Data> = unsafe { >>::deserialize_full( &mut std::fs::File::open(&file)? )? }; -let t: MemCase> = unsafe { >>::mmap(&file, Flags::empty())? }; +let t: MemCase>> = unsafe { >>::mmap(&file, Flags::empty())? }; # Ok(()) # } ``` @@ -565,7 +559,7 @@ let t: &[i32] = unsafe { >::deserialize_eps(b.as_ref())? }; let t: Vec = unsafe { >::deserialize_full( &mut std::fs::File::open(&file)? )? }; -let t: MemCase<&[i32]> = unsafe { >::mmap(&file, Flags::empty())? }; +let t: MemCase> = unsafe { >::mmap(&file, Flags::empty())? }; // Within a structure #[derive(Epserde, Debug, PartialEq, Eq, Default, Clone)] @@ -584,7 +578,7 @@ let t: Data<&[i32]> = unsafe { >>::deserialize_eps(b.as_ref())? }; let t: Data> = unsafe { >>::deserialize_full( &mut std::fs::File::open(&file)? )? }; -let t: MemCase> = unsafe { >>::mmap(&file, Flags::empty())? }; +let t: MemCase>> = unsafe { >>::mmap(&file, Flags::empty())? }; # Ok(()) # } ``` diff --git a/epserde-derive/src/lib.rs b/epserde-derive/src/lib.rs index 5c0ff96..ec9e5bf 100644 --- a/epserde-derive/src/lib.rs +++ b/epserde-derive/src/lib.rs @@ -484,8 +484,9 @@ pub fn epserde_derive(input: TokenStream) -> TokenStream { } } + // SAFETY: &'epserde_desertype Self is covariant #[automatically_derived] - impl<#generics_deserialize> epserde::deser::DeserializeInner for #name<#concat_generics> #where_clause_des + unsafe impl<#generics_deserialize> epserde::deser::DeserializeInner for #name<#concat_generics> #where_clause_des { unsafe fn _deserialize_full_inner( backend: &mut impl epserde::deser::ReadWithPos, @@ -540,8 +541,9 @@ pub fn epserde_derive(input: TokenStream) -> TokenStream { } } + // SAFETY: #name is a struct, so it is covariant #[automatically_derived] - impl<#generics_deserialize> epserde::deser::DeserializeInner for #name<#concat_generics> #where_clause_des { + unsafe impl<#generics_deserialize> epserde::deser::DeserializeInner for #name<#concat_generics> #where_clause_des { unsafe fn _deserialize_full_inner( backend: &mut impl epserde::deser::ReadWithPos, ) -> core::result::Result { @@ -824,8 +826,9 @@ pub fn epserde_derive(input: TokenStream) -> TokenStream { } } + // SAFETY: &'epserde_desertype Self is covariant #[automatically_derived] - impl<#generics_deserialize> epserde::deser::DeserializeInner for #name<#concat_generics> #where_clause_des { + unsafe impl<#generics_deserialize> epserde::deser::DeserializeInner for #name<#concat_generics> #where_clause_des { unsafe fn _deserialize_full_inner( backend: &mut impl epserde::deser::ReadWithPos, ) -> core::result::Result { @@ -878,8 +881,9 @@ pub fn epserde_derive(input: TokenStream) -> TokenStream { Ok(()) } } + // SAFETY: #name is an enum, so it is covariant #[automatically_derived] - impl<#generics_deserialize> epserde::deser::DeserializeInner for #name<#concat_generics> #where_clause_des { + unsafe impl<#generics_deserialize> epserde::deser::DeserializeInner for #name<#concat_generics> #where_clause_des { unsafe fn _deserialize_full_inner( backend: &mut impl epserde::deser::ReadWithPos, ) -> core::result::Result { diff --git a/epserde/src/deser/mem_case.rs b/epserde/src/deser/mem_case.rs index dabce95..42c0593 100644 --- a/epserde/src/deser/mem_case.rs +++ b/epserde/src/deser/mem_case.rs @@ -4,8 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later */ +use crate::DeserializeInner; use bitflags::bitflags; -use core::{mem::size_of, ops::Deref}; +use core::{fmt, mem::size_of}; use maligned::A64; use mem_dbg::{MemDbg, MemSize}; @@ -111,36 +112,41 @@ impl MemBackend { /// wrapped type, using the no-op [`None`](`MemBackend#variant.None`) variant /// of [`MemBackend`], so a structure can be [encased](MemCase::encase) /// almost transparently. -#[derive(Debug, MemDbg, MemSize)] -pub struct MemCase(pub(crate) S, pub(crate) MemBackend); +#[derive(MemDbg, MemSize)] +pub struct MemCase<'a, S: DeserializeInner>( + pub(crate) ::DeserType<'a>, + pub(crate) MemBackend, +); -impl MemCase { - /// Encases a data structure in a [`MemCase`] with no backend. - pub fn encase(s: S) -> MemCase { - MemCase(s, MemBackend::None) +impl<'a, S: DeserializeInner> fmt::Debug for MemCase<'a, S> +where + ::DeserType<'a>: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("MemBackend") + .field(&self.0) + .field(&self.1) + .finish() } } -unsafe impl Send for MemCase {} -unsafe impl Sync for MemCase {} - -impl Deref for MemCase { - type Target = S; - #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.0 +impl<'a, S: DeserializeInner> MemCase<'a, S> { + /// Encases a data structure in a [`MemCase`] with no backend. + pub fn encase(s: ::DeserType<'a>) -> Self { + MemCase(s, MemBackend::None) } -} -impl AsRef for MemCase { - #[inline(always)] - fn as_ref(&self) -> &S { - &self.0 + pub fn borrow<'this>(&'this self) -> &'this ::DeserType<'this> { + // SAFETY: 'a outlives 'this, and ::DeserType is required to be + // covariant (ie. it's a normal structure and not, say, a closure with 'this as argument) + unsafe { + core::mem::transmute::< + &'this ::DeserType<'a>, + &'this ::DeserType<'this>, + >(&self.0) + } } } -impl From for MemCase { - fn from(s: S) -> Self { - MemCase::encase(s) - } -} +unsafe impl<'a, S: DeserializeInner + Send> Send for MemCase<'a, S> {} +unsafe impl<'a, S: DeserializeInner + Sync> Sync for MemCase<'a, S> {} diff --git a/epserde/src/deser/mod.rs b/epserde/src/deser/mod.rs index ebe7bca..b63a525 100644 --- a/epserde/src/deser/mod.rs +++ b/epserde/src/deser/mod.rs @@ -64,6 +64,8 @@ pub type DeserType<'a, T> = ::DeserType<'a>; /// incompatible structures using the same code, or cause undefined behavior /// by loading data with an incorrect alignment. /// - Memory-mapped files might be modified externally. +/// - [`Self::DeserType`] must be covariant (ie. behave like a structure, +/// not a closure with a generic argument) pub trait Deserialize: DeserializeInner { /// Fully deserialize a structure of this type from the given backend. /// @@ -99,9 +101,7 @@ pub trait Deserialize: DeserializeInner { /// # Safety /// /// See the [trait documentation](Deserialize). - unsafe fn load_mem<'a>( - path: impl AsRef, - ) -> anyhow::Result::DeserType<'a>>> { + unsafe fn load_mem<'a>(path: impl AsRef) -> anyhow::Result> { let align_to = align_of::(); if align_of::() > align_to { return Err(Error::AlignmentError.into()); @@ -111,8 +111,7 @@ pub trait Deserialize: DeserializeInner { // Round up to u128 size let capacity = file_len + crate::pad_align_to(file_len, align_to); - let mut uninit: MaybeUninit::DeserType<'_>>> = - MaybeUninit::uninit(); + let mut uninit: MaybeUninit> = MaybeUninit::uninit(); let ptr = uninit.as_mut_ptr(); // SAFETY: the entire vector will be filled with data read from the file, @@ -170,13 +169,12 @@ pub trait Deserialize: DeserializeInner { unsafe fn load_mmap<'a>( path: impl AsRef, flags: Flags, - ) -> anyhow::Result::DeserType<'a>>> { + ) -> anyhow::Result> { let file_len = path.as_ref().metadata()?.len() as usize; let mut file = std::fs::File::open(path)?; let capacity = file_len + crate::pad_align_to(file_len, 16); - let mut uninit: MaybeUninit::DeserType<'_>>> = - MaybeUninit::uninit(); + let mut uninit: MaybeUninit> = MaybeUninit::uninit(); let ptr = uninit.as_mut_ptr(); let mut mmap = mmap_rs::MmapOptions::new(capacity)? @@ -217,15 +215,11 @@ pub trait Deserialize: DeserializeInner { /// /// See the [trait documentation](Deserialize) and [mmap's `with_file`'s documentation](mmap_rs::MmapOptions::with_file). #[cfg(feature = "mmap")] - unsafe fn mmap<'a>( - path: impl AsRef, - flags: Flags, - ) -> anyhow::Result::DeserType<'a>>> { + unsafe fn mmap<'a>(path: impl AsRef, flags: Flags) -> anyhow::Result> { let file_len = path.as_ref().metadata()?.len(); let file = std::fs::File::open(path)?; - let mut uninit: MaybeUninit::DeserType<'_>>> = - MaybeUninit::uninit(); + let mut uninit: MaybeUninit> = MaybeUninit::uninit(); let ptr = uninit.as_mut_ptr(); let mmap = unsafe { @@ -261,7 +255,11 @@ pub trait Deserialize: DeserializeInner { /// the user from modifying the methods in [`Deserialize`]. /// /// The user should not implement this trait directly, but rather derive it. -pub trait DeserializeInner: Sized { +/// +/// # Safety +/// +/// See [`Deserialize`] +pub unsafe trait DeserializeInner: Sized { /// The deserialization type associated with this type. It can be /// retrieved conveniently with the alias [`DeserType`]. type DeserType<'a>; diff --git a/epserde/src/impls/array.rs b/epserde/src/impls/array.rs index 9e8b7d0..4a6ad3f 100644 --- a/epserde/src/impls/array.rs +++ b/epserde/src/impls/array.rs @@ -75,7 +75,7 @@ impl SerializeHelper for [T; } } -impl DeserializeInner for [T; N] +unsafe impl DeserializeInner for [T; N] where [T; N]: DeserializeHelper<::Copy, FullType = [T; N]>, { diff --git a/epserde/src/impls/boxed_slice.rs b/epserde/src/impls/boxed_slice.rs index 2ae717e..5608774 100644 --- a/epserde/src/impls/boxed_slice.rs +++ b/epserde/src/impls/boxed_slice.rs @@ -60,7 +60,7 @@ impl SerializeHelper for Box<[T]> { } // This delegates to a private helper trait which we can specialize on in stable rust -impl DeserializeInner for Box<[T]> +unsafe impl DeserializeInner for Box<[T]> where Box<[T]>: DeserializeHelper<::Copy, FullType = Box<[T]>>, { diff --git a/epserde/src/impls/prim.rs b/epserde/src/impls/prim.rs index fc9ba21..4fdd5a9 100644 --- a/epserde/src/impls/prim.rs +++ b/epserde/src/impls/prim.rs @@ -67,7 +67,7 @@ macro_rules! impl_prim_ser_des { } } - impl DeserializeInner for $ty { + unsafe impl DeserializeInner for $ty { #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<$ty> { let mut buf = [0; size_of::<$ty>()]; @@ -109,7 +109,7 @@ macro_rules! impl_nonzero_ser_des { } } - impl DeserializeInner for $ty { + unsafe impl DeserializeInner for $ty { #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<$ty> { let mut buf = [0; size_of::<$ty>()]; @@ -179,7 +179,7 @@ impl SerializeInner for bool { } } -impl DeserializeInner for bool { +unsafe impl DeserializeInner for bool { #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { Ok(u8::_deserialize_full_inner(backend)? != 0) @@ -208,7 +208,7 @@ impl SerializeInner for char { } } -impl DeserializeInner for char { +unsafe impl DeserializeInner for char { #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { Ok(char::from_u32(u32::_deserialize_full_inner(backend)?).unwrap()) @@ -235,7 +235,7 @@ impl SerializeInner for () { } } -impl DeserializeInner for () { +unsafe impl DeserializeInner for () { #[inline(always)] unsafe fn _deserialize_full_inner(_backend: &mut impl ReadWithPos) -> deser::Result { Ok(()) @@ -288,7 +288,7 @@ impl SerializeInner for PhantomData { } } -impl DeserializeInner for PhantomData { +unsafe impl DeserializeInner for PhantomData { #[inline(always)] unsafe fn _deserialize_full_inner(_backend: &mut impl ReadWithPos) -> deser::Result { Ok(PhantomData::) @@ -339,7 +339,7 @@ impl SerializeInner for Option { } } -impl DeserializeInner for Option { +unsafe impl DeserializeInner for Option { #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { let tag = u8::_deserialize_full_inner(backend)?; diff --git a/epserde/src/impls/stdlib.rs b/epserde/src/impls/stdlib.rs index 8375662..7c1eb6d 100644 --- a/epserde/src/impls/stdlib.rs +++ b/epserde/src/impls/stdlib.rs @@ -94,7 +94,7 @@ impl SerializeInner } } -impl DeserializeInner for core::ops::Range { +unsafe impl DeserializeInner for core::ops::Range { #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { let start = Idx::_deserialize_full_inner(backend)?; @@ -126,7 +126,7 @@ impl SerializeInner } } -impl DeserializeInner for core::ops::RangeFrom { +unsafe impl DeserializeInner for core::ops::RangeFrom { #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { let start = Idx::_deserialize_full_inner(backend)?; @@ -158,7 +158,7 @@ impl SerializeInner } } -impl DeserializeInner for core::ops::RangeInclusive { +unsafe impl DeserializeInner for core::ops::RangeInclusive { #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { let start = Idx::_deserialize_full_inner(backend)?; @@ -194,7 +194,7 @@ impl SerializeInner } } -impl DeserializeInner for core::ops::RangeTo { +unsafe impl DeserializeInner for core::ops::RangeTo { #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { let end = Idx::_deserialize_full_inner(backend)?; @@ -224,7 +224,9 @@ impl SerializeInner } } -impl DeserializeInner for core::ops::RangeToInclusive { +unsafe impl DeserializeInner + for core::ops::RangeToInclusive +{ #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { let end = Idx::_deserialize_full_inner(backend)?; @@ -251,7 +253,7 @@ impl SerializeInner for core::ops::RangeFull { } } -impl DeserializeInner for core::ops::RangeFull { +unsafe impl DeserializeInner for core::ops::RangeFull { #[inline(always)] unsafe fn _deserialize_full_inner(_backend: &mut impl ReadWithPos) -> deser::Result { Ok(core::ops::RangeFull) @@ -301,7 +303,7 @@ impl SerializeInner for core::ops::Bou } } -impl DeserializeInner for core::ops::Bound { +unsafe impl DeserializeInner for core::ops::Bound { #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { let tag = u8::_deserialize_full_inner(backend)?; @@ -376,7 +378,9 @@ impl DeserializeInner for core::ops::ControlFlow { +unsafe impl DeserializeInner + for core::ops::ControlFlow +{ #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { let tag = u8::_deserialize_full_inner(backend)?; diff --git a/epserde/src/impls/string.rs b/epserde/src/impls/string.rs index 2a1a668..17e2dae 100644 --- a/epserde/src/impls/string.rs +++ b/epserde/src/impls/string.rs @@ -65,7 +65,7 @@ impl SerializeInner for String { } } -impl DeserializeInner for String { +unsafe impl DeserializeInner for String { unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { let slice = deserialize_full_vec_zero(backend)?; Ok(String::from_utf8(slice).unwrap()) @@ -99,7 +99,7 @@ impl SerializeInner for Box { } } -impl DeserializeInner for Box { +unsafe impl DeserializeInner for Box { #[inline(always)] unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { Ok(String::_deserialize_full_inner(backend)?.into_boxed_str()) diff --git a/epserde/src/impls/tuple.rs b/epserde/src/impls/tuple.rs index 7ec267e..e5e1e6c 100644 --- a/epserde/src/impls/tuple.rs +++ b/epserde/src/impls/tuple.rs @@ -87,7 +87,7 @@ macro_rules! impl_tuples { } } - impl DeserializeInner for ($($t,)*) { + unsafe impl DeserializeInner for ($($t,)*) { type DeserType<'a> = &'a ($($t,)*); unsafe fn _deserialize_full_inner(backend: &mut impl ReadWithPos) -> deser::Result { deserialize_full_zero::<($($t,)*)>(backend) diff --git a/epserde/src/impls/vec.rs b/epserde/src/impls/vec.rs index 72c3978..3a75a6b 100644 --- a/epserde/src/impls/vec.rs +++ b/epserde/src/impls/vec.rs @@ -66,7 +66,7 @@ impl SerializeHelper for Vec { } // This delegates to a private helper trait which we can specialize on in stable rust -impl DeserializeInner for Vec +unsafe impl DeserializeInner for Vec where Vec: DeserializeHelper<::Copy, FullType = Vec>, { diff --git a/epserde/src/lib.rs b/epserde/src/lib.rs index 37668b0..0e9e045 100644 --- a/epserde/src/lib.rs +++ b/epserde/src/lib.rs @@ -147,7 +147,7 @@ impl SerializeInner for PhantomDeserData { } } -impl DeserializeInner for PhantomDeserData { +unsafe impl DeserializeInner for PhantomDeserData { #[inline(always)] unsafe fn _deserialize_full_inner(_backend: &mut impl ReadWithPos) -> deser::Result { Ok(PhantomDeserData(PhantomData)) diff --git a/epserde/tests/test_memcase.rs b/epserde/tests/test_memcase.rs index 241d0c7..838e09a 100644 --- a/epserde/tests/test_memcase.rs +++ b/epserde/tests/test_memcase.rs @@ -37,18 +37,21 @@ fn test_mem_case() { unsafe { person.store("test.bin").unwrap() }; let res = unsafe { Person::load_mem("test.bin").unwrap() }; + let res = res.borrow(); assert_eq!(person.test, res.test); assert_eq!(person.a, res.a); assert_eq!(person.b.a, res.b.a); assert_eq!(person.b.b, res.b.b); let res = unsafe { Person::load_mmap("test.bin", Flags::empty()).unwrap() }; + let res = res.borrow(); assert_eq!(person.test, res.test); assert_eq!(person.a, res.a); assert_eq!(person.b.a, res.b.a); assert_eq!(person.b.b, res.b.b); let res = unsafe { Person::load_mem("test.bin").unwrap() }; + let res = res.borrow(); assert_eq!(person.test, res.test); assert_eq!(person.a, res.a); assert_eq!(person.b.a, res.b.a); @@ -61,18 +64,21 @@ fn test_mem_case() { assert_eq!(person.b.b, res.b.b); let res = unsafe { Person::mmap("test.bin", Flags::empty()).unwrap() }; + let res = res.borrow(); assert_eq!(person.test, res.test); assert_eq!(person.a, res.a); assert_eq!(person.b.a, res.b.a); assert_eq!(person.b.b, res.b.b); let res = unsafe { Person::mmap("test.bin", Flags::TRANSPARENT_HUGE_PAGES).unwrap() }; + let res = res.borrow(); assert_eq!(person.test, res.test); assert_eq!(person.a, res.a); assert_eq!(person.b.a, res.b.a); assert_eq!(person.b.b, res.b.b); let res = unsafe { Person::mmap("test.bin", Flags::empty()).unwrap() }; + let res = res.borrow(); assert_eq!(person.test, res.test); assert_eq!(person.a, res.a); assert_eq!(person.b.a, res.b.a);