rkyv/
with.rs

1//! Wrapper type support and commonly used wrappers.
2//!
3//! Wrappers can be applied with the `#[rkyv(with = ..)]` attribute in the
4//! [`Archive`](macro@crate::Archive) macro.
5
6// mod impls;
7
8use core::{fmt, marker::PhantomData};
9
10use rancor::Fallible;
11
12#[doc(inline)]
13pub use crate::niche::niching::DefaultNiche;
14use crate::{Archive, Deserialize, Place, Portable, Serialize};
15
16/// A variant of [`Archive`] that works with wrappers.
17///
18/// Creating a wrapper allows users to customize how fields are archived easily
19/// without changing the unarchived type.
20///
21/// This trait allows wrapper types to transparently change the archive
22/// behaviors for struct and enum fields. When a field is serialized, it may use
23/// the implementations for the wrapper type and the given field instead of the
24/// implementation for the type itself.
25///
26/// Only a single implementation of [`Archive`] may be written
27/// for each type, but multiple implementations of ArchiveWith can be written
28/// for the same type because it is parametric over the wrapper type. This is
29/// used with the `#[rkyv(with = ..)]` macro attribute to provide a more
30/// flexible interface for serialization.
31///
32/// # Example
33///
34/// ```
35/// use rkyv::{
36///     access_unchecked, deserialize,
37///     rancor::{Error, Fallible, Infallible, ResultExt as _},
38///     to_bytes,
39///     with::{ArchiveWith, DeserializeWith, SerializeWith},
40///     Archive, Archived, Deserialize, Place, Resolver, Serialize,
41/// };
42///
43/// struct Incremented;
44///
45/// impl ArchiveWith<i32> for Incremented {
46///     type Archived = Archived<i32>;
47///     type Resolver = Resolver<i32>;
48///
49///     fn resolve_with(field: &i32, _: (), out: Place<Self::Archived>) {
50///         let incremented = field + 1;
51///         incremented.resolve((), out);
52///     }
53/// }
54///
55/// impl<S> SerializeWith<i32, S> for Incremented
56/// where
57///     S: Fallible + ?Sized,
58///     i32: Serialize<S>,
59/// {
60///     fn serialize_with(
61///         field: &i32,
62///         serializer: &mut S,
63///     ) -> Result<Self::Resolver, S::Error> {
64///         let incremented = field + 1;
65///         incremented.serialize(serializer)
66///     }
67/// }
68///
69/// impl<D> DeserializeWith<Archived<i32>, i32, D> for Incremented
70/// where
71///     D: Fallible + ?Sized,
72///     Archived<i32>: Deserialize<i32, D>,
73/// {
74///     fn deserialize_with(
75///         field: &Archived<i32>,
76///         deserializer: &mut D,
77///     ) -> Result<i32, D::Error> {
78///         Ok(field.deserialize(deserializer)? - 1)
79///     }
80/// }
81///
82/// #[derive(Archive, Deserialize, Serialize)]
83/// struct Example {
84///     #[rkyv(with = Incremented)]
85///     a: i32,
86///     // Another i32 field, but not incremented this time
87///     b: i32,
88/// }
89///
90/// let value = Example { a: 4, b: 9 };
91///
92/// let buf = to_bytes::<Error>(&value).unwrap();
93///
94/// let archived =
95///     unsafe { access_unchecked::<Archived<Example>>(buf.as_ref()) };
96/// // The wrapped field has been incremented
97/// assert_eq!(archived.a, 5);
98/// // ... and the unwrapped field has not
99/// assert_eq!(archived.b, 9);
100///
101/// let deserialized = deserialize::<Example, Infallible>(archived).always_ok();
102/// // The wrapped field is back to normal
103/// assert_eq!(deserialized.a, 4);
104/// // ... and the unwrapped field is unchanged
105/// assert_eq!(deserialized.b, 9);
106/// ```
107pub trait ArchiveWith<F: ?Sized> {
108    /// The archived type of `Self` with `F`.
109    type Archived: Portable;
110    /// The resolver of a `Self` with `F`.
111    type Resolver;
112
113    /// Resolves the archived type using a reference to the field type `F`.
114    fn resolve_with(
115        field: &F,
116        resolver: Self::Resolver,
117        out: Place<Self::Archived>,
118    );
119}
120
121/// A variant of `Serialize` for "with" types.
122///
123/// See [ArchiveWith] for more details.
124pub trait SerializeWith<F: ?Sized, S: Fallible + ?Sized>:
125    ArchiveWith<F>
126{
127    /// Serializes the field type `F` using the given serializer.
128    fn serialize_with(
129        field: &F,
130        serializer: &mut S,
131    ) -> Result<Self::Resolver, S::Error>;
132}
133
134/// A variant of `Deserialize` for "with" types.
135///
136/// See [ArchiveWith] for more details.
137pub trait DeserializeWith<F: ?Sized, T, D: Fallible + ?Sized> {
138    /// Deserializes the field type `F` using the given deserializer.
139    fn deserialize_with(field: &F, deserializer: &mut D)
140        -> Result<T, D::Error>;
141}
142
143/// A transparent wrapper which applies a "with" type.
144///
145/// `With` wraps a reference to a type and applies the specified wrapper type
146/// when serializing and deserializing.
147#[repr(transparent)]
148pub struct With<F: ?Sized, W> {
149    _phantom: PhantomData<W>,
150    field: F,
151}
152
153impl<F: ?Sized, W> With<F, W> {
154    /// Casts a `With` reference from a reference to the underlying field.
155    pub fn cast(field: &F) -> &Self {
156        // SAFETY: `With` is `repr(transparent)` and so a reference to `F` can
157        // always be transmuted into a reference to `With<F, W>`.
158        unsafe { ::core::mem::transmute::<&F, &Self>(field) }
159    }
160}
161
162impl<F: ?Sized, W: ArchiveWith<F>> Archive for With<F, W> {
163    type Archived = <W as ArchiveWith<F>>::Archived;
164    type Resolver = <W as ArchiveWith<F>>::Resolver;
165
166    fn resolve(&self, resolver: Self::Resolver, out: Place<Self::Archived>) {
167        W::resolve_with(&self.field, resolver, out);
168    }
169}
170
171impl<S, F, W> Serialize<S> for With<F, W>
172where
173    S: Fallible + ?Sized,
174    F: ?Sized,
175    W: SerializeWith<F, S>,
176{
177    fn serialize(
178        &self,
179        serializer: &mut S,
180    ) -> Result<Self::Resolver, <S as Fallible>::Error> {
181        W::serialize_with(&self.field, serializer)
182    }
183}
184
185impl<T, D, F, W> Deserialize<T, D> for With<F, W>
186where
187    D: Fallible + ?Sized,
188    F: ?Sized,
189    W: DeserializeWith<F, T, D>,
190{
191    fn deserialize(
192        &self,
193        deserializer: &mut D,
194    ) -> Result<T, <D as Fallible>::Error> {
195        W::deserialize_with(&self.field, deserializer)
196    }
197}
198
199/// A wrapper that applies another wrapper to the values contained in a type.
200/// This can be applied to a vector to map each element, or an option to map any
201/// contained value.
202///
203/// See [ArchiveWith] for more details.
204///
205/// # Example
206///
207/// ```
208/// use rkyv::{
209///     with::{InlineAsBox, Map},
210///     Archive,
211/// };
212///
213/// #[derive(Archive)]
214/// struct Example<'a> {
215///     // This will apply `InlineAsBox` to the `&i32` contained in this option
216///     #[rkyv(with = Map<InlineAsBox>)]
217///     option: Option<&'a i32>,
218///     // This will apply `InlineAsBox` to each `&i32` contained in this vector
219///     #[rkyv(with = Map<InlineAsBox>)]
220///     vec: Vec<&'a i32>,
221/// }
222/// ```
223pub struct Map<T> {
224    _phantom: PhantomData<T>,
225}
226
227/// A wrapper that applies key and value wrappers to the key-value pairs
228/// contained in a type. This can be applied to a hash map or B-tree map to map
229/// the key-value pairs.
230///
231/// # Example
232/// ```
233/// use std::collections::HashMap;
234///
235/// use rkyv::{
236///     with::{Inline, InlineAsBox, MapKV},
237///     Archive,
238/// };
239///
240/// #[derive(Archive)]
241/// struct Example<'a> {
242///     // This will apply `InlineAsBox` to the `&str` key, and `Inline` to the
243///     // `&str` value.
244///     #[rkyv(with = MapKV<InlineAsBox, Inline>)]
245///     hash_map: HashMap<&'a str, &'a str>,
246/// }
247/// ```
248pub struct MapKV<K, V> {
249    _phantom: PhantomData<(K, V)>,
250}
251
252/// A type indicating relaxed atomic loads.
253pub struct Relaxed;
254
255/// A type indicating acquire atomic loads.
256pub struct Acquire;
257
258/// A type indicating sequentially-consistent atomic loads.
259pub struct SeqCst;
260
261/// A wrapper that archives an atomic by loading its value with a particular
262/// ordering.
263///
264/// When serializing, the specified ordering will be used to load the value from
265/// the source atomic. The underlying archived type is still a non-atomic value.
266///
267/// # Example
268///
269/// ```
270/// # #[cfg(target_has_atomic = "32")]
271/// use core::sync::atomic::AtomicU32;
272///
273/// use rkyv::{
274///     with::{AtomicLoad, Relaxed},
275///     Archive,
276/// };
277///
278/// # #[cfg(target_has_atomic = "32")]
279/// #[derive(Archive)]
280/// struct Example {
281///     #[rkyv(with = AtomicLoad<Relaxed>)]
282///     a: AtomicU32,
283/// }
284/// ```
285#[derive(Debug)]
286pub struct AtomicLoad<SO> {
287    _phantom: PhantomData<SO>,
288}
289
290/// A wrapper that serializes a reference inline.
291///
292/// References serialized with `Inline` cannot be deserialized because the
293/// struct cannot own the deserialized value.
294///
295/// # Example
296///
297/// ```
298/// use rkyv::{with::Inline, Archive};
299///
300/// #[derive(Archive)]
301/// struct Example<'a> {
302///     #[rkyv(with = Inline)]
303///     a: &'a i32,
304/// }
305/// ```
306#[derive(Debug)]
307pub struct Inline;
308
309/// A wrapper that serializes a field into a box.
310///
311/// This functions similarly to [`InlineAsBox`], but is for regular fields
312/// instead of references.
313///
314/// # Example
315///
316/// ```
317/// use rkyv::{with::AsBox, Archive};
318///
319/// #[derive(Archive)]
320/// struct Example {
321///     #[rkyv(with = AsBox)]
322///     a: i32,
323///     #[rkyv(with = AsBox)]
324///     b: str,
325/// }
326/// ```
327#[derive(Debug)]
328pub struct AsBox;
329
330/// A wrapper that serializes a reference as if it were boxed.
331///
332/// Unlike [`Inline`], unsized references can be serialized with `InlineAsBox`.
333///
334/// References serialized with `InlineAsBox` cannot be deserialized because the
335/// struct cannot own the deserialized value.
336///
337/// # Example
338///
339/// ```
340/// use rkyv::{with::InlineAsBox, Archive};
341///
342/// #[derive(Archive)]
343/// struct Example<'a> {
344///     #[rkyv(with = InlineAsBox)]
345///     a: &'a i32,
346///     #[rkyv(with = InlineAsBox)]
347///     b: &'a str,
348/// }
349/// ```
350#[derive(Debug)]
351pub struct InlineAsBox;
352
353/// A wrapper that attempts to convert a type to and from UTF-8.
354///
355/// Types like `OsString` and `PathBuf` aren't guaranteed to be encoded as
356/// UTF-8, but they usually are anyway. Using this wrapper will archive them as
357/// if they were regular `String`s.
358///
359/// # Example
360///
361/// ```
362/// use std::{ffi::OsString, path::PathBuf};
363///
364/// use rkyv::{with::AsString, Archive};
365///
366/// #[derive(Archive)]
367/// struct Example {
368///     #[rkyv(with = AsString)]
369///     os_string: OsString,
370///     #[rkyv(with = AsString)]
371///     path: PathBuf,
372/// }
373/// ```
374#[derive(Debug)]
375pub struct AsString;
376
377/// A wrapper that locks a lock and serializes the value immutably.
378///
379/// This wrapper can panic under very specific circumstances when:
380///
381/// 1. `serialize_with` is called and succeeds in locking the value to serialize
382///    it.
383/// 2. Another thread locks the value and panics, poisoning the lock
384/// 3. `resolve_with` is called and gets a poisoned value.
385///
386/// Unfortunately, it's not possible to work around this issue internally. Users
387/// must ensure this doesn't happen on their own through manual synchronization
388/// or guaranteeing that panics do not occur while holding locks.
389///
390/// # Example
391///
392/// ```
393/// use std::sync::Mutex;
394///
395/// use rkyv::{with::Lock, Archive};
396///
397/// #[derive(Archive)]
398/// struct Example {
399///     #[rkyv(with = Lock)]
400///     a: Mutex<i32>,
401/// }
402/// ```
403#[derive(Debug)]
404pub struct Lock;
405
406/// A wrapper that serializes a `Cow` as if it were owned.
407///
408/// # Example
409///
410/// ```
411/// use std::borrow::Cow;
412///
413/// use rkyv::{with::AsOwned, Archive};
414///
415/// #[derive(Archive)]
416/// struct Example<'a> {
417///     #[rkyv(with = AsOwned)]
418///     a: Cow<'a, str>,
419/// }
420/// ```
421#[derive(Debug)]
422pub struct AsOwned;
423
424/// A wrapper that serializes associative containers as a `Vec` of key-value
425/// pairs.
426///
427/// This provides faster serialization for containers like `HashMap` and
428/// `BTreeMap` by serializing the key-value pairs directly instead of building a
429/// data structure in the buffer.
430///
431/// # Example
432///
433/// ```
434/// use std::collections::HashMap;
435///
436/// use rkyv::{with::AsVec, Archive};
437///
438/// #[derive(Archive)]
439/// struct Example {
440///     #[rkyv(with = AsVec)]
441///     values: HashMap<String, u32>,
442/// }
443/// ```
444#[derive(Debug)]
445pub struct AsVec;
446
447/// A wrapper that niches some type combinations.
448///
449/// A common type combination is `Option<Box<T>>`. By using a null pointer, the
450/// archived version can save some space on-disk.
451///
452/// # Example
453///
454/// ```
455/// use core::mem::size_of;
456///
457/// use rkyv::{with::Niche, Archive, Archived};
458///
459/// #[derive(Archive)]
460/// struct BasicExample {
461///     value: Option<Box<str>>,
462/// }
463///
464/// #[derive(Archive)]
465/// struct NichedExample {
466///     #[rkyv(with = Niche)]
467///     value: Option<Box<str>>,
468/// }
469///
470/// assert!(
471///     size_of::<Archived<BasicExample>>()
472///         > size_of::<Archived<NichedExample>>()
473/// );
474/// ```
475#[derive(Debug)]
476pub struct Niche;
477
478/// A wrapper that niches based on a generic [`Niching`].
479///
480/// A common type combination is `Option<Box<T>>`. By niching `None` into the
481/// null pointer, the archived version can save some space on-disk.
482///
483/// # Example
484///
485/// ```
486/// use core::mem::size_of;
487///
488/// use rkyv::{
489///     niche::niching::{NaN, Null},
490///     with::NicheInto,
491///     Archive, Archived,
492/// };
493///
494/// #[derive(Archive)]
495/// struct BasicExample {
496///     maybe_box: Option<Box<str>>,
497///     maybe_non_nan: Option<f32>,
498/// }
499///
500/// #[derive(Archive)]
501/// struct NichedExample {
502///     #[rkyv(with = NicheInto<Null>)]
503///     maybe_box: Option<Box<str>>,
504///     #[rkyv(with = NicheInto<NaN>)]
505///     maybe_non_nan: Option<f32>,
506/// }
507///
508/// assert!(
509///     size_of::<Archived<BasicExample>>()
510///         > size_of::<Archived<NichedExample>>()
511/// );
512/// ```
513///
514/// [`Niching`]: crate::niche::niching::Niching
515pub struct NicheInto<N: ?Sized>(PhantomData<N>);
516
517impl<N: ?Sized> Default for NicheInto<N> {
518    fn default() -> Self {
519        Self(PhantomData)
520    }
521}
522
523impl<N: ?Sized> fmt::Debug for NicheInto<N> {
524    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
525        f.write_str("NicheInto")
526    }
527}
528
529/// A wrapper that first applies another wrapper `W` to the value inside an
530/// `Option` and then niches the result based on the [`Niching`] `N`.
531///
532/// # Example
533///
534/// ```
535/// use rkyv::{
536///     with::{AsBox, MapNiche},
537///     Archive, Serialize,
538/// };
539///
540/// #[derive(Archive, Serialize)]
541/// struct BasicExample {
542///     option: Option<HugeType>,
543/// }
544///
545/// #[derive(Archive, Serialize)]
546/// struct NichedExample {
547///     #[rkyv(with = MapNiche<AsBox>)]
548///     option: Option<HugeType>,
549/// }
550///
551/// #[derive(Archive, Serialize)]
552/// struct HugeType([u8; 1024]);
553///
554/// # fn main() -> Result<(), rkyv::rancor::Error> {
555/// let basic_value = BasicExample { option: None };
556/// let basic_bytes = rkyv::to_bytes(&basic_value)?;
557/// assert_eq!(basic_bytes.len(), 1 + 1024);
558///
559/// let niched_value = NichedExample { option: None };
560/// let niched_bytes = rkyv::to_bytes(&niched_value)?;
561/// assert_eq!(niched_bytes.len(), 4); // size_of::<ArchivedBox<_>>()
562/// # Ok(()) }
563/// ```
564///
565/// [`Niching`]: crate::niche::niching::Niching
566pub struct MapNiche<W: ?Sized, N: ?Sized = DefaultNiche> {
567    _map: PhantomData<W>,
568    _niching: PhantomData<N>,
569}
570
571impl<W: ?Sized, N: ?Sized> Default for MapNiche<W, N> {
572    fn default() -> Self {
573        Self {
574            _map: PhantomData,
575            _niching: PhantomData,
576        }
577    }
578}
579
580impl<W: ?Sized, N: ?Sized> fmt::Debug for MapNiche<W, N> {
581    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
582        f.write_str("MapNiche")
583    }
584}
585
586/// A wrapper that converts a [`SystemTime`](std::time::SystemTime) to a
587/// [`Duration`](std::time::Duration) since
588/// [`UNIX_EPOCH`](std::time::UNIX_EPOCH).
589///
590/// If the serialized time occurs before the UNIX epoch, serialization will
591/// panic during `resolve`. The resulting archived time will be an
592/// [`ArchivedDuration`](crate::time::ArchivedDuration) relative to the UNIX
593/// epoch.
594///
595/// # Example
596///
597/// ```
598/// use rkyv::{Archive, with::AsUnixTime};
599/// use std::time::SystemTime;
600///
601/// #[derive(Archive)]
602/// struct Example {
603///     #[rkyv(with = AsUnixTime)]
604///     time: SystemTime,
605/// }
606#[derive(Debug)]
607pub struct AsUnixTime;
608
609/// A wrapper that allows serialize-unsafe types to be serialized.
610///
611/// Types like `Cell` and `UnsafeCell` may contain serializable types, but have
612/// unsafe access semantics due to interior mutability. They may be safe to
613/// serialize, but only under conditions that rkyv is unable to guarantee.
614///
615/// This wrapper enables serializing these types, and places the burden of
616/// verifying that their access semantics are used safely on the user.
617///
618/// # Safety
619///
620/// Using this wrapper on types with interior mutability can create races
621/// conditions or allow access to data in an invalid state if access semantics
622/// are not followed properly. During serialization, the data must not be
623/// modified.
624///
625/// # Example
626///
627/// ```
628/// use core::cell::{Cell, UnsafeCell};
629///
630/// use rkyv::{with::Unsafe, Archive};
631///
632/// #[derive(Archive)]
633/// struct Example {
634///     #[rkyv(with = Unsafe)]
635///     cell: Cell<String>,
636///     #[rkyv(with = Unsafe)]
637///     unsafe_cell: UnsafeCell<String>,
638/// }
639/// ```
640#[derive(Debug)]
641pub struct Unsafe;
642
643/// A wrapper that skips serializing a field.
644///
645/// Skipped fields must implement `Default` to be deserialized.
646///
647/// # Example
648///
649/// ```
650/// use rkyv::{with::Skip, Archive};
651///
652/// #[derive(Archive)]
653/// struct Example {
654///     #[rkyv(with = Skip)]
655///     a: u32,
656/// }
657/// ```
658#[derive(Debug)]
659pub struct Skip;
660
661/// A wrapper that clones the contents of `Arc` and `Rc` pointers.
662#[derive(Debug)]
663pub struct Unshare;
664
665/// A no-op wrapper which uses the default impls for the type.
666///
667/// This is most useful for wrappers like [`MapKV`] when you only want to apply
668/// a wrapper to either the key or the value.
669///
670/// # Example
671///
672/// ```
673/// use std::collections::HashMap;
674///
675/// use rkyv::{
676///     with::{Identity, Inline, MapKV},
677///     Archive,
678/// };
679///
680/// #[derive(Archive)]
681/// struct Example<'a> {
682///     #[rkyv(with = MapKV<Identity, Inline>)]
683///     a: HashMap<u32, &'a u32>,
684/// }
685/// ```
686#[derive(Debug)]
687pub struct Identity;