[go: up one dir, main page]

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/// It also allows `&str` to be archived like an owned `String`. However, note
360/// that `&str` cannot be *deserialized* this way.
361///
362/// # Example
363///
364/// ```
365/// use std::{ffi::OsString, path::PathBuf};
366///
367/// use rkyv::{with::AsString, Archive};
368///
369/// #[derive(Archive)]
370/// struct Example<'a> {
371///     #[rkyv(with = AsString)]
372///     os_string: OsString,
373///     #[rkyv(with = AsString)]
374///     path: PathBuf,
375///     #[rkyv(with = AsString)]
376///     reference: &'a str,
377/// }
378/// ```
379#[derive(Debug)]
380pub struct AsString;
381
382/// A wrapper that locks a lock and serializes the value immutably.
383///
384/// This wrapper can panic under very specific circumstances when:
385///
386/// 1. `serialize_with` is called and succeeds in locking the value to serialize
387///    it.
388/// 2. Another thread locks the value and panics, poisoning the lock
389/// 3. `resolve_with` is called and gets a poisoned value.
390///
391/// Unfortunately, it's not possible to work around this issue internally. Users
392/// must ensure this doesn't happen on their own through manual synchronization
393/// or guaranteeing that panics do not occur while holding locks.
394///
395/// # Example
396///
397/// ```
398/// use std::sync::Mutex;
399///
400/// use rkyv::{with::Lock, Archive};
401///
402/// #[derive(Archive)]
403/// struct Example {
404///     #[rkyv(with = Lock)]
405///     a: Mutex<i32>,
406/// }
407/// ```
408#[derive(Debug)]
409pub struct Lock;
410
411/// A wrapper that serializes a `Cow` as if it were owned.
412///
413/// # Example
414///
415/// ```
416/// use std::borrow::Cow;
417///
418/// use rkyv::{with::AsOwned, Archive};
419///
420/// #[derive(Archive)]
421/// struct Example<'a> {
422///     #[rkyv(with = AsOwned)]
423///     a: Cow<'a, str>,
424/// }
425/// ```
426#[derive(Debug)]
427pub struct AsOwned;
428
429/// A wrapper that serializes associative containers as a `Vec` of key-value
430/// pairs.
431///
432/// This provides faster serialization for containers like `HashMap` and
433/// `BTreeMap` by serializing the key-value pairs directly instead of building a
434/// data structure in the buffer.
435///
436/// It also allows `&[T]` to be archived like an owned `Vec`. However, note
437/// that `&[T]` cannot be *deserialized* this way.
438///
439/// # Example
440///
441/// ```
442/// use std::collections::HashMap;
443///
444/// use rkyv::{with::AsVec, Archive};
445///
446/// #[derive(Archive)]
447/// struct Example<'a> {
448///     #[rkyv(with = AsVec)]
449///     values: HashMap<String, u32>,
450///     #[rkyv(with = AsVec)]
451///     slice: &'a [u32],
452/// }
453/// ```
454#[derive(Debug)]
455pub struct AsVec;
456
457/// A wrapper that niches some type combinations.
458///
459/// A common type combination is `Option<Box<T>>`. By using a null pointer, the
460/// archived version can save some space on-disk.
461///
462/// # Example
463///
464/// ```
465/// use core::mem::size_of;
466///
467/// use rkyv::{with::Niche, Archive, Archived};
468///
469/// #[derive(Archive)]
470/// struct BasicExample {
471///     value: Option<Box<str>>,
472/// }
473///
474/// #[derive(Archive)]
475/// struct NichedExample {
476///     #[rkyv(with = Niche)]
477///     value: Option<Box<str>>,
478/// }
479///
480/// assert!(
481///     size_of::<Archived<BasicExample>>()
482///         > size_of::<Archived<NichedExample>>()
483/// );
484/// ```
485#[derive(Debug)]
486pub struct Niche;
487
488/// A wrapper that niches based on a generic [`Niching`].
489///
490/// A common type combination is `Option<Box<T>>`. By niching `None` into the
491/// null pointer, the archived version can save some space on-disk.
492///
493/// # Example
494///
495/// ```
496/// use core::mem::size_of;
497///
498/// use rkyv::{
499///     niche::niching::{NaN, Null},
500///     with::NicheInto,
501///     Archive, Archived,
502/// };
503///
504/// #[derive(Archive)]
505/// struct BasicExample {
506///     maybe_box: Option<Box<str>>,
507///     maybe_non_nan: Option<f32>,
508/// }
509///
510/// #[derive(Archive)]
511/// struct NichedExample {
512///     #[rkyv(with = NicheInto<Null>)]
513///     maybe_box: Option<Box<str>>,
514///     #[rkyv(with = NicheInto<NaN>)]
515///     maybe_non_nan: Option<f32>,
516/// }
517///
518/// assert!(
519///     size_of::<Archived<BasicExample>>()
520///         > size_of::<Archived<NichedExample>>()
521/// );
522/// ```
523///
524/// [`Niching`]: crate::niche::niching::Niching
525pub struct NicheInto<N: ?Sized>(PhantomData<N>);
526
527impl<N: ?Sized> Default for NicheInto<N> {
528    fn default() -> Self {
529        Self(PhantomData)
530    }
531}
532
533impl<N: ?Sized> fmt::Debug for NicheInto<N> {
534    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
535        f.write_str("NicheInto")
536    }
537}
538
539/// A wrapper that first applies another wrapper `W` to the value inside an
540/// `Option` and then niches the result based on the [`Niching`] `N`.
541///
542/// # Example
543///
544/// ```
545/// use rkyv::{
546///     with::{AsBox, MapNiche},
547///     Archive, Serialize,
548/// };
549///
550/// #[derive(Archive, Serialize)]
551/// struct BasicExample {
552///     option: Option<HugeType>,
553/// }
554///
555/// #[derive(Archive, Serialize)]
556/// struct NichedExample {
557///     #[rkyv(with = MapNiche<AsBox>)]
558///     option: Option<HugeType>,
559/// }
560///
561/// #[derive(Archive, Serialize)]
562/// struct HugeType([u8; 1024]);
563///
564/// # fn main() -> Result<(), rkyv::rancor::Error> {
565/// let basic_value = BasicExample { option: None };
566/// let basic_bytes = rkyv::to_bytes(&basic_value)?;
567/// assert_eq!(basic_bytes.len(), 1 + 1024);
568///
569/// let niched_value = NichedExample { option: None };
570/// let niched_bytes = rkyv::to_bytes(&niched_value)?;
571/// assert_eq!(niched_bytes.len(), 4); // size_of::<ArchivedBox<_>>()
572/// # Ok(()) }
573/// ```
574///
575/// [`Niching`]: crate::niche::niching::Niching
576pub struct MapNiche<W: ?Sized, N: ?Sized = DefaultNiche> {
577    _map: PhantomData<W>,
578    _niching: PhantomData<N>,
579}
580
581impl<W: ?Sized, N: ?Sized> Default for MapNiche<W, N> {
582    fn default() -> Self {
583        Self {
584            _map: PhantomData,
585            _niching: PhantomData,
586        }
587    }
588}
589
590impl<W: ?Sized, N: ?Sized> fmt::Debug for MapNiche<W, N> {
591    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
592        f.write_str("MapNiche")
593    }
594}
595
596/// A wrapper that converts a [`SystemTime`](std::time::SystemTime) to a
597/// [`Duration`](std::time::Duration) since
598/// [`UNIX_EPOCH`](std::time::UNIX_EPOCH).
599///
600/// If the serialized time occurs before the UNIX epoch, serialization will
601/// panic during `resolve`. The resulting archived time will be an
602/// [`ArchivedDuration`](crate::time::ArchivedDuration) relative to the UNIX
603/// epoch.
604///
605/// # Example
606///
607/// ```
608/// use rkyv::{Archive, with::AsUnixTime};
609/// use std::time::SystemTime;
610///
611/// #[derive(Archive)]
612/// struct Example {
613///     #[rkyv(with = AsUnixTime)]
614///     time: SystemTime,
615/// }
616#[derive(Debug)]
617pub struct AsUnixTime;
618
619/// A wrapper that allows serialize-unsafe types to be serialized.
620///
621/// Types like `Cell` and `UnsafeCell` may contain serializable types, but have
622/// unsafe access semantics due to interior mutability. They may be safe to
623/// serialize, but only under conditions that rkyv is unable to guarantee.
624///
625/// This wrapper enables serializing these types, and places the burden of
626/// verifying that their access semantics are used safely on the user.
627///
628/// # Safety
629///
630/// Using this wrapper on types with interior mutability can create races
631/// conditions or allow access to data in an invalid state if access semantics
632/// are not followed properly. During serialization, the data must not be
633/// modified.
634///
635/// # Example
636///
637/// ```
638/// use core::cell::{Cell, UnsafeCell};
639///
640/// use rkyv::{with::Unsafe, Archive};
641///
642/// #[derive(Archive)]
643/// struct Example {
644///     #[rkyv(with = Unsafe)]
645///     cell: Cell<String>,
646///     #[rkyv(with = Unsafe)]
647///     unsafe_cell: UnsafeCell<String>,
648/// }
649/// ```
650#[derive(Debug)]
651pub struct Unsafe;
652
653/// A wrapper that skips serializing a field.
654///
655/// Skipped fields must implement `Default` to be deserialized.
656///
657/// # Example
658///
659/// ```
660/// use rkyv::{with::Skip, Archive};
661///
662/// #[derive(Archive)]
663/// struct Example {
664///     #[rkyv(with = Skip)]
665///     a: u32,
666/// }
667/// ```
668#[derive(Debug)]
669pub struct Skip;
670
671/// A wrapper that clones the contents of `Arc` and `Rc` pointers.
672#[derive(Debug)]
673pub struct Unshare;
674
675/// A no-op wrapper which uses the default impls for the type.
676///
677/// This is most useful for wrappers like [`MapKV`] when you only want to apply
678/// a wrapper to either the key or the value.
679///
680/// # Example
681///
682/// ```
683/// use std::collections::HashMap;
684///
685/// use rkyv::{
686///     with::{Identity, Inline, MapKV},
687///     Archive,
688/// };
689///
690/// #[derive(Archive)]
691/// struct Example<'a> {
692///     #[rkyv(with = MapKV<Identity, Inline>)]
693///     a: HashMap<u32, &'a u32>,
694/// }
695/// ```
696#[derive(Debug)]
697pub struct Identity;