Skip to content

Commit

Permalink
Rewrite ArchiveCopy
Browse files Browse the repository at this point in the history
  • Loading branch information
djkoloski committed May 7, 2021
1 parent acee7c9 commit f438fa3
Show file tree
Hide file tree
Showing 15 changed files with 187 additions and 499 deletions.
120 changes: 108 additions & 12 deletions rkyv/src/copy.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,35 @@
use std::marker::{PhantomData, PhantomPinned};
use core::{
marker::{PhantomData, PhantomPinned},
num::{
NonZeroI8,
NonZeroI16,
NonZeroI32,
NonZeroI64,
NonZeroI128,
NonZeroIsize,
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU128,
NonZeroUsize
},
};
#[cfg(has_atomics)]
use core::sync::atomic::{
AtomicBool,
AtomicI8,
AtomicI16,
AtomicI32,
AtomicU8,
AtomicU16,
AtomicU32,
};
#[cfg(has_atomics_64)]
use core::sync::atomic::{
AtomicI64,
AtomicU64,
};

/// A type that is `Copy` and can be archived without additional processing.
///
Expand All @@ -8,6 +39,10 @@ use std::marker::{PhantomData, PhantomPinned};
#[rustc_unsafe_specialization_marker]
pub auto trait ArchiveCopy {}

// (), PhantomData, PhantomPinned, bool, i8, u8, NonZeroI8, and NonZeroU8 are always ArchiveCopy
impl<T: ?Sized> ArchiveCopy for PhantomData<T> {}

// Multibyte integers are not ArchiveCopy if the target does not match the archive endianness
#[cfg(any(
all(target_endian = "little", feature = "archive_be"),
all(target_endian = "big", feature = "archive_le"),
Expand All @@ -24,31 +59,71 @@ const _: () = {
impl !ArchiveCopy for f32 {}
impl !ArchiveCopy for f64 {}
impl !ArchiveCopy for char {}
impl !ArchiveCopy for NonZeroI16 {}
impl !ArchiveCopy for NonZeroI32 {}
impl !ArchiveCopy for NonZeroI64 {}
impl !ArchiveCopy for NonZeroI128 {}
impl !ArchiveCopy for NonZeroU16 {}
impl !ArchiveCopy for NonZeroU32 {}
impl !ArchiveCopy for NonZeroU64 {}
impl !ArchiveCopy for NonZeroU128 {}
};

impl !ArchiveCopy for isize {}
impl !ArchiveCopy for usize {}
// Pointer-sized integers are not ArchiveCopy if the target pointer width does not match the archive
// pointer width
#[cfg(any(
target_pointer_width = "16",
all(target_pointer_width = "32", feature = "size_64"),
all(target_pointer_width = "64", not(feature = "size_64"))
))]
const _: () = {
impl !ArchiveCopy for isize {}
impl !ArchiveCopy for usize {}
impl !ArchiveCopy for NonZeroIsize {}
impl !ArchiveCopy for NonZeroUsize {}
};

// Atomics are not ArchiveCopy if the platform supports them
#[cfg(has_atomics)]
const _: () = {
impl !ArchiveCopy for AtomicBool {}
impl !ArchiveCopy for AtomicI8 {}
impl !ArchiveCopy for AtomicI16 {}
impl !ArchiveCopy for AtomicI32 {}
impl !ArchiveCopy for AtomicU8 {}
impl !ArchiveCopy for AtomicU16 {}
impl !ArchiveCopy for AtomicU32 {}
};
#[cfg(has_atomics_64)]
const _: () = {
impl !ArchiveCopy for AtomicI64 {}
impl !ArchiveCopy for AtomicU64 {}
};

// Pointers and references are never ArchiveCopy
impl<T: ?Sized> !ArchiveCopy for *const T {}
impl<T: ?Sized> !ArchiveCopy for *mut T {}
impl<T: ?Sized> !ArchiveCopy for &T {}
impl<T: ?Sized> !ArchiveCopy for &mut T {}

impl !ArchiveCopy for PhantomPinned {}

