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