rkyv/with/
mod.rs

1//! Wrapper type support and commonly used wrappers.
2//!
3//! Wrappers can be applied with the `#[with(...)]` attribute in the
4//! [`Archive`](macro@crate::Archive) macro. See [`With`] for examples.
5
6#[cfg(feature = "alloc")]
7mod alloc;
8#[cfg(has_atomics)]
9mod atomic;
10mod core;
11#[cfg(feature = "std")]
12mod std;
13
14use crate::{Archive, Deserialize, Fallible, Serialize};
15use ::core::{fmt, marker::PhantomData, mem::transmute, ops::Deref};
16
17/// A transparent wrapper for archived fields.
18///
19/// This is used by the `#[with(...)]` attribute in the [`Archive`](macro@crate::Archive) macro to
20/// create transparent serialization wrappers. Those wrappers leverage [`ArchiveWith`] to change
21/// how the type is archived, serialized, and deserialized.
22///
23/// When a field is serialized, a reference to the field (i.e. `&T`) can be cast to a reference to a
24/// wrapping `With` (i.e. `With<T, Wrapper>`) and serialized instead. This is safe to do because
25/// `With` is a transparent wrapper and is shaped exactly the same as the underlying field.
26///
27/// # Example
28///
29/// ```
30/// use rkyv::{Archive, with::Inline};
31///
32/// #[derive(Archive)]
33/// struct Example<'a> {
34///     // This will archive as if it were With<&'a i32, Inline>. That will delegate the archival
35///     // to the ArchiveWith implementation of Inline for &T.
36///     #[with(Inline)]
37///     a: &'a i32,
38/// }
39/// ```
40#[repr(transparent)]
41#[derive(Debug)]
42pub struct With<F: ?Sized, W> {
43    _phantom: PhantomData<W>,
44    field: F,
45}
46
47impl<F: ?Sized, W> With<F, W> {
48    /// Casts a `With` reference from a reference to the underlying field.
49    ///
50    /// This is always safe to do because `With` is a transparent wrapper.
51    #[inline]
52    pub fn cast(field: &F) -> &'_ With<F, W> {
53        // Safety: transmuting from an unsized type reference to a reference to a transparent
54        // wrapper is safe because they both have the same data address and metadata
55        #[allow(clippy::transmute_ptr_to_ptr)]
56        unsafe {
57            transmute(field)
58        }
59    }
60}
61
62impl<F, W> With<F, W> {
63    /// Unwraps a `With` into the underlying field.
64    #[inline]
65    pub fn into_inner(self) -> F {
66        self.field
67    }
68}
69
70impl<F: ?Sized, W> AsRef<F> for With<F, W> {
71    fn as_ref(&self) -> &F {
72        &self.field
73    }
74}
75
76/// A variant of [`Archive`] that works with [`With`] wrappers.
77///
78/// Creating a wrapper allows users to customize how fields are archived easily without changing the
79/// unarchived type.
80///
81/// This trait allows wrapper types to transparently change the archive behaviors for struct fields.
82/// When a field is serialized, its reference may be converted to a [`With`] reference, and that
83/// reference may be serialized instead. `With` references look for implementations of `ArchiveWith`
84/// to determine how a wrapped field should be treated.
85///
86/// # Example
87///
88/// ```
89/// use rkyv::{
90///     archived_root,
91///     ser::{
92///         serializers::AllocSerializer,
93///         Serializer,
94///     },
95///     with::{
96///         ArchiveWith,
97///         DeserializeWith,
98///         SerializeWith,
99///     },
100///     Archive,
101///     Archived,
102///     Deserialize,
103///     Fallible,
104///     Infallible,
105///     Resolver,
106///     Serialize,
107/// };
108///
109/// struct Incremented;
110///
111/// impl ArchiveWith<i32> for Incremented {
112///     type Archived = Archived<i32>;
113///     type Resolver = Resolver<i32>;
114///
115///     unsafe fn resolve_with(field: &i32, pos: usize, _: (), out: *mut Self::Archived) {
116///         let incremented = field + 1;
117///         incremented.resolve(pos, (), out);
118///     }
119/// }
120///
121/// impl<S: Fallible + ?Sized> SerializeWith<i32, S> for Incremented
122/// where
123///     i32: Serialize<S>,
124/// {
125///     fn serialize_with(field: &i32, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
126///         let incremented = field + 1;
127///         incremented.serialize(serializer)
128///     }
129/// }
130///
131/// impl<D: Fallible + ?Sized> DeserializeWith<Archived<i32>, i32, D> for Incremented
132/// where
133///     Archived<i32>: Deserialize<i32, D>,
134/// {
135///     fn deserialize_with(field: &Archived<i32>, deserializer: &mut D) -> Result<i32, D::Error> {
136///         Ok(field.deserialize(deserializer)? - 1)
137///     }
138/// }
139///
140/// #[derive(Archive, Deserialize, Serialize)]
141/// struct Example {
142///     #[with(Incremented)]
143///     a: i32,
144///     // Another i32 field, but not incremented this time
145///     b: i32,
146/// }
147///
148/// let value = Example {
149///     a: 4,
150///     b: 9,
151/// };
152///
153/// let mut serializer = AllocSerializer::<4096>::default();
154/// serializer.serialize_value(&value).unwrap();
155/// let buf = serializer.into_serializer().into_inner();
156///
157/// let archived = unsafe { archived_root::<Example>(buf.as_ref()) };
158/// // The wrapped field has been incremented
159/// assert_eq!(archived.a, 5);
160/// // ... and the unwrapped field has not
161/// assert_eq!(archived.b, 9);
162///
163/// let deserialized: Example = archived.deserialize(&mut Infallible).unwrap();
164/// // The wrapped field is back to normal
165/// assert_eq!(deserialized.a, 4);
166/// // ... and the unwrapped field is unchanged
167/// assert_eq!(deserialized.b, 9);
168/// ```
169pub trait ArchiveWith<F: ?Sized> {
170    /// The archived type of a `With<F, Self>`.
171    type Archived;
172    /// The resolver of a `With<F, Self>`.
173    type Resolver;
174
175    /// Resolves the archived type using a reference to the field type `F`.
176    ///
177    /// # Safety
178    ///
179    /// - `pos` must be the position of `out` within the archive
180    /// - `resolver` must be the result of serializing `field`
181    unsafe fn resolve_with(
182        field: &F,
183        pos: usize,
184        resolver: Self::Resolver,
185        out: *mut Self::Archived,
186    );
187}
188
189impl<F: ?Sized, W: ArchiveWith<F>> Archive for With<F, W> {
190    type Archived = W::Archived;
191    type Resolver = W::Resolver;
192
193    #[inline]
194    unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) {
195        W::resolve_with(&self.field, pos, resolver, out.cast());
196    }
197}
198
199/// A variant of `Serialize` that works with `With` wrappers.
200pub trait SerializeWith<F: ?Sized, S: Fallible + ?Sized>: ArchiveWith<F> {
201    /// Serializes the field type `F` using the given serializer.
202    fn serialize_with(field: &F, serializer: &mut S) -> Result<Self::Resolver, S::Error>;
203}
204
205impl<F: ?Sized, W: SerializeWith<F, S>, S: Fallible + ?Sized> Serialize<S> for With<F, W> {
206    #[inline]
207    fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
208        W::serialize_with(&self.field, serializer)
209    }
210}
211
212/// A variant of `Deserialize` that works with `With` wrappers.
213pub trait DeserializeWith<F: ?Sized, T, D: Fallible + ?Sized> {
214    /// Deserializes the field type `F` using the given deserializer.
215    fn deserialize_with(field: &F, deserializer: &mut D) -> Result<T, D::Error>;
216}
217
218impl<F, W, T, D> Deserialize<With<T, W>, D> for F
219where
220    F: ?Sized,
221    W: DeserializeWith<F, T, D>,
222    D: Fallible + ?Sized,
223{
224    #[inline]
225    fn deserialize(&self, deserializer: &mut D) -> Result<With<T, W>, D::Error> {
226        Ok(With {
227            _phantom: PhantomData,
228            field: W::deserialize_with(self, deserializer)?,
229        })
230    }
231}
232
233/// A wrapper to make a type immutable.
234#[repr(transparent)]
235#[derive(Debug)]
236pub struct Immutable<T: ?Sized>(T);
237
238impl<T: ?Sized> Immutable<T> {
239    /// Gets the underlying immutable value.
240    #[inline]
241    pub fn value(&self) -> &T {
242        &self.0
243    }
244}
245
246impl<T: ?Sized> Deref for Immutable<T> {
247    type Target = T;
248
249    #[inline]
250    fn deref(&self) -> &Self::Target {
251        &self.0
252    }
253}
254
255#[cfg(feature = "validation")]
256const _: () = {
257    use bytecheck::CheckBytes;
258
259    impl<T: CheckBytes<C> + ?Sized, C: ?Sized> CheckBytes<C> for Immutable<T> {
260        type Error = T::Error;
261
262        unsafe fn check_bytes<'a>(
263            value: *const Self,
264            context: &mut C,
265        ) -> Result<&'a Self, Self::Error> {
266            CheckBytes::check_bytes(::core::ptr::addr_of!((*value).0), context)?;
267            Ok(&*value)
268        }
269    }
270};
271
272/// A generic wrapper that allows wrapping an `Option<T>`.
273///
274/// # Example
275///
276/// ```
277/// use rkyv::{Archive, with::{Map, RefAsBox}};
278///
279/// #[derive(Archive)]
280/// struct Example<'a> {
281///     #[with(Map<RefAsBox>)]
282///     option: Option<&'a i32>,
283///     #[with(Map<RefAsBox>)]
284///     vec: Vec<&'a i32>,
285/// }
286/// ```
287#[derive(Debug)]
288pub struct Map<Archivable> {
289    _type: PhantomData<Archivable>,
290}
291
292/// A wrapper that archives an atomic with an underlying atomic.
293///
294/// By default, atomics are archived with an underlying integer.
295///
296/// # Safety
297///
298/// This wrapper is only safe to use when the backing memory for wrapped types is mutable.
299///
300/// # Example
301///
302/// ```
303/// # #[cfg(has_atomics)]
304/// use core::sync::atomic::AtomicU32;
305/// use rkyv::{Archive, with::Atomic};
306///
307/// # #[cfg(has_atomics)]
308/// #[derive(Archive)]
309/// struct Example {
310///     #[with(Atomic)]
311///     a: AtomicU32,
312/// }
313/// ```
314#[derive(Debug)]
315pub struct Atomic;
316
317/// A wrapper that serializes a reference inline.
318///
319/// References serialized with `Inline` cannot be deserialized because the struct cannot own the
320/// deserialized value.
321///
322/// # Example
323///
324/// ```
325/// use rkyv::{Archive, with::Inline};
326///
327/// #[derive(Archive)]
328/// struct Example<'a> {
329///     #[with(Inline)]
330///     a: &'a i32,
331/// }
332/// ```
333#[derive(Debug)]
334pub struct Inline;
335
336/// A wrapper that serializes a reference as if it were boxed.
337///
338/// Unlike [`Inline`], unsized references can be serialized with `Boxed`.
339///
340/// References serialized with `Boxed` cannot be deserialized because the struct cannot own the
341/// deserialized value.
342///
343/// # Example
344///
345/// ```
346/// use rkyv::{Archive, with::Boxed};
347///
348/// #[derive(Archive)]
349/// struct Example<'a> {
350///     #[with(Boxed)]
351///     a: &'a str,
352/// }
353/// ```
354#[deprecated = "Use `RefAsBox` for references, or `AsBox` for direct fields"]
355pub type Boxed = RefAsBox;
356
357/// A wrapper that serializes a field into a box.
358///
359/// This functions similarly to [`RefAsBox`], but is for regular fields instead of references.
360///
361/// # Example
362///
363/// ```
364/// use rkyv::{Archive, with::AsBox};
365///
366/// #[derive(Archive)]
367/// struct Example {
368///     #[with(AsBox)]
369///     a: i32,
370///     #[with(AsBox)]
371///     b: str,
372/// }
373/// ```
374#[derive(Debug)]
375pub struct AsBox;
376
377/// A wrapper that serializes a reference as if it were boxed.
378///
379/// Unlike [`Inline`], unsized references can be serialized with `RefAsBox`.
380///
381/// References serialized with `RefAsBox` cannot be deserialized because the struct cannot own the
382/// deserialized value.
383///
384/// # Example
385///
386/// ```
387/// use rkyv::{Archive, with::RefAsBox};
388///
389/// #[derive(Archive)]
390/// struct Example<'a> {
391///     #[with(RefAsBox)]
392///     a: &'a i32,
393///     #[with(RefAsBox)]
394///     b: &'a str,
395/// }
396/// ```
397#[derive(Debug)]
398pub struct RefAsBox;
399
400/// A wrapper that attempts to convert a type to and from UTF-8.
401///
402/// Types like `OsString` and `PathBuf` aren't guaranteed to be encoded as UTF-8, but they usually
403/// are anyway. Using this wrapper will archive them as if they were regular `String`s.
404///
405/// Regular serializers don't support the custom error handling needed for this type by default. To
406/// use this wrapper, a custom serializer with an error type satisfying
407/// `<S as Fallible>::Error: From<AsStringError>` must be provided.
408///
409/// # Example
410///
411/// ```
412/// use std::{ffi::OsString, path::PathBuf};
413/// use rkyv::{Archive, with::AsString};
414///
415/// #[derive(Archive)]
416/// struct Example {
417///     #[with(AsString)]
418///     os_string: OsString,
419///     #[with(AsString)]
420///     path: PathBuf,
421/// }
422/// ```
423#[derive(Debug)]
424pub struct AsString;
425
426/// Errors that can occur when serializing a [`AsString`] wrapper.
427#[derive(Debug)]
428pub enum AsStringError {
429    /// The `OsString` or `PathBuf` was not valid UTF-8.
430    InvalidUTF8,
431}
432
433impl fmt::Display for AsStringError {
434    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435        write!(f, "invalid UTF-8")
436    }
437}
438
439#[cfg(feature = "std")]
440impl ::std::error::Error for AsStringError {}
441
442/// A wrapper that locks a lock and serializes the value immutably.
443///
444/// This wrapper can panic under very specific circumstances when:
445///
446/// 1. `serialize_with` is called and succeeds in locking the value to serialize it.
447/// 2. Another thread locks the value and panics, poisoning the lock
448/// 3. `resolve_with` is called and gets a poisoned value.
449///
450/// Unfortunately, it's not possible to work around this issue. If your code absolutely must not
451/// panic under any circumstances, it's recommended that you lock your values and then serialize
452/// them while locked.
453///
454/// Additionally, mutating the data protected by a mutex between the serialize and resolve steps may
455/// cause undefined behavior in the resolve step. **Uses of this wrapper should be considered
456/// unsafe** with the requirement that the data not be mutated between these two steps.
457///
458/// Regular serializers don't support the custom error handling needed for this type by default. To
459/// use this wrapper, a custom serializer with an error type satisfying
460/// `<S as Fallible>::Error: From<LockError>` must be provided.
461///
462/// # Example
463///
464/// ```
465/// use std::sync::Mutex;
466/// use rkyv::{Archive, with::Lock};
467///
468/// #[derive(Archive)]
469/// struct Example {
470///     #[with(Lock)]
471///     a: Mutex<i32>,
472/// }
473/// ```
474#[derive(Debug)]
475pub struct Lock;
476
477/// Errors that can occur while serializing a [`Lock`] wrapper
478#[derive(Debug)]
479pub enum LockError {
480    /// The mutex was poisoned
481    Poisoned,
482}
483
484impl fmt::Display for LockError {
485    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
486        write!(f, "lock poisoned")
487    }
488}
489
490#[cfg(feature = "std")]
491impl ::std::error::Error for LockError {}
492
493/// A wrapper that serializes a `Cow` as if it were owned.
494///
495/// # Example
496///
497/// ```
498/// use std::borrow::Cow;
499/// use rkyv::{Archive, with::AsOwned};
500///
501/// #[derive(Archive)]
502/// struct Example<'a> {
503///     #[with(AsOwned)]
504///     a: Cow<'a, str>,
505/// }
506/// ```
507#[derive(Debug)]
508pub struct AsOwned;
509
510/// A wrapper that serializes associative containers as a `Vec` of key-value pairs.
511///
512/// This provides faster serialization for containers like `HashMap` and `BTreeMap` by serializing
513/// the key-value pairs directly instead of building a data structure in the buffer.
514///
515/// # Example
516///
517/// ```
518/// use std::collections::HashMap;
519/// use rkyv::{Archive, with::AsVec};
520///
521/// #[derive(Archive)]
522/// struct Example {
523///     #[with(AsVec)]
524///     values: HashMap<String, u32>,
525/// }
526/// ```
527#[derive(Debug)]
528pub struct AsVec;
529
530/// A wrapper that niches some type combinations.
531///
532/// A common type combination is `Option<Box<T>>`. By using a null pointer, the archived version can
533/// save some space on-disk.
534///
535/// # Example
536///
537/// ```
538/// use core::mem::size_of;
539/// use rkyv::{Archive, Archived, with::Niche};
540///
541/// #[derive(Archive)]
542/// struct BasicExample {
543///     value: Option<Box<str>>,
544/// }
545///
546/// #[derive(Archive)]
547/// struct NichedExample {
548///     #[with(Niche)]
549///     value: Option<Box<str>>,
550/// }
551///
552/// assert!(size_of::<Archived<BasicExample>>() > size_of::<Archived<NichedExample>>());
553/// ```
554#[derive(Debug)]
555pub struct Niche;
556
557/// A wrapper that provides specialized, performant implementations of serialization and
558/// deserialization.
559///
560/// This wrapper can be used with containers like `Vec`, but care must be taken to ensure that they
561/// contain copy-safe types. Copy-safe types must be trivially copyable (have the same archived and
562/// unarchived representations) and contain no padding bytes. In situations where copying
563/// uninitialized bytes the output is acceptable, this wrapper may be used with containers of types
564/// that contain padding bytes.
565///
566/// # Safety
567///
568/// Using this wrapper with containers containing non-copy-safe types may result in undefined
569/// behavior.
570///
571/// # Example
572///
573/// ```
574/// use rkyv::{Archive, with::CopyOptimize};
575///
576/// #[derive(Archive)]
577/// struct Example {
578///     #[with(CopyOptimize)]
579///     bytes: Vec<u8>,
580/// }
581/// ```
582#[derive(Debug)]
583pub struct CopyOptimize;
584
585/// A wrapper that converts a [`SystemTime`](::std::time::SystemTime) to a
586/// [`Duration`](::std::time::Duration) since [`UNIX_EPOCH`](::std::time::UNIX_EPOCH).
587///
588/// If the serialized time occurs before the UNIX epoch, serialization will panic during `resolve`.
589/// The resulting archived time will be an [`ArchivedDuration`](crate::time::ArchivedDuration)
590/// relative to the UNIX epoch.
591///
592/// Regular serializers don't support the custom error handling needed for this type by default. To
593/// use this wrapper, a custom serializer with an error type satisfying
594/// `<S as Fallible>::Error: From<UnixTimestampError>` must be provided.
595///
596/// # Example
597///
598/// ```
599/// use rkyv::{Archive, with::UnixTimestamp};
600/// use std::time::SystemTime;
601///
602/// #[derive(Archive)]
603/// struct Example {
604///     #[with(UnixTimestamp)]
605///     time: SystemTime,
606/// }
607#[derive(Debug)]
608pub struct UnixTimestamp;
609
610/// Errors that can occur when serializing a [`UnixTimestamp`] wrapper.
611#[derive(Debug)]
612pub enum UnixTimestampError {
613    /// The `SystemTime` occurred prior to the UNIX epoch.
614    TimeBeforeUnixEpoch,
615}
616
617impl fmt::Display for UnixTimestampError {
618    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
619        write!(f, "time occurred before the UNIX epoch")
620    }
621}
622
623#[cfg(feature = "std")]
624impl ::std::error::Error for UnixTimestampError {}
625
626/// A wrapper that provides an optimized bulk data array. This is primarily intended for large
627/// amounts of raw data, like bytes, floats, or integers.
628///
629/// This wrapper can be used with containers like `Vec`, but care must be taken to ensure that they
630/// contain copy-safe types. Copy-safe types must be trivially copyable (have the same archived and
631/// unarchived representations) and contain no padding bytes. In situations where copying
632/// uninitialized bytes the output is acceptable, this wrapper may be used with containers of types
633/// that contain padding bytes.
634///
635/// Unlike [`CopyOptimize`], this wrapper will also skip validation for its elements. If the
636/// elements of the container can have any invalid bit patterns (e.g. `char`, `bool`, complex
637/// containers, etc.), then using `Raw` in an insecure setting can lead to undefined behavior. Take
638/// great caution!
639///
640/// # Safety
641///
642/// Using this wrapper with containers containing non-copy-safe types or types that require
643/// validation may result in undefined behavior.
644///
645/// # Example
646///
647/// ```
648/// use rkyv::{Archive, with::Raw};
649///
650/// #[derive(Archive)]
651/// struct Example {
652///     #[with(Raw)]
653///     bytes: Vec<u8>,
654///     #[with(Raw)]
655///     vertices: Vec<[f32; 3]>,
656/// }
657/// ```
658#[derive(Debug)]
659pub struct Raw;
660
661/// A wrapper that allows serialize-unsafe types to be serialized.
662///
663/// Types like `Cell` and `UnsafeCell` may contain serializable types, but have unsafe access
664/// semantics due to interior mutability. They may be safe to serialize, but only under conditions
665/// that rkyv is unable to guarantee.
666///
667/// This wrapper enables serializing these types, and places the burden of verifying that their
668/// access semantics are used safely on the user.
669///
670/// # Safety
671///
672/// Using this wrapper on types with interior mutability can create races conditions or allow access
673/// to data in an invalid state if access semantics are not followed properly. During serialization,
674/// the data must not be modified.
675///
676/// # Example
677///
678/// ```
679/// use rkyv::{Archive, with::Unsafe};
680/// use core::cell::{Cell, UnsafeCell};
681///
682/// #[derive(Archive)]
683/// struct Example {
684///     #[with(Unsafe)]
685///     cell: Cell<String>,
686///     #[with(Unsafe)]
687///     unsafe_cell: UnsafeCell<String>,
688/// }
689/// ```
690#[derive(Debug)]
691pub struct Unsafe;
692
693/// A wrapper that skips serializing a field.
694///
695/// Skipped fields must implement `Default` to be deserialized.
696///
697/// # Example
698///
699/// ```
700/// use rkyv::{Archive, with::Skip};
701///
702/// #[derive(Archive)]
703/// struct Example {
704///     #[with(Skip)]
705///     a: u32,
706/// }
707/// ```
708#[derive(Debug)]
709pub struct Skip;