/// Types that are `ArchiveCopy` and have no padding.
///
/// These types are always safe to `memcpy` around because they will never contain uninitialized
/// padding.
#[rustc_unsafe_specialization_marker]
pub unsafe trait ArchiveCopySafe: ArchiveCopy + Sized {
const PACKED_SIZE: usize;
}
pub unsafe trait ArchiveCopySafe: ArchiveCopy + Sized {}

// (), PhantomData, PhantomPinned, bool, i8, u8, NonZeroI8, and NonZeroU8 are always ArchiveCopySafe
unsafe impl ArchiveCopySafe for () {}
unsafe impl<T: ?Sized> ArchiveCopySafe for PhantomData<T> {}
unsafe impl ArchiveCopySafe for PhantomPinned {}
unsafe impl ArchiveCopySafe for bool {}
unsafe impl ArchiveCopySafe for i8 {}
unsafe impl ArchiveCopySafe for u8 {}
unsafe impl ArchiveCopySafe for bool {}
unsafe impl ArchiveCopySafe for NonZeroI8 {}
unsafe impl ArchiveCopySafe for NonZeroU8 {}

// Multibytes integers are ArchiveCopySafe if the target matches the archived endianness
#[cfg(not(any(
all(target_endian = "little", feature = "archive_be"),
all(target_endian = "big", feature = "archive_le"),
Expand All @@ -65,18 +140,39 @@ const _: () = {
unsafe impl ArchiveCopySafe for f32 {}
unsafe impl ArchiveCopySafe for f64 {}
unsafe impl ArchiveCopySafe for char {}
unsafe impl ArchiveCopySafe for NonZeroI16 {}
unsafe impl ArchiveCopySafe for NonZeroI32 {}
unsafe impl ArchiveCopySafe for NonZeroI64 {}
unsafe impl ArchiveCopySafe for NonZeroI128 {}
unsafe impl ArchiveCopySafe for NonZeroU16 {}
unsafe impl ArchiveCopySafe for NonZeroU32 {}
unsafe impl ArchiveCopySafe for NonZeroU64 {}
unsafe impl ArchiveCopySafe for NonZeroU128 {}
};

unsafe impl ArchiveCopySafe for () {}
unsafe impl<T: ?Sized> ArchiveCopySafe for PhantomData<T> {}
unsafe impl<T: ArchiveCopySafe, const N: usize> ArchiveCopySafe for [T; N] {}
// Pointer-sized integers are ArchiveCopySafe if the target pointer width matches the archive
// pointer width
#[cfg(not(any(
target_pointer_width = "16",
all(target_pointer_width = "32", feature = "size_64"),
all(target_pointer_width = "64", not(feature = "size_64"))
)))]
const _: () = {
impl ArchiveCopySafe for isize {}
impl ArchiveCopySafe for usize {}
impl ArchiveCopySafe for NonZeroIsize {}
impl ArchiveCopySafe for NonZeroUsize {}
};

macro_rules! impl_tuple {
() => {};
(T, $($ts:ident,)*) => {
unsafe impl<T: ArchiveCopySafe> ArchiveCopySafe for (T, $($ts,)*) {}

impl_tuple!($($ts,)*);
};
}

impl_tuple!(T, T, T, T, T, T, T, T, T, T, T,);

unsafe impl<T: ArchiveCopySafe, const N: usize> ArchiveCopySafe for [T; N] {}
16 changes: 9 additions & 7 deletions rkyv/src/core_impl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use crate::{
ArchivePointee, ArchiveUnsized, Archived, ArchivedMetadata, ArchivedUsize,
Deserialize, DeserializeUnsized, Fallible, FixedUsize, Serialize, SerializeUnsized,
};
#[cfg(feature = "copy")]
use crate::copy::ArchiveCopySafe;
use core::{
alloc, cmp,
hash::{Hash, Hasher},
Expand Down Expand Up @@ -299,8 +301,8 @@ impl<T: Archive<Resolver = ()> + Serialize<S>, S: Serializer + ?Sized> Serialize
}
}

