rkyv_test/
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    #[doc(hidden)]
62    #[inline]
63    pub fn is_null(&self) -> bool {
64        self.0.is_null()
65    }
66}
67
68impl<T> ArchivedBox<[T]> {
69    /// Serializes an archived `Box` from a given slice by directly copying bytes.
70    ///
71    /// # Safety
72    ///
73    /// The type being serialized must be copy-safe. Copy-safe types must be trivially copyable
74    /// (have the same archived and unarchived representations) and contain no padding bytes. In
75    /// situations where copying uninitialized bytes the output is acceptable, this function may be
76    /// used with types that contain padding bytes.
77    #[inline]
78    pub unsafe fn serialize_copy_from_slice<U, S>(
79        slice: &[U],
80        serializer: &mut S,
81    ) -> Result<BoxResolver<MetadataResolver<[U]>>, S::Error>
82    where
83        U: Serialize<S, Archived = T>,
84        S: Serializer + ?Sized,
85    {
86        use ::core::{mem::size_of, slice::from_raw_parts};
87
88        let pos = serializer.align_for::<T>()?;
89
90        let bytes = from_raw_parts(slice.as_ptr().cast::<u8>(), size_of::<T>() * slice.len());
91        serializer.write(bytes)?;
92
93        Ok(BoxResolver {
94            pos,
95            metadata_resolver: (),
96        })
97    }
98}
99
100impl<T: ArchivePointee + ?Sized> ArchivedBox<T>
101where
102    T::ArchivedMetadata: Default,
103{
104    #[doc(hidden)]
105    #[inline]
106    pub unsafe fn emplace_null(pos: usize, out: *mut Self) {
107        let (fp, fo) = out_field!(out.0);
108        RelPtr::emplace_null(pos + fp, fo);
109    }
110}
111
112impl<T: ArchivePointee + ?Sized> AsRef<T> for ArchivedBox<T> {
113    #[inline]
114    fn as_ref(&self) -> &T {
115        self.get()
116    }
117}
118
119impl<T: ArchivePointee + ?Sized> Borrow<T> for ArchivedBox<T> {
120    #[inline]
121    fn borrow(&self) -> &T {
122        self.get()
123    }
124}
125
126impl<T: ArchivePointee + ?Sized> fmt::Debug for ArchivedBox<T>
127where
128    T::ArchivedMetadata: fmt::Debug,
129{
130    #[inline]
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        f.debug_tuple("ArchivedBox").field(&self.0).finish()
133    }
134}
135
136impl<T: ArchivePointee + ?Sized> Deref for ArchivedBox<T> {
137    type Target = T;
138
139    #[inline]
140    fn deref(&self) -> &Self::Target {
141        self.get()
142    }
143}
144
145impl<T: ArchivePointee + fmt::Display + ?Sized> fmt::Display for ArchivedBox<T> {
146    #[inline]
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        self.get().fmt(f)
149    }
150}
151
152impl<T: ArchivePointee + Eq + ?Sized> Eq for ArchivedBox<T> {}
153
154impl<T: ArchivePointee + hash::Hash + ?Sized> hash::Hash for ArchivedBox<T> {
155    #[inline]
156    fn hash<H: hash::Hasher>(&self, state: &mut H) {
157        self.get().hash(state);
158    }
159}
160
161impl<T: ArchivePointee + Ord + ?Sized> Ord for ArchivedBox<T> {
162    #[inline]
163    fn cmp(&self, other: &Self) -> cmp::Ordering {
164        self.as_ref().cmp(other.as_ref())
165    }
166}
167
168impl<T: ArchivePointee + PartialEq<U> + ?Sized, U: ArchivePointee + ?Sized>
169    PartialEq<ArchivedBox<U>> for ArchivedBox<T>
170{
171    #[inline]
172    fn eq(&self, other: &ArchivedBox<U>) -> bool {
173        self.get().eq(other.get())
174    }
175}
176
177impl<T: ArchivePointee + PartialOrd + ?Sized> PartialOrd for ArchivedBox<T> {
178    #[inline]
179    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
180        self.get().partial_cmp(other.get())
181    }
182}
183
184impl<T: ArchivePointee + ?Sized> fmt::Pointer for ArchivedBox<T> {
185    #[inline]
186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187        let ptr = self.get() as *const T;
188        fmt::Pointer::fmt(&ptr, f)
189    }
190}
191
192/// The resolver for `Box`.
193pub struct BoxResolver<T> {
194    pos: usize,
195    metadata_resolver: T,
196}
197
198#[cfg(feature = "validation")]
199const _: () = {
200    use crate::validation::{
201        owned::{CheckOwnedPointerError, OwnedPointerError},
202        ArchiveContext, LayoutRaw,
203    };
204    use bytecheck::{CheckBytes, Error};
205    use ptr_meta::Pointee;
206
207    impl<T, C> CheckBytes<C> for ArchivedBox<T>
208    where
209        T: ArchivePointee + CheckBytes<C> + LayoutRaw + Pointee + ?Sized,
210        C: ArchiveContext + ?Sized,
211        T::ArchivedMetadata: CheckBytes<C>,
212        C::Error: Error,
213    {
214        type Error = CheckOwnedPointerError<T, C>;
215
216        #[inline]
217        unsafe fn check_bytes<'a>(
218            value: *const Self,
219            context: &mut C,
220        ) -> Result<&'a Self, Self::Error> {
221            let rel_ptr = RelPtr::<T>::manual_check_bytes(value.cast(), context)
222                .map_err(OwnedPointerError::PointerCheckBytesError)?;
223            let ptr = context
224                .check_subtree_rel_ptr(rel_ptr)
225                .map_err(OwnedPointerError::ContextError)?;
226
227            let range = context
228                .push_prefix_subtree(ptr)
229                .map_err(OwnedPointerError::ContextError)?;
230            T::check_bytes(ptr, context).map_err(OwnedPointerError::ValueCheckBytesError)?;
231            context
232                .pop_prefix_range(range)
233                .map_err(OwnedPointerError::ContextError)?;
234
235            Ok(&*value)
236        }
237    }
238};