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}