Skip to main content

rkyv/
traits.rs

1//! The core traits provided by rkyv.
2
3use core::{
4    alloc::{Layout, LayoutError},
5    hash::Hash,
6    marker::PhantomData,
7};
8
9pub use ::rkyv_derive::{Archive, Deserialize, Portable, Serialize};
10
11use crate::{ptr_meta::Pointee, rancor::Fallible, ArchivedMetadata, Place};
12
13/// A type with a stable, well-defined layout that is the same on all targets.
14///
15/// # Safety
16///
17/// The implementing type must have a stable, well-defined layout that is the
18/// same on all targets. Structs and unions must be `#[repr(transparent)]` or
19/// `#[repr(C)]`. Enums must be `#[repr(C)]`, `#[repr(int)]`, or `#[repr(C,
20/// int)]`.
21///
22/// The implementing type must not have interior mutability (i.e. no
23/// `UnsafeCell`s).
24pub unsafe trait Portable {}
25
26/// A type with no undefined bytes.
27///
28/// # Safety
29///
30/// The bytes of types implementing `NoUndef` must always be well-defined. Among
31/// other things, this means that `NoUndef` types may not contain padding or
32/// uninitialized `MaybeUninit`s.
33pub unsafe trait NoUndef {}
34
35// SAFETY: An array of values which are all fully-initialized is also
36// fully-initalized.
37unsafe impl<T: NoUndef, const N: usize> NoUndef for [T; N] {}
38
39// SAFETY: An array of values which are all fully-initialized is also
40// fully-initalized.
41unsafe impl<T: NoUndef> NoUndef for [T] {}
42
43/// Returns the layout of a type from its metadata.
44pub trait LayoutRaw
45where
46    Self: Pointee,
47{
48    /// Returns the layout of the type.
49    fn layout_raw(
50        metadata: <Self as Pointee>::Metadata,
51    ) -> Result<Layout, LayoutError>;
52}
53
54/// An optimization hint about whether `T` is trivially copyable.
55pub struct CopyOptimization<T: ?Sized>(bool, PhantomData<T>);
56
57impl<T: ?Sized> CopyOptimization<T> {
58    /// Returns a `CopyOptimization` hint with the optimization enabled for `T`.
59    ///
60    /// # Safety
61    ///
62    /// `T` must not have any uninit bytes (e.g. padding).
63    pub const unsafe fn enable() -> Self {
64        Self(true, PhantomData)
65    }
66
67    /// Returns a `CopyOptimization` hint with the optimization enabled for `T`
68    /// if `value` is `true`.
69    ///
70    /// # Safety
71    ///
72    /// `T` must not have any uninit bytes (e.g. padding) if `value` is `true`.
73    pub const unsafe fn enable_if(value: bool) -> Self {
74        Self(value, PhantomData)
75    }
76
77    /// Returns a `CopyOptimization` hint with the optimization disabled for
78    /// `T`.
79    pub const fn disable() -> Self {
80        Self(false, PhantomData)
81    }
82
83    /// Returns whether the optimization is enabled for `T`.
84    pub const fn is_enabled(&self) -> bool {
85        self.0
86    }
87}
88
89/// A type that can be used without deserializing.
90///
91/// `Archive` is one of three basic traits used to work with zero-copy data and
92/// controls the layout of the data in its archived zero-copy representation.
93/// The [`Serialize`] trait helps transform types into that representation, and
94/// the [`Deserialize`] trait helps transform types back out.
95///
96/// Types that implement `Archive` must have a well-defined archived size.
97/// Unsized types can be supported using the [`ArchiveUnsized`] trait, along
98/// with [`SerializeUnsized`] and [`DeserializeUnsized`].
99///
100/// Archiving is done depth-first, writing any data owned by a type before
101/// writing the data for the type itself. The type must be able to create the
102/// archived type from only its own data and its resolver.
103///
104/// Archived data is always treated as if it is tree-shaped, with the root
105/// owning its direct descendents and so on. Data that is not tree-shaped can be
106/// supported using special serializer and deserializer bounds (see
107/// [`ArchivedRc`](crate::rc::ArchivedRc) for example). In a buffer of
108/// serialized data, objects are laid out in *reverse order*. This means that
109/// the root object is located near the end of the buffer and leaf objects are
110/// located near the beginning.
111///
112/// # Examples
113///
114/// Most of the time, `#[derive(Archive)]` will create an acceptable
115/// implementation. You can use the `#[rkyv(...)]` attribute to control how the
116/// implementation is generated. See the [`Archive`](macro@crate::Archive)
117/// derive macro for more details.
118#[doc = concat!("```\n", include_str!("../examples/readme.rs"), "```\n")]
119/// _Note: the safe API requires the `bytecheck` feature._
120///
121/// Many of the core and standard library types already have `Archive`
122/// implementations available, but you may need to implement `Archive` for your
123/// own types in some cases the derive macro cannot handle.
124///
125/// In this example, we add our own wrapper that serializes a `&'static str` as
126/// if it's owned. Normally you can lean on the archived version of `String` to
127/// do most of the work, or use the [`Inline`](crate::with::Inline) to do
128/// exactly this. This example does everything to demonstrate how to implement
129/// `Archive` for your own types.
130/// ```
131/// use core::{slice, str};
132///
133/// use rkyv::{
134///     access_unchecked,
135///     rancor::{Error, Fallible},
136///     ser::Writer,
137///     to_bytes,
138///     Archive, ArchiveUnsized, Archived, Portable, RelPtr, Serialize,
139///     SerializeUnsized, munge::munge, Place,
140/// };
141///
142/// struct OwnedStr {
143///     inner: &'static str,
144/// }
145///
146/// #[derive(Portable)]
147/// #[repr(transparent)]
148/// struct ArchivedOwnedStr {
149///     // This will be a relative pointer to our string
150///     ptr: RelPtr<str>,
151/// }
152///
153/// impl ArchivedOwnedStr {
154///     // This will help us get the bytes of our type as a str again.
155///     fn as_str(&self) -> &str {
156///         unsafe {
157///             // The as_ptr() function of RelPtr will get a pointer the str
158///             &*self.ptr.as_ptr()
159///         }
160///     }
161/// }
162///
163/// struct OwnedStrResolver {
164///     // This will be the position that the bytes of our string are stored at.
165///     // We'll use this to resolve the relative pointer of our
166///     // ArchivedOwnedStr.
167///     pos: usize,
168/// }
169///
170/// // The Archive implementation defines the archived version of our type and
171/// // determines how to turn the resolver into the archived form. The Serialize
172/// // implementations determine how to make a resolver from the original value.
173/// impl Archive for OwnedStr {
174///     type Archived = ArchivedOwnedStr;
175///     // This is the resolver we can create our Archived version from.
176///     type Resolver = OwnedStrResolver;
177///
178///     // The resolve function consumes the resolver and produces the archived
179///     // value at the given position.
180///     fn resolve(
181///         &self,
182///         resolver: Self::Resolver,
183///         out: Place<Self::Archived>,
184///     ) {
185///         munge!(let ArchivedOwnedStr { ptr } = out);
186///         RelPtr::emplace_unsized(
187///             resolver.pos,
188///             self.inner.archived_metadata(),
189///             ptr,
190///         );
191///     }
192/// }
193///
194/// // We restrict our serializer types with Writer because we need its
195/// // capabilities to serialize the inner string. For other types, we might
196/// // need more or less restrictive bounds on the type of S.
197/// impl<S: Fallible + Writer + ?Sized> Serialize<S> for OwnedStr {
198///     fn serialize(
199///         &self,
200///         serializer: &mut S,
201///     ) -> Result<Self::Resolver, S::Error> {
202///         // This is where we want to write the bytes of our string and return
203///         // a resolver that knows where those bytes were written.
204///         // We also need to serialize the metadata for our str.
205///         Ok(OwnedStrResolver {
206///             pos: self.inner.serialize_unsized(serializer)?,
207///         })
208///     }
209/// }
210///
211/// const STR_VAL: &'static str = "I'm in an OwnedStr!";
212/// let value = OwnedStr { inner: STR_VAL };
213/// // It works!
214/// let buf = to_bytes::<Error>(&value).expect("failed to serialize");
215/// let archived =
216///     unsafe { access_unchecked::<ArchivedOwnedStr>(buf.as_ref()) };
217/// // Let's make sure our data got written correctly
218/// assert_eq!(archived.as_str(), STR_VAL);
219/// ```
220pub trait Archive {
221    /// An optimization flag that allows the bytes of this type to be copied
222    /// directly to a writer instead of calling `serialize`.
223    ///
224    /// This optimization is disabled by default. To enable this optimization,
225    /// you must unsafely attest that `Self` is trivially copyable using
226    /// [`CopyOptimization::enable`] or [`CopyOptimization::enable_if`].
227    const COPY_OPTIMIZATION: CopyOptimization<Self> =
228        CopyOptimization::disable();
229
230    /// The archived representation of this type.
231    ///
232    /// In this form, the data can be used with zero-copy deserialization.
233    type Archived: Portable;
234
235    /// The resolver for this type. It must contain all the additional
236    /// information from serializing needed to make the archived type from
237    /// the normal type.
238    type Resolver;
239
240    /// Creates the archived version of this value at the given position and
241    /// writes it to the given output.
242    ///
243    /// The output should be initialized field-by-field rather than by writing a
244    /// whole struct. Performing a typed copy will mark all of the padding
245    /// bytes as uninitialized, but they must remain set to the value they
246    /// currently have. This prevents leaking uninitialized memory to
247    /// the final archive.
248    fn resolve(&self, resolver: Self::Resolver, out: Place<Self::Archived>);
249}
250
251/// Converts a type to its archived form.
252///
253/// Objects perform any supportive serialization during
254/// [`serialize`](Serialize::serialize). For types that reference nonlocal
255/// (pointed-to) data, this is when that data must be serialized to the output.
256/// These types will need to bound `S` to implement
257/// [`Writer`](crate::ser::Writer) and any other required traits (e.g.
258/// [`Sharing`](crate::ser::Sharing)). They should then serialize their
259/// dependencies during `serialize`.
260///
261/// See [`Archive`] for examples of implementing `Serialize`.
262pub trait Serialize<S: Fallible + ?Sized>: Archive {
263    /// Writes the dependencies for the object and returns a resolver that can
264    /// create the archived type.
265    fn serialize(&self, serializer: &mut S)
266        -> Result<Self::Resolver, S::Error>;
267}
268
269/// Converts a type back from its archived form.
270///
271/// Some types may require specific deserializer capabilities, such as `Rc` and
272/// `Arc`. In these cases, the deserializer type `D` should be bound so that it
273/// implements traits that provide those capabilities (e.g.
274/// [`Pooling`](crate::de::Pooling)).
275///
276/// This can be derived with [`Deserialize`](macro@crate::Deserialize).
277pub trait Deserialize<T, D: Fallible + ?Sized> {
278    /// Deserializes using the given deserializer
279    fn deserialize(&self, deserializer: &mut D) -> Result<T, D::Error>;
280}
281
282/// A counterpart of [`Archive`] that's suitable for unsized types.
283///
284/// Unlike `Archive`, types that implement `ArchiveUnsized` must be serialized
285/// separately from their owning object. For example, whereas an `i32` might be
286/// laid out as part of a larger struct, a `Box<i32>` would serialize the `i32`
287/// somewhere in the archive and the `Box` would point to it as part of the
288/// larger struct. Because of this, the equivalent
289/// [`Resolver`](Archive::Resolver) type for `ArchiveUnsized` is always a
290/// `usize` representing the position of the serialized value.
291///
292/// `ArchiveUnsized` is automatically implemented for all types that implement
293/// [`Archive`]. Nothing special needs to be done to use them with types like
294/// `Box`, `Rc`, and `Arc`. It is also already implemented for slices and string
295/// slices, and the `rkyv_dyn` crate can be used to archive trait objects. Other
296/// unsized types must manually implement `ArchiveUnsized`.
297///
298/// # Examples
299///
300/// This example shows how to manually implement `ArchiveUnsized` for an unsized
301/// type. Special care must be taken to ensure that the types are laid out
302/// correctly.
303///
304/// ```
305/// use core::ops::{Deref, DerefMut};
306///
307/// use ptr_meta::Pointee;
308/// use rkyv::{
309///     access_unchecked,
310///     primitive::ArchivedUsize,
311///     rancor::{Error, Fallible},
312///     ser::{Positional, Writer, WriterExt as _},
313///     to_bytes,
314///     traits::ArchivePointee,
315///     Archive, ArchiveUnsized, Archived, ArchivedMetadata, Portable, RelPtr,
316///     Serialize, SerializeUnsized,
317/// };
318///
319/// // We're going to be dealing mostly with blocks that have a trailing slice
320/// #[derive(Portable)]
321/// #[repr(C)]
322/// pub struct Block<H, T: ?Sized> {
323///     head: H,
324///     tail: T,
325/// }
326///
327/// unsafe impl<H, T> Pointee for Block<H, [T]> {
328///     type Metadata = <[T] as Pointee>::Metadata;
329/// }
330///
331/// // ArchivePointee is automatically derived for sized types because pointers
332/// // to sized types don't need to store any extra information. Because we're
333/// // making an unsized block, we need to define what metadata gets stored with
334/// // our data pointer.
335/// impl<H, T> ArchivePointee for Block<H, [T]> {
336///     // This is the extra data that needs to get stored for blocks with
337///     // trailing slices
338///     type ArchivedMetadata = <[T] as ArchivePointee>::ArchivedMetadata;
339///
340///     // We need to be able to turn our archived metadata into regular
341///     // metadata for our type
342///     fn pointer_metadata(
343///         metadata: &Self::ArchivedMetadata,
344///     ) -> <Self as Pointee>::Metadata {
345///         metadata.to_native() as usize
346///     }
347/// }
348///
349/// // We're implementing ArchiveUnsized for just Block<H, [T]>. We can still
350/// // implement Archive for blocks with sized tails and they won't conflict.
351/// impl<H: Archive, T: Archive> ArchiveUnsized for Block<H, [T]> {
352///     // We'll reuse our block type as our archived type.
353///     type Archived = Block<Archived<H>, [Archived<T>]>;
354///
355///     // Here's where we make the metadata for our archived type.
356///     fn archived_metadata(&self) -> ArchivedMetadata<Self> {
357///         // Because the metadata for our `ArchivedBlock` is the metadata of
358///         // the trailing slice, we just need to return that archived
359///         // metadata.
360///         self.tail.archived_metadata()
361///     }
362/// }
363///
364/// // The bounds we use on our serializer type indicate that we need basic
365/// // serializer capabilities, and then whatever capabilities our head and tail
366/// // types need to serialize themselves.
367/// impl<H, T, S> SerializeUnsized<S> for Block<H, [T]>
368/// where
369///     H: Serialize<S>,
370///     T: Serialize<S>,
371///     S: Fallible + Writer + ?Sized,
372/// {
373///     // This is where we construct our unsized type in the serializer
374///     fn serialize_unsized(
375///         &self,
376///         serializer: &mut S,
377///     ) -> Result<usize, S::Error> {
378///         // First, we serialize the head and all the tails. This will make
379///         // sure that when we finally build our block, we don't accidentally
380///         // mess up the structure with serialized dependencies.
381///         let head_resolver = self.head.serialize(serializer)?;
382///         let mut resolvers = Vec::new();
383///         for tail in self.tail.iter() {
384///             resolvers.push(tail.serialize(serializer)?);
385///         }
386///         // Now we align our serializer for our archived type and resolve it.
387///         // We can't align for unsized types so we treat the trailing slice
388///         // like an array of 0 length for now.
389///         let result = serializer
390///             .align_for::<Block<Archived<H>, [Archived<T>; 0]>>()?;
391///         unsafe {
392///             serializer.resolve_aligned(&self.head, head_resolver)?;
393///         }
394///         serializer.align_for::<Archived<T>>()?;
395///         for (item, resolver) in self.tail.iter().zip(resolvers.drain(..)) {
396///             unsafe {
397///                 serializer.resolve_aligned(item, resolver)?;
398///             }
399///         }
400///         Ok(result)
401///     }
402/// }
403///
404/// let value = Box::new(Block {
405///     head: "Numbers 1-4".to_string(),
406///     tail: [1, 2, 3, 4],
407/// });
408///
409/// // We have a Box<Block<String, [i32; 4]>> but we want to it to be a
410/// // Box<Block<String, [i32]>>, so we need manually "unsize" the pointer.
411/// let ptr = Box::into_raw(value);
412/// let unsized_ptr = ptr_meta::from_raw_parts_mut::<Block<String, [i32]>>(
413///     ptr.cast::<()>(),
414///     4,
415/// );
416/// let unsized_value = unsafe { Box::from_raw(unsized_ptr) };
417///
418/// let bytes = to_bytes::<Error>(&unsized_value).unwrap();
419///
420/// let archived = unsafe {
421///     access_unchecked::<Archived<Box<Block<String, [i32]>>>>(&bytes)
422/// };
423/// assert_eq!(archived.head, "Numbers 1-4");
424/// assert_eq!(archived.tail.len(), 4);
425/// assert_eq!(archived.tail, [1, 2, 3, 4]);
426/// ```
427pub trait ArchiveUnsized: Pointee {
428    /// The archived counterpart of this type. Unlike `Archive`, it may be
429    /// unsized.
430    ///
431    /// This type must implement [`ArchivePointee`], a trait that helps make
432    /// valid pointers using archived pointer metadata.
433    type Archived: ArchivePointee + Portable + ?Sized;
434
435    /// Creates the archived version of the metadata for this value.
436    fn archived_metadata(&self) -> ArchivedMetadata<Self>;
437}
438
439/// An archived type with associated metadata for its relative pointer.
440///
441/// This is mostly used in the context of smart pointers and unsized types, and
442/// is implemented for all sized types by default.
443pub trait ArchivePointee: Pointee {
444    /// The archived version of the pointer metadata for this type.
445    type ArchivedMetadata: Copy
446        + Send
447        + Sync
448        + Ord
449        + Hash
450        + Unpin
451        + Portable
452        + NoUndef
453        + Default;
454
455    /// Converts some archived metadata to the pointer metadata for itself.
456    fn pointer_metadata(
457        archived: &Self::ArchivedMetadata,
458    ) -> <Self as Pointee>::Metadata;
459}
460
461/// A counterpart of [`Serialize`] that's suitable for unsized types.
462///
463/// See [`ArchiveUnsized`] for examples of implementing `SerializeUnsized`.
464pub trait SerializeUnsized<S: Fallible + ?Sized>: ArchiveUnsized {
465    /// Writes the object and returns the position of the archived type.
466    fn serialize_unsized(&self, serializer: &mut S) -> Result<usize, S::Error>;
467}
468
469/// A counterpart of [`Deserialize`] that's suitable for unsized types.
470pub trait DeserializeUnsized<T: Pointee + ?Sized, D: Fallible + ?Sized>:
471    ArchivePointee
472{
473    /// Deserializes a reference to the given value.
474    ///
475    /// # Safety
476    ///
477    /// `out` must be non-null, properly-aligned, and valid for writes. It must
478    /// be allocated according to the layout of the deserialized metadata.
479    unsafe fn deserialize_unsized(
480        &self,
481        deserializer: &mut D,
482        out: *mut T,
483    ) -> Result<(), D::Error>;
484
485    /// Deserializes the metadata for the given type.
486    fn deserialize_metadata(&self) -> T::Metadata;
487}