use core::{borrow::Borrow, cmp, fmt, hash, ops::Deref};
use munge::munge;
use rancor::Fallible;
use crate::{
primitive::FixedUsize, seal::Seal, traits::ArchivePointee, ArchiveUnsized,
Place, Portable, RelPtr, SerializeUnsized,
};
#[derive(Portable)]
#[rkyv(crate)]
#[cfg_attr(
feature = "bytecheck",
derive(bytecheck::CheckBytes),
bytecheck(verify)
)]
#[repr(transparent)]
pub struct ArchivedBox<T: ArchivePointee + ?Sized> {
ptr: RelPtr<T>,
}
impl<T: ArchivePointee + ?Sized> ArchivedBox<T> {
pub fn get(&self) -> &T {
unsafe { &*self.ptr.as_ptr() }
}
pub fn get_seal(this: Seal<'_, Self>) -> Seal<'_, T> {
munge!(let Self { ptr } = this);
Seal::new(unsafe { &mut *RelPtr::as_mut_ptr(ptr) })
}
pub fn resolve_from_ref<U: ArchiveUnsized<Archived = T> + ?Sized>(
value: &U,
resolver: BoxResolver,
out: Place<Self>,
) {
Self::resolve_from_raw_parts(resolver, value.archived_metadata(), out)
}
pub fn serialize_from_ref<U, S>(
value: &U,
serializer: &mut S,
) -> Result<BoxResolver, S::Error>
where
U: SerializeUnsized<S, Archived = T> + ?Sized,
S: Fallible + ?Sized,
{
Ok(BoxResolver {
pos: value.serialize_unsized(serializer)? as FixedUsize,
})
}
pub fn resolve_from_raw_parts(
resolver: BoxResolver,
metadata: T::ArchivedMetadata,
out: Place<Self>,
) {
munge!(let ArchivedBox { ptr } = out);
RelPtr::emplace_unsized(resolver.pos as usize, metadata, ptr);
}
}
impl<T: ArchivePointee + ?Sized> AsRef<T> for ArchivedBox<T> {
fn as_ref(&self) -> &T {
self.get()
}
}
impl<T: ArchivePointee + ?Sized> Borrow<T> for ArchivedBox<T> {
fn borrow(&self) -> &T {
self.get()
}
}
impl<T: ArchivePointee + ?Sized> fmt::Debug for ArchivedBox<T>
where
T::ArchivedMetadata: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("ArchivedBox").field(&self.ptr).finish()
}
}
impl<T: ArchivePointee + ?Sized> Deref for ArchivedBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.get()
}
}
impl<T: ArchivePointee + fmt::Display + ?Sized> fmt::Display
for ArchivedBox<T>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.get().fmt(f)
}
}
impl<T: ArchivePointee + Eq + ?Sized> Eq for ArchivedBox<T> {}
impl<T: ArchivePointee + hash::Hash + ?Sized> hash::Hash for ArchivedBox<T> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.get().hash(state);
}
}
impl<T: ArchivePointee + Ord + ?Sized> Ord for ArchivedBox<T> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_ref().cmp(other.as_ref())
}
}
impl<T: ArchivePointee + PartialEq<U> + ?Sized, U: ArchivePointee + ?Sized>
PartialEq<ArchivedBox<U>> for ArchivedBox<T>
{
fn eq(&self, other: &ArchivedBox<U>) -> bool {
self.get().eq(other.get())
}
}
impl<T: ArchivePointee + PartialOrd + ?Sized> PartialOrd for ArchivedBox<T> {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.get().partial_cmp(other.get())
}
}
impl<T: ArchivePointee + ?Sized> fmt::Pointer for ArchivedBox<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ptr = self.get() as *const T;
fmt::Pointer::fmt(&ptr, f)
}
}
pub struct BoxResolver {
pos: FixedUsize,
}
impl BoxResolver {
pub fn from_pos(pos: usize) -> Self {
Self {
pos: pos as FixedUsize,
}
}
}
#[cfg(feature = "bytecheck")]
mod verify {
use bytecheck::{
rancor::{Fallible, Source},
CheckBytes, Verify,
};
use crate::{
boxed::ArchivedBox,
traits::{ArchivePointee, LayoutRaw},
validation::{ArchiveContext, ArchiveContextExt},
};
unsafe impl<T, C> Verify<C> for ArchivedBox<T>
where
T: ArchivePointee + CheckBytes<C> + LayoutRaw + ?Sized,
T::ArchivedMetadata: CheckBytes<C>,
C: Fallible + ArchiveContext + ?Sized,
C::Error: Source,
{
fn verify(&self, context: &mut C) -> Result<(), C::Error> {
let ptr = self.ptr.as_ptr_wrapping();
context.in_subtree(ptr, |context| unsafe {
T::check_bytes(ptr, context)
})
}
}
}