Skip to main content

rkyv/
boxed.rs

1//! An archived version of `Box`.
2
3use core::{borrow::Borrow, cmp, fmt, hash, ops::Deref};
4
5use munge::munge;
6use rancor::Fallible;
7
8use crate::{
9    primitive::FixedUsize, seal::Seal, traits::ArchivePointee, ArchiveUnsized,
10    Place, Portable, RelPtr, SerializeUnsized,
11};
12
13/// An archived [`Box`].
14///
15/// This is a thin `#[repr(transparent)]` wrapper around a [`RelPtr`] to the
16/// archived type.
17#[derive(Portable)]
18#[rkyv(crate)]
19#[cfg_attr(
20    feature = "bytecheck",
21    derive(bytecheck::CheckBytes),
22    bytecheck(verify)
23)]
24#[repr(transparent)]
25pub struct ArchivedBox<T: ArchivePointee + ?Sized> {
26    ptr: RelPtr<T>,
27}
28
29impl<T: ArchivePointee + ?Sized> ArchivedBox<T> {
30    /// Returns a reference to the value of this archived box.
31    pub fn get(&self) -> &T {
32        unsafe { &*self.ptr.as_ptr() }
33    }
34
35    /// Returns a sealed mutable reference to the value of this archived box.
36    pub fn get_seal(this: Seal<'_, Self>) -> Seal<'_, T> {
37        munge!(let Self { ptr } = this);
38        Seal::new(unsafe { &mut *RelPtr::as_mut_ptr(ptr) })
39    }
40
41    /// Resolves an archived box from the given value and parameters.
42    pub fn resolve_from_ref<U: ArchiveUnsized<Archived = T> + ?Sized>(
43        value: &U,
44        resolver: BoxResolver,
45        out: Place<Self>,
46    ) {
47        Self::resolve_from_raw_parts(resolver, value.archived_metadata(), out)
48    }
49
50    /// Serializes an archived box from the given value and serializer.
51    pub fn serialize_from_ref<U, S>(
52        value: &U,
53        serializer: &mut S,
54    ) -> Result<BoxResolver, S::Error>
55    where
56        U: SerializeUnsized<S, Archived = T> + ?Sized,
57        S: Fallible + ?Sized,
58    {
59        Ok(BoxResolver {
60            pos: value.serialize_unsized(serializer)? as FixedUsize,
61        })
62    }
63
64    /// Resolves an archived box from a [`BoxResolver`] and the raw metadata
65    /// directly.
66    pub fn resolve_from_raw_parts(
67        resolver: BoxResolver,
68        metadata: T::ArchivedMetadata,
69        out: Place<Self>,
70    ) {
71        munge!(let ArchivedBox { ptr } = out);
72        RelPtr::emplace_unsized(resolver.pos as usize, metadata, ptr);
73    }
74}
75
76impl<T: ArchivePointee + ?Sized> AsRef<T> for ArchivedBox<T> {
77    fn as_ref(&self) -> &T {
78        self.get()
79    }
80}
81
82impl<T: ArchivePointee + ?Sized> Borrow<T> for ArchivedBox<T> {
83    fn borrow(&self) -> &T {
84        self.get()
85    }
86}
87
88impl<T: ArchivePointee + ?Sized> fmt::Debug for ArchivedBox<T>
89where
90    T::ArchivedMetadata: fmt::Debug,
91{
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        f.debug_tuple("ArchivedBox").field(&self.ptr).finish()
94    }
95}
96
97impl<T: ArchivePointee + ?Sized> Deref for ArchivedBox<T> {
98    type Target = T;
99
100    fn deref(&self) -> &Self::Target {
101        self.get()
102    }
103}
104
105impl<T: ArchivePointee + fmt::Display + ?Sized> fmt::Display
106    for ArchivedBox<T>
107{
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        self.get().fmt(f)
110    }
111}
112
113impl<T: ArchivePointee + Eq + ?Sized> Eq for ArchivedBox<T> {}
114
115impl<T: ArchivePointee + hash::Hash + ?Sized> hash::Hash for ArchivedBox<T> {
116    fn hash<H: hash::Hasher>(&self, state: &mut H) {
117        self.get().hash(state);
118    }
119}
120
121impl<T: ArchivePointee + Ord + ?Sized> Ord for ArchivedBox<T> {
122    fn cmp(&self, other: &Self) -> cmp::Ordering {
123        self.as_ref().cmp(other.as_ref())
124    }
125}
126
127impl<T: ArchivePointee + PartialEq<U> + ?Sized, U: ArchivePointee + ?Sized>
128    PartialEq<ArchivedBox<U>> for ArchivedBox<T>
129{
130    fn eq(&self, other: &ArchivedBox<U>) -> bool {
131        self.get().eq(other.get())
132    }
133}
134
135impl<T: ArchivePointee + PartialOrd + ?Sized> PartialOrd for ArchivedBox<T> {
136    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
137        self.get().partial_cmp(other.get())
138    }
139}
140
141impl<T: ArchivePointee + ?Sized> fmt::Pointer for ArchivedBox<T> {
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143        let ptr = self.get() as *const T;
144        fmt::Pointer::fmt(&ptr, f)
145    }
146}
147
148/// The resolver for `Box`.
149pub struct BoxResolver {
150    pos: FixedUsize,
151}
152
153impl BoxResolver {
154    /// Creates a new [`BoxResolver`] from the position of a serialized value.
155    ///
156    /// In most cases, you won't need to create a [`BoxResolver`] yourself and
157    /// can instead obtain it through [`ArchivedBox::serialize_from_ref`].
158    pub fn from_pos(pos: usize) -> Self {
159        Self {
160            pos: pos as FixedUsize,
161        }
162    }
163}
164
165#[cfg(feature = "bytecheck")]
166mod verify {
167    use bytecheck::{
168        rancor::{Fallible, Source},
169        CheckBytes, Verify,
170    };
171
172    use crate::{
173        boxed::ArchivedBox,
174        traits::{ArchivePointee, LayoutRaw},
175        validation::{ArchiveContext, ArchiveContextExt},
176    };
177
178    unsafe impl<T, C> Verify<C> for ArchivedBox<T>
179    where
180        T: ArchivePointee + CheckBytes<C> + LayoutRaw + ?Sized,
181        T::ArchivedMetadata: CheckBytes<C>,
182        C: Fallible + ArchiveContext + ?Sized,
183        C::Error: Source,
184    {
185        fn verify(&self, context: &mut C) -> Result<(), C::Error> {
186            let ptr = self.ptr.as_ptr_wrapping();
187            context.in_subtree(ptr, |context| unsafe {
188                T::check_bytes(ptr, context)
189            })
190        }
191    }
192}