#[cfg(all(not(feature = "std"), feature = "specialization"))]
impl<T: Archive<Resolver = ()> + crate::copy::ArchiveCopySafe + Serialize<S>, S: Serializer + ?Sized> SerializeUnsized<S> for [T] {
#[cfg(all(not(feature = "std"), feature = "copy"))]
impl<T: Archive<Resolver = ()> + Serialize<S> + crate::copy::ArchiveCopySafe, S: Serializer + ?Sized> SerializeUnsized<S> for [T] {
#[inline]
fn serialize_unsized(&self, serializer: &mut S) -> Result<usize, S::Error> {
if self.is_empty() || core::mem::size_of::<T::Archived>() == 0 {
Expand Down Expand Up @@ -355,8 +357,8 @@ impl<T: Serialize<S>, S: Serializer + ?Sized> SerializeUnsized<S> for [T] {
}
}

#[cfg(all(feature = "std", feature = "specialization"))]
impl<T: crate::copy::ArchiveCopySafe + Serialize<S>, S: Serializer + ?Sized> SerializeUnsized<S> for [T] {
#[cfg(all(feature = "std", feature = "copy"))]
impl<T: Serialize<S> + crate::copy::ArchiveCopySafe, S: Serializer + ?Sized> SerializeUnsized<S> for [T] {
#[inline]
fn serialize_unsized(&self, serializer: &mut S) -> Result<usize, S::Error> {
if self.is_empty() || core::mem::size_of::<T::Archived>() == 0 {
Expand All @@ -380,7 +382,7 @@ impl<T: crate::copy::ArchiveCopySafe + Serialize<S>, S: Serializer + ?Sized> Ser
}
}

impl<T: Deserialize<U, D>, U: Archive<Archived = T>, D: Deserializer + ?Sized>
impl<T: Deserialize<U, D>, U, D: Deserializer + ?Sized>
DeserializeUnsized<[U], D> for [T]
{
#[inline]
Expand Down Expand Up @@ -409,8 +411,8 @@ impl<T: Deserialize<U, D>, U: Archive<Archived = T>, D: Deserializer + ?Sized>
}

#[cfg(feature = "copy")]
impl<T: Deserialize<T, D> + ArchiveCopySafe, D: Deserializer + ?Sized> DeserializeUnsized<[T], D>
for [T]
impl<T: Deserialize<U, D>, U: ArchiveCopySafe, D: Deserializer + ?Sized>
DeserializeUnsized<[U], D> for [T]
{
#[inline]
unsafe fn deserialize_unsized(&self, deserializer: &mut D) -> Result<*mut (), D::Error> {
Expand Down
34 changes: 26 additions & 8 deletions rkyv/src/core_impl/primitive.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
Archive, ArchiveCopy, Archived, ArchivedIsize, ArchivedUsize, Fallible, FixedIsize, FixedUsize,
Archive, Archived, ArchivedIsize, ArchivedUsize, Fallible, FixedIsize, FixedUsize,
Serialize, Deserialize,
};
use core::{
Expand All @@ -16,6 +16,7 @@ use core::sync::atomic::{
};
#[cfg(has_atomics_64)]
use core::sync::atomic::{AtomicI64, AtomicU64};
use std::marker::PhantomPinned;

macro_rules! impl_primitive {
(@serialize_deserialize $type:ty) => {
Expand Down Expand Up @@ -47,8 +48,6 @@ macro_rules! impl_primitive {
}

impl_primitive!(@serialize_deserialize $type);

unsafe impl ArchiveCopy for $type {}
};
($type:ty, $type_le:ident, $type_be:ident) => {
impl Archive for $type {
Expand All @@ -70,9 +69,6 @@ macro_rules! impl_primitive {
}

impl_primitive!(@serialize_deserialize $type);

#[cfg(not(any(feature = "archive_le", feature = "archive_be")))]
unsafe impl ArchiveCopy for $type {}
};
}

Expand Down Expand Up @@ -197,15 +193,37 @@ impl<T: ?Sized, S: Fallible + ?Sized> Serialize<S> for PhantomData<T> {
}
}

unsafe impl<T: ?Sized> ArchiveCopy for PhantomData<T> {}

impl<T: ?Sized, D: Fallible + ?Sized> Deserialize<PhantomData<T>, D> for PhantomData<T> {
#[inline]
fn deserialize(&self, _: &mut D) -> Result<PhantomData<T>, D::Error> {
Ok(PhantomData)
}
}

// PhantomPinned
impl Archive for PhantomPinned {
type Archived = PhantomPinned;
type Resolver = ();

#[inline]
fn resolve(&self, _: usize, _: Self::Resolver, _: &mut MaybeUninit<Self::Archived>) {
}
}

impl<S: Fallible + ?Sized> Serialize<S> for PhantomPinned {
#[inline]
fn serialize(&self, _: &mut S) -> Result<Self::Resolver, S::Error> {
Ok(())
}
}

impl<D: Fallible + ?Sized> Deserialize<PhantomPinned, D> for PhantomPinned {
#[inline]
fn deserialize(&self, _: &mut D) -> Result<PhantomPinned, D::Error> {
Ok(PhantomPinned)
}
}

// usize

impl Archive for usize {
Expand Down
4 changes: 1 addition & 3 deletions rkyv/src/core_impl/range.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! [`Archive`] implementations for ranges.

use crate::{Archive, ArchiveCopy, Archived, Deserialize, Fallible, Serialize};
use crate::{Archive, Archived, Deserialize, Fallible, Serialize};
use core::{
cmp, fmt,
mem::MaybeUninit,
Expand All @@ -24,8 +24,6 @@ impl<S: Fallible + ?Sized> Serialize<S> for RangeFull {
}
}

unsafe impl ArchiveCopy for RangeFull {}

impl<D: Fallible + ?Sized> Deserialize<RangeFull, D> for RangeFull {
#[inline]
fn deserialize(&self, _: &mut D) -> Result<Self, D::Error> {
Expand Down
4 changes: 2 additions & 2 deletions rkyv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ pub trait Serialize<S: Fallible + ?Sized>: Archive {
/// Converts a type back from its archived form.
///
/// This can be derived with [`Deserialize`](macro@Deserialize).
pub trait Deserialize<T: Archive<Archived = Self>, D: Fallible + ?Sized> {
pub trait Deserialize<T, D: Fallible + ?Sized> {
/// Deserializes using the given deserializer
fn deserialize(&self, deserializer: &mut D) -> Result<T, D::Error>;
}
Expand Down Expand Up @@ -563,7 +563,7 @@ pub trait SerializeUnsized<S: Fallible + ?Sized>: ArchiveUnsized {
///
/// Most types that implement `DeserializeUnsized` will need a [`Deserializer`](de::Deserializer)
/// bound so that they can allocate memory.
pub trait DeserializeUnsized<T: ArchiveUnsized<Archived = Self> + ?Sized, D: Fallible + ?Sized>:
pub trait DeserializeUnsized<T: Pointee + ?Sized, D: Fallible + ?Sized>:
ArchivePointee
{
/// Deserializes a reference to the given value.
Expand Down
4 changes: 2 additions & 2 deletions rkyv/src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#[cfg(feature = "specialization")]
#[cfg(feature = "copy")]
macro_rules! default {
($($fn:tt)*) => { default $($fn)* };
}

#[cfg(not(feature = "specialization"))]
#[cfg(not(feature = "copy"))]
macro_rules! default {
($($fn:tt)*) => { $($fn)* };
}
Expand Down
12 changes: 4 additions & 8 deletions rkyv_bench/benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,8 @@ fn generate_vec<R: Rng, T: Generate>(rng: &mut R, range: core::ops::Range<usize>
result
}

#[derive(
Archive, Serialize, CheckBytes, Clone, Copy, Deserialize, serde::Deserialize, serde::Serialize,
)]
#[archive(copy)]
#[derive(Archive, Serialize, Clone, Copy, Deserialize, serde::Deserialize, serde::Serialize)]
#[archive_attr(derive(CheckBytes))]
#[repr(u8)]
pub enum GameType {
Survival,
Expand Down Expand Up @@ -141,10 +139,8 @@ impl Generate for Item {
}
}

#[derive(
Archive, Serialize, CheckBytes, Clone, Copy, Deserialize, serde::Serialize, serde::Deserialize,
)]
#[archive(copy)]
#[derive(Archive, Serialize, Clone, Copy, Deserialize, serde::Serialize, serde::Deserialize)]
#[archive_attr(derive(CheckBytes))]
pub struct Abilities {
walk_speed: f32,
fly_speed: f32,
Expand Down

0 comments on commit f438fa3

Please sign in to comment.