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;