use core::cmp::Ordering;
use core::marker::{PhantomData, PhantomPinned};
use core::mem::MaybeUninit;
use core::ptr::{Alignment, copy_nonoverlapping};
use crate::boxed::ArchivedBox;
use crate::impls::lexicographical_partial_ord;
use crate::list::ArchivedList;
use crate::primitive::{ArchivedUsize, FixedUsize};
use crate::string::ArchivedString;
use crate::util::{align_offset, max_alignment, offset_archived};
use crate::{Serialize, SerializeError, VerifyError};
impl<T: Serialize> Serialize for Box<T> {
type Archived = ArchivedBox<T::Archived>;
const ALIGN: Alignment = max_alignment([Alignment::of::<ArchivedUsize>(), T::ALIGN]);
unsafe fn serialize(
&self,
out: *mut MaybeUninit<ArchivedBox<T::Archived>>,
heap: *mut MaybeUninit<u8>,
) -> usize {
let align_size = align_offset::<T::Archived>(heap as usize);
unsafe {
let heap = heap.add(align_size);
*out = MaybeUninit::new(ArchivedBox {
offset: ArchivedUsize::from_native(heap.offset_from_unsigned(out.cast()) as _),
_phantom_data: PhantomData,
_phantom_pinned: PhantomPinned,
});
if T::COPY_OPTIMIZATION {
copy_nonoverlapping((&raw const **self).cast(), heap, size_of::<T>());
align_size + size_of::<T::Archived>()
} else {
align_size
+ size_of::<T::Archived>()
+ (**self).serialize(heap.cast(), heap.add(size_of::<T::Archived>()))
}
}
}
fn serialized_size(&self, offset: usize) -> Result<usize, SerializeError> {
if (FixedUsize::MAX as usize) < offset + align_offset::<T::Archived>(offset) {
Err(SerializeError::OverflowedPointer)
} else {
let type_size = align_offset::<T::Archived>(offset) + size_of::<T::Archived>();
(**self)
.serialized_size(offset + type_size)
.map(|size| size + type_size)
}
}
#[inline]
unsafe fn verify(
this: *const ArchivedBox<T::Archived>,
buffer_end: *const u8,
) -> Result<(), VerifyError> {
unsafe {
offset_archived(
this.cast(),
(*this).offset.to_native() as usize,
size_of::<T::Archived>(),
buffer_end,
Alignment::of::<T::Archived>(),
)
.and_then(|ptr| T::verify(ptr.cast(), buffer_end))
}
}
}
impl<T: Serialize> Serialize for Box<[T]> {
type Archived = ArchivedList<T::Archived>;
const ALIGN: Alignment = max_alignment([T::ALIGN, Alignment::of::<ArchivedUsize>()]);
unsafe fn serialize(
&self,
out: *mut MaybeUninit<ArchivedList<T::Archived>>,
heap: *mut MaybeUninit<u8>,
) -> usize {
unsafe { (**self).serialize(out, heap) }
}
fn serialized_size(&self, offset: usize) -> Result<usize, SerializeError> {
(**self).serialized_size(offset)
}
#[inline]
unsafe fn verify(
this: *const ArchivedList<T::Archived>,
buffer_end: *const u8,
) -> Result<(), VerifyError> {
unsafe { <[T]>::verify(this, buffer_end) }
}
}
impl Serialize for Box<str> {
type Archived = ArchivedString;
const ALIGN: Alignment = Alignment::of::<ArchivedUsize>();
unsafe fn serialize(
&self,
out: *mut MaybeUninit<ArchivedString>,
heap: *mut MaybeUninit<u8>,
) -> usize {
unsafe { (**self).serialize(out, heap) }
}
fn serialized_size(&self, offset: usize) -> Result<usize, SerializeError> {
(**self).serialized_size(offset)
}
#[inline]
unsafe fn verify(
this: *const ArchivedString,
buffer_end: *const u8,
) -> Result<(), VerifyError> {
unsafe { str::verify(this, buffer_end) }
}
}
impl<T: PartialEq<U>, U> PartialEq<Box<U>> for ArchivedBox<T> {
fn eq(&self, other: &Box<U>) -> bool {
self.get().eq(other.as_ref())
}
}
impl<T: PartialOrd<U>, U> PartialOrd<Box<U>> for ArchivedBox<T> {
fn partial_cmp(&self, other: &Box<U>) -> Option<Ordering> {
self.get().partial_cmp(other.as_ref())
}
}
impl<T: PartialEq<U>, U> PartialEq<Box<[U]>> for ArchivedList<T> {
fn eq(&self, other: &Box<[U]>) -> bool {
self.as_slice().eq(&**other)
}
}
impl<T: PartialOrd<U>, U> PartialOrd<Box<[U]>> for ArchivedList<T> {
fn partial_cmp(&self, other: &Box<[U]>) -> Option<Ordering> {
lexicographical_partial_ord(self.as_slice(), other)
}
}
impl<T: PartialEq<U>, U> PartialEq<ArchivedList<U>> for Box<[T]> {
fn eq(&self, other: &ArchivedList<U>) -> bool {
(**self).eq(other.as_slice())
}
}
impl<T: PartialOrd<U>, U> PartialOrd<ArchivedList<U>> for Box<[T]> {
fn partial_cmp(&self, other: &ArchivedList<U>) -> Option<Ordering> {
lexicographical_partial_ord(self, other.as_slice())
}
}
#[cfg(test)]
mod tests {
use crate::test::roundtrip;
#[test]
fn roundtrip_box() {
roundtrip(&Box::new(42));
roundtrip(&Box::new([1, 2, 3, 4, 5, 6]));
}
#[test]
fn roundtrip_boxed_str() {
roundtrip(&"".to_string().into_boxed_str());
roundtrip(&"hello world".to_string().into_boxed_str());
}
#[test]
fn roundtrip_boxed_slice() {
roundtrip(&Vec::<i32>::new().into_boxed_slice());
roundtrip(&vec![1, 2, 3, 4].into_boxed_slice());
}
#[test]
fn roundtrip_box_zsts() {
roundtrip(&Box::new(()));
roundtrip(&Vec::<()>::new().into_boxed_slice());
roundtrip(&vec![(), (), (), ()].into_boxed_slice());
}
#[test]
fn roundtrip_option_box() {
roundtrip(&Some(Box::new(42)));
roundtrip(&Some(Box::new([1, 2, 3, 4, 5, 6])));
}
#[test]
fn roundtrip_option_box_str() {
roundtrip(&Some("".to_string().into_boxed_str()));
roundtrip(&Some("hello world".to_string().into_boxed_str()));
}
#[test]
fn roundtrip_option_box_slice() {
roundtrip(&Some(Vec::<i32>::new().into_boxed_slice()));
roundtrip(&Some(vec![1, 2, 3, 4].into_boxed_slice()));
}
#[test]
fn roundtrip_result_box() {
roundtrip(&Ok::<_, ()>(Box::new(42)));
roundtrip(&Ok::<_, ()>(Box::new([1, 2, 3, 4, 5, 6])));
roundtrip(&Err::<(), _>(Box::new(42)));
roundtrip(&Err::<(), _>(Box::new([1, 2, 3, 4, 5, 6])));
}
#[test]
fn roundtrip_result_box_str() {
roundtrip(&Ok::<_, ()>("".to_string().into_boxed_str()));
roundtrip(&Ok::<_, ()>("hello world".to_string().into_boxed_str()));
roundtrip(&Err::<(), _>("".to_string().into_boxed_str()));
roundtrip(&Err::<(), _>("hello world".to_string().into_boxed_str()));
}
#[test]
fn roundtrip_result_box_slice() {
roundtrip(&Ok::<_, ()>(Vec::<i32>::new().into_boxed_slice()));
roundtrip(&Ok::<_, ()>(vec![1, 2, 3, 4].into_boxed_slice()));
roundtrip(&Err::<(), _>(Vec::<i32>::new().into_boxed_slice()));
roundtrip(&Err::<(), _>(vec![1, 2, 3, 4].into_boxed_slice()));
}
}