rkyv/ser/
mod.rs

1//! Serialization traits, serializers, and adapters.
2
3pub mod serializers;
4
5use crate::{Archive, ArchiveUnsized, Fallible, RelPtr, Serialize, SerializeUnsized};
6use core::{alloc::Layout, mem, ptr::NonNull, slice};
7
8/// A byte sink that knows where it is.
9///
10/// A type that is [`io::Write`](std::io::Write) can be wrapped in a
11/// [`WriteSerializer`](serializers::WriteSerializer) to equip it with `Serializer`.
12///
13/// It's important that the memory for archived objects is properly aligned before attempting to
14/// read objects out of it; use an [`AlignedVec`](crate::AlignedVec) or the
15/// [`AlignedBytes`](crate::AlignedBytes) wrappers if they are appropriate.
16pub trait Serializer: Fallible {
17    /// Returns the current position of the serializer.
18    fn pos(&self) -> usize;
19
20    /// Attempts to write the given bytes to the serializer.
21    fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error>;
22
23    /// Advances the given number of bytes as padding.
24    #[inline]
25    fn pad(&mut self, padding: usize) -> Result<(), Self::Error> {
26        const MAX_ZEROES: usize = 32;
27        const ZEROES: [u8; MAX_ZEROES] = [0; MAX_ZEROES];
28        debug_assert!(padding < MAX_ZEROES);
29
30        self.write(&ZEROES[0..padding])
31    }
32
33    /// Aligns the position of the serializer to the given alignment.
34    #[inline]
35    fn align(&mut self, align: usize) -> Result<usize, Self::Error> {
36        let mask = align - 1;
37        debug_assert_eq!(align & mask, 0);
38
39        self.pad((align - (self.pos() & mask)) & mask)?;
40        Ok(self.pos())
41    }
42
43    /// Aligns the position of the serializer to be suitable to write the given type.
44    #[inline]
45    fn align_for<T>(&mut self) -> Result<usize, Self::Error> {
46        self.align(mem::align_of::<T>())
47    }
48
49    /// Resolves the given value with its resolver and writes the archived type.
50    ///
51    /// Returns the position of the written archived type.
52    ///
53    /// # Safety
54    ///
55    /// - `resolver` must be the result of serializing `value`
56    /// - The serializer must be aligned for a `T::Archived`
57    unsafe fn resolve_aligned<T: Archive + ?Sized>(
58        &mut self,
59        value: &T,
60        resolver: T::Resolver,
61    ) -> Result<usize, Self::Error> {
62        let pos = self.pos();
63        debug_assert_eq!(pos & (mem::align_of::<T::Archived>() - 1), 0);
64
65        let mut resolved = mem::MaybeUninit::<T::Archived>::uninit();
66        resolved.as_mut_ptr().write_bytes(0, 1);
67        value.resolve(pos, resolver, resolved.as_mut_ptr());
68
69        let data = resolved.as_ptr().cast::<u8>();
70        let len = mem::size_of::<T::Archived>();
71        self.write(slice::from_raw_parts(data, len))?;
72        Ok(pos)
73    }
74
75    /// Archives the given object and returns the position it was archived at.
76    #[inline]
77    fn serialize_value<T: Serialize<Self>>(&mut self, value: &T) -> Result<usize, Self::Error> {
78        let resolver = value.serialize(self)?;
79        self.align_for::<T::Archived>()?;
80        unsafe { self.resolve_aligned(value, resolver) }
81    }
82
83    /// Resolves the given reference with its resolver and writes the archived reference.
84    ///
85    /// Returns the position of the written archived `RelPtr`.
86    ///
87    /// # Safety
88    ///
89    /// - `metadata_resolver` must be the result of serializing the metadata of `value`
90    /// - `to` must be the position of the serialized `value` within the archive
91    /// - The serializer must be aligned for a `RelPtr<T::Archived>`
92    unsafe fn resolve_unsized_aligned<T: ArchiveUnsized + ?Sized>(
93        &mut self,
94        value: &T,
95        to: usize,
96        metadata_resolver: T::MetadataResolver,
97    ) -> Result<usize, Self::Error> {
98        let from = self.pos();
99        debug_assert_eq!(from & (mem::align_of::<RelPtr<T::Archived>>() - 1), 0);
100
101        let mut resolved = mem::MaybeUninit::<RelPtr<T::Archived>>::uninit();
102        resolved.as_mut_ptr().write_bytes(0, 1);
103        value.resolve_unsized(from, to, metadata_resolver, resolved.as_mut_ptr());
104
105        let data = resolved.as_ptr().cast::<u8>();
106        let len = mem::size_of::<RelPtr<T::Archived>>();
107        self.write(slice::from_raw_parts(data, len))?;
108        Ok(from)
109    }
110
111    /// Archives a reference to the given object and returns the position it was archived at.
112    #[inline]
113    fn serialize_unsized_value<T: SerializeUnsized<Self> + ?Sized>(
114        &mut self,
115        value: &T,
116    ) -> Result<usize, Self::Error> {
117        let to = value.serialize_unsized(self)?;
118        let metadata_resolver = value.serialize_metadata(self)?;
119        self.align_for::<RelPtr<T::Archived>>()?;
120        unsafe { self.resolve_unsized_aligned(value, to, metadata_resolver) }
121    }
122}
123
124// Someday this can probably be replaced with alloc::Allocator
125
126/// A serializer that can allocate scratch space.
127pub trait ScratchSpace: Fallible {
128    /// Allocates scratch space of the requested size.
129    ///
130    /// # Safety
131    ///
132    /// `layout` must have non-zero size.
133    unsafe fn push_scratch(&mut self, layout: Layout) -> Result<NonNull<[u8]>, Self::Error>;
134
135    /// Deallocates previously allocated scratch space.
136    ///
137    /// # Safety
138    ///
139    /// - `ptr` must be the scratch memory last allocated with `push_scratch`.
140    /// - `layout` must be the same layout that was used to allocate that block of memory.
141    unsafe fn pop_scratch(&mut self, ptr: NonNull<u8>, layout: Layout) -> Result<(), Self::Error>;
142}
143
144/// A registry that tracks serialized shared memory.
145///
146/// This trait is required to serialize shared pointers.
147pub trait SharedSerializeRegistry: Fallible {
148    /// Gets the position of a previously-added shared pointer.
149    ///
150    /// Returns `None` if the pointer has not yet been added.
151    fn get_shared_ptr(&self, value: *const u8) -> Option<usize>;
152
153    /// Gets the position of a previously-added shared value.
154    ///
155    /// Returns `None` if the value has not yet been added.
156    #[inline]
157    fn get_shared<T: ?Sized>(&self, value: &T) -> Option<usize> {
158        self.get_shared_ptr(value as *const T as *const u8)
159    }
160
161    /// Adds the position of a shared pointer to the registry.
162    fn add_shared_ptr(&mut self, value: *const u8, pos: usize) -> Result<(), Self::Error>;
163
164    /// Adds the position of a shared value to the registry.
165    #[inline]
166    fn add_shared<T: ?Sized>(&mut self, value: &T, pos: usize) -> Result<(), Self::Error> {
167        self.add_shared_ptr(value as *const T as *const u8, pos)
168    }
169
170    /// Archives the given shared value and returns its position. If the value has already been
171    /// added then it returns the position of the previously added value.
172    #[inline]
173    fn serialize_shared<T: SerializeUnsized<Self> + ?Sized>(
174        &mut self,
175        value: &T,
176    ) -> Result<usize, Self::Error>
177    where
178        Self: Serializer,
179    {
180        if let Some(pos) = self.get_shared(value) {
181            Ok(pos)
182        } else {
183            let pos = value.serialize_unsized(self)?;
184            self.add_shared(value, pos)?;
185            Ok(pos)
186        }
187    }
188}