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;