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