Skip to main content

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