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;