rkyv/
boxed.rs

1//! An archived version of `Box`.
2
3use crate::{
4    ser::Serializer, ArchivePointee, ArchiveUnsized, Fallible, MetadataResolver, RelPtr, Serialize,
5    SerializeUnsized,
6};
7use core::{borrow::Borrow, cmp, fmt, hash, ops::Deref, pin::Pin};
8
9/// An archived [`Box`].
10///
11/// This is a thin wrapper around a [`RelPtr`] to the archived type.
12#[repr(transparent)]
13pub struct ArchivedBox<T: ArchivePointee + ?Sized>(RelPtr<T>);
14
15impl<T: ArchivePointee + ?Sized> ArchivedBox<T> {
16    /// Returns a reference to the value of this archived box.
17    #[inline]
18    pub fn get(&self) -> &T {
19        unsafe { &*self.0.as_ptr() }
20    }
21
22    /// Returns a pinned mutable reference to the value of this archived box
23    #[inline]
24    pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
25        unsafe { self.map_unchecked_mut(|s| &mut *s.0.as_mut_ptr()) }
26    }
27
28    /// Resolves an archived box from the given value and parameters.
29    ///
30    /// # Safety
31    ///
32    /// - `pos` must be the position of `out` within the archive
33    /// - `resolver` must be the result of serializing `value`
34    #[inline]
35    pub unsafe fn resolve_from_ref<U: ArchiveUnsized<Archived = T> + ?Sized>(
36        value: &U,
37        pos: usize,
38        resolver: BoxResolver<U::MetadataResolver>,
39        out: *mut Self,
40    ) {
41        let (fp, fo) = out_field!(out.0);
42        value.resolve_unsized(pos + fp, resolver.pos, resolver.metadata_resolver, fo);
43    }
44
45    /// Serializes an archived box from the given value and serializer.
46    #[inline]
47    pub fn serialize_from_ref<U, S>(
48        value: &U,
49        serializer: &mut S,
50    ) -> Result<BoxResolver<U::MetadataResolver>, S::Error>
51    where
52        U: SerializeUnsized<S, Archived = T> + ?Sized,
53        S: Fallible + ?Sized,
54    {
55        Ok(BoxResolver {
56            pos: value.serialize_unsized(serializer)?,
57            metadata_resolver: value.serialize_metadata(serializer)?,
58        })
59    }
60
61    /// Resolves an archived box from a [`BoxResolver`] which contains
62    /// the raw [`<T as ArchivePointee>::ArchivedMetadata`] directly.
63    ///
64    /// # Safety
65    ///
66    /// - `pos` must be the position of `out` within the archive
67    /// - `resolver` must be obtained by following the safety documentation of
68    /// [`BoxResolver::from_raw_parts`].
69    ///
70    /// [`<T as ArchivePointee>::ArchivedMetadata`]: ArchivePointee::ArchivedMetadata
71    pub unsafe fn resolve_from_raw_parts(
72        pos: usize,
73        resolver: BoxResolver<<T as ArchivePointee>::ArchivedMetadata>,
74        out: *mut Self,
75    ) {
76        let (fp, fo) = out_field!(out.0);
77        RelPtr::resolve_emplace_from_raw_parts(
78            pos + fp,
79            resolver.pos,
80            resolver.metadata_resolver,
81            fo,
82        );
83    }
84
85    #[doc(hidden)]
86    #[inline]
87    pub fn is_null(&self) -> bool {
88        self.0.is_null()
89    }
90}
91
92impl<T> ArchivedBox<[T]> {
93    /// Serializes an archived `Box` from a given slice by directly copying bytes.
94    ///
95    /// # Safety
96    ///
97    /// The type being serialized must be copy-safe. Copy-safe types must be trivially copyable
98    /// (have the same archived and unarchived representations) and contain no padding bytes. In
99    /// situations where copying uninitialized bytes the output is acceptable, this function may be
100    /// used with types that contain padding bytes.
101    #[inline]
102    pub unsafe fn serialize_copy_from_slice<U, S>(
103        slice: &[U],
104        serializer: &mut S,
105    ) -> Result<BoxResolver<MetadataResolver<[U]>>, S::Error>
106    where
107        U: Serialize<S, Archived = T>,
108        S: Serializer + ?Sized,
109    {
110        use ::core::{mem::size_of, slice::from_raw_parts};
111
112        let pos = serializer.align_for::<T>()?;
113
114        let bytes = from_raw_parts(slice.as_ptr().cast::<u8>(), size_of::<T>() * slice.len());
115        serializer.write(bytes)?;
116
117        Ok(BoxResolver {
118            pos,
119            metadata_resolver: (),
120        })
121    }
122}
123
124impl<T: ArchivePointee + ?Sized> ArchivedBox<T>
125where
126    T::ArchivedMetadata: Default,
127{
128    #[doc(hidden)]
129    #[inline]
130    pub unsafe fn emplace_null(pos: usize, out: *mut Self) {
131        let (fp, fo) = out_field!(out.0);
132        RelPtr::emplace_null(pos + fp, fo);
133    }
134}
135
136impl<T: ArchivePointee + ?Sized> AsRef<T> for ArchivedBox<T> {
137    #[inline]
138    fn as_ref(&self) -> &T {
139        self.get()
140    }
141}
142
143impl<T: ArchivePointee + ?Sized> Borrow<T> for ArchivedBox<T> {
144    #[inline]
145    fn borrow(&self) -> &T {
146        self.get()
147    }
148}
149
150impl<T: ArchivePointee + ?Sized> fmt::Debug for ArchivedBox<T>
151where
152    T::ArchivedMetadata: fmt::Debug,
153{
154    #[inline]
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        f.debug_tuple("ArchivedBox").field(&self.0).finish()
157    }
158}
159
160impl<T: ArchivePointee + ?Sized> Deref for ArchivedBox<T> {
161    type Target = T;
162
163    #[inline]
164    fn deref(&self) -> &Self::Target {
165        self.get()
166    }
167}
168
169impl<T: ArchivePointee + fmt::Display + ?Sized> fmt::Display for ArchivedBox<T> {
170    #[inline]
171    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172        self.get().fmt(f)
173    }
174}
175
176impl<T: ArchivePointee + Eq + ?Sized> Eq for ArchivedBox<T> {}
177
178impl<T: ArchivePointee + hash::Hash + ?Sized> hash::Hash for ArchivedBox<T> {
179    #[inline]
180    fn hash<H: hash::Hasher>(&self, state: &mut H) {
181        self.get().hash(state);
182    }
183}
184
185impl<T: ArchivePointee + Ord + ?Sized> Ord for ArchivedBox<T> {
186    #[inline]
187    fn cmp(&self, other: &Self) -> cmp::Ordering {
188        self.as_ref().cmp(other.as_ref())
189    }
190}
191
192impl<T: ArchivePointee + PartialEq<U> + ?Sized, U: ArchivePointee + ?Sized>
193    PartialEq<ArchivedBox<U>> for ArchivedBox<T>
194{
195    #[inline]
196    fn eq(&self, other: &ArchivedBox<U>) -> bool {
197        self.get().eq(other.get())
198    }
199}
200
201impl<T: ArchivePointee + PartialOrd + ?Sized> PartialOrd for ArchivedBox<T> {
202    #[inline]
203    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
204        self.get().partial_cmp(other.get())
205    }
206}
207
208impl<T: ArchivePointee + ?Sized> fmt::Pointer for ArchivedBox<T> {
209    #[inline]
210    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211        let ptr = self.get() as *const T;
212        fmt::Pointer::fmt(&ptr, f)
213    }
214}
215
216/// The resolver for `Box`.
217pub struct BoxResolver<M> {
218    pos: usize,
219    metadata_resolver: M,
220}
221
222impl<M> BoxResolver<M> {
223    /// Create a a new [`BoxResolver<M>`] from raw parts. Note that `M` here is ***not*** the same
224    /// `T` which should be serialized/contained in the resulting [`ArchivedBox<T>`], and is rather
225    /// a type that can be used to resolve any needed [`ArchivePointee::ArchivedMetadata`]
226    /// for the serialized pointed-to value.
227    ///
228    /// In most cases, you won't need to create a [`BoxResolver`] yourself and can instead obtain it through
229    /// [`ArchivedBox::serialize_from_ref`] or [`ArchivedBox::serialize_copy_from_slice`].
230    ///
231    /// # Safety
232    ///
233    /// Technically no unsafety can happen directly from calling this function, however, passing this as a resolver to
234    /// [`ArchivedBox`]'s resolving functions absolutely can. In general this should be treated as a semi-private type, as
235    /// constructing a valid resolver is quite fraught. Please make sure you understand what the implications are before doing it.
236    ///
237    /// - `pos`: You must ensure that you serialized and resolved (i.e. [`Serializer::serialize_value`])
238    /// a `T` which will be pointed to by the final [`ArchivedBox<T>`] that this resolver will help resolve
239    /// at the given `pos` within the archive.
240    ///
241    /// - `metadata_resolver`: You must also ensure that the given `metadata_resolver` can be used to successfully produce
242    /// valid [`<T as ArchivePointee>::ArchivedMetadata`] for that serialized `T`. This means it must either be:
243    ///     - The necessary [`<T as ArchivePointee>::ArchivedMetadata`] itself, in which case you may use the created
244    /// `BoxResolver<<T as ArchivePointee>::ArchivedMetadata>` as a resolver in [`ArchivedBox::resolve_from_raw_parts`]
245    ///     - An [`ArchiveUnsized::MetadataResolver`] obtained from some `value: &U` where `U: ArchiveUnsized<Archived = T>`, in which case you
246    /// must pass that same `value: &U` into [`ArchivedBox::resolve_from_ref`] along with this [`BoxResolver`].
247    ///
248    /// [`<T as ArchivePointee>::ArchivedMetadata`]: ArchivePointee::ArchivedMetadata
249    pub unsafe fn from_raw_parts(pos: usize, metadata_resolver: M) -> Self {
250        Self {
251            pos,
252            metadata_resolver,
253        }
254    }
255}
256
257#[cfg(feature = "validation")]
258const _: () = {
259    use crate::validation::{
260        owned::{CheckOwnedPointerError, OwnedPointerError},
261        ArchiveContext, LayoutRaw,
262    };
263    use bytecheck::{CheckBytes, Error};
264    use ptr_meta::Pointee;
265
266    impl<T, C> CheckBytes<C> for ArchivedBox<T>
267    where
268        T: ArchivePointee + CheckBytes<C> + LayoutRaw + Pointee + ?Sized,
269        C: ArchiveContext + ?Sized,
270        T::ArchivedMetadata: CheckBytes<C>,
271        C::Error: Error,
272    {
273        type Error = CheckOwnedPointerError<T, C>;
274
275        #[inline]
276        unsafe fn check_bytes<'a>(
277            value: *const Self,
278            context: &mut C,
279        ) -> Result<&'a Self, Self::Error> {
280            let rel_ptr = RelPtr::<T>::manual_check_bytes(value.cast(), context)
281                .map_err(OwnedPointerError::PointerCheckBytesError)?;
282            let ptr = context
283                .check_subtree_rel_ptr(rel_ptr)
284                .map_err(OwnedPointerError::ContextError)?;
285
286            let range = context
287                .push_prefix_subtree(ptr)
288                .map_err(OwnedPointerError::ContextError)?;
289            T::check_bytes(ptr, context).map_err(OwnedPointerError::ValueCheckBytesError)?;
290            context
291                .pop_prefix_range(range)
292                .map_err(OwnedPointerError::ContextError)?;
293
294            Ok(&*value)
295        }
296    }
297};