rkyv/ser/serializers/
mod.rs

1//! Serializers that can be used standalone and provide basic capabilities.
2
3#[cfg(feature = "alloc")]
4mod alloc;
5mod core;
6#[cfg(feature = "std")]
7mod std;
8
9#[cfg(feature = "alloc")]
10use crate::AlignedVec;
11use crate::{
12    ser::{ScratchSpace, Serializer, SharedSerializeRegistry},
13    AlignedBytes, Archive, ArchiveUnsized, Fallible, Infallible,
14};
15use ::core::{alloc::Layout, fmt, ptr::NonNull};
16
17#[doc(inline)]
18#[cfg(feature = "alloc")]
19pub use self::alloc::*;
20#[doc(inline)]
21pub use self::core::*;
22#[doc(inline)]
23#[cfg(feature = "std")]
24pub use self::std::*;
25
26/// The default serializer error.
27#[derive(Debug)]
28pub enum CompositeSerializerError<S, C, H> {
29    /// An error occurred while serializing
30    SerializerError(S),
31    /// An error occurred while using scratch space
32    ScratchSpaceError(C),
33    /// An error occurred while serializing shared memory
34    SharedError(H),
35}
36
37impl<S, C, H> fmt::Display for CompositeSerializerError<S, C, H>
38where
39    S: fmt::Display,
40    C: fmt::Display,
41    H: fmt::Display,
42{
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        match self {
45            Self::SerializerError(e) => write!(f, "serialization error: {}", e),
46            Self::ScratchSpaceError(e) => write!(f, "scratch space error: {}", e),
47            Self::SharedError(e) => write!(f, "shared memory error: {}", e),
48        }
49    }
50}
51
52#[cfg(feature = "std")]
53const _: () = {
54    use ::std::error::Error;
55
56    impl<S, C, H> Error for CompositeSerializerError<S, C, H>
57    where
58        S: Error + 'static,
59        C: Error + 'static,
60        H: Error + 'static,
61    {
62        fn source(&self) -> Option<&(dyn Error + 'static)> {
63            match self {
64                Self::SerializerError(e) => Some(e as &dyn Error),
65                Self::ScratchSpaceError(e) => Some(e as &dyn Error),
66                Self::SharedError(e) => Some(e as &dyn Error),
67            }
68        }
69    }
70};
71
72/// A serializer built from composeable pieces.
73#[derive(Debug)]
74pub struct CompositeSerializer<S = Infallible, C = Infallible, H = Infallible> {
75    serializer: S,
76    scratch: C,
77    shared: H,
78}
79
80impl<S, C, H> CompositeSerializer<S, C, H> {
81    /// Creates a new composite serializer from serializer, scratch, and shared components.
82    #[inline]
83    pub fn new(serializer: S, scratch: C, shared: H) -> Self {
84        Self {
85            serializer,
86            scratch,
87            shared,
88        }
89    }
90
91    /// Consumes the composite serializer and returns the components.
92    #[inline]
93    pub fn into_components(self) -> (S, C, H) {
94        (self.serializer, self.scratch, self.shared)
95    }
96
97    /// Consumes the composite serializer and returns the serializer.
98    ///
99    /// The scratch space and shared component are discarded.
100    #[inline]
101    pub fn into_serializer(self) -> S {
102        self.serializer
103    }
104}
105
106impl<S: Default, C: Default, H: Default> Default for CompositeSerializer<S, C, H> {
107    #[inline]
108    fn default() -> Self {
109        Self {
110            serializer: S::default(),
111            scratch: C::default(),
112            shared: H::default(),
113        }
114    }
115}
116
117impl<S: Fallible, C: Fallible, H: Fallible> Fallible for CompositeSerializer<S, C, H> {
118    type Error = CompositeSerializerError<S::Error, C::Error, H::Error>;
119}
120
121impl<S: Serializer, C: Fallible, H: Fallible> Serializer for CompositeSerializer<S, C, H> {
122    #[inline]
123    fn pos(&self) -> usize {
124        self.serializer.pos()
125    }
126
127    #[inline]
128    fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
129        self.serializer
130            .write(bytes)
131            .map_err(CompositeSerializerError::SerializerError)
132    }
133
134    #[inline]
135    fn pad(&mut self, padding: usize) -> Result<(), Self::Error> {
136        self.serializer
137            .pad(padding)
138            .map_err(CompositeSerializerError::SerializerError)
139    }
140
141    #[inline]
142    fn align(&mut self, align: usize) -> Result<usize, Self::Error> {
143        self.serializer
144            .align(align)
145            .map_err(CompositeSerializerError::SerializerError)
146    }
147
148    #[inline]
149    fn align_for<T>(&mut self) -> Result<usize, Self::Error> {
150        self.serializer
151            .align_for::<T>()
152            .map_err(CompositeSerializerError::SerializerError)
153    }
154
155    #[inline]
156    unsafe fn resolve_aligned<T: Archive + ?Sized>(
157        &mut self,
158        value: &T,
159        resolver: T::Resolver,
160    ) -> Result<usize, Self::Error> {
161        self.serializer
162            .resolve_aligned::<T>(value, resolver)
163            .map_err(CompositeSerializerError::SerializerError)
164    }
165
166    #[inline]
167    unsafe fn resolve_unsized_aligned<T: ArchiveUnsized + ?Sized>(
168        &mut self,
169        value: &T,
170        to: usize,
171        metadata_resolver: T::MetadataResolver,
172    ) -> Result<usize, Self::Error> {
173        self.serializer
174            .resolve_unsized_aligned(value, to, metadata_resolver)
175            .map_err(CompositeSerializerError::SerializerError)
176    }
177}
178
179impl<S: Fallible, C: ScratchSpace, H: Fallible> ScratchSpace for CompositeSerializer<S, C, H> {
180    #[inline]
181    unsafe fn push_scratch(&mut self, layout: Layout) -> Result<NonNull<[u8]>, Self::Error> {
182        self.scratch
183            .push_scratch(layout)
184            .map_err(CompositeSerializerError::ScratchSpaceError)
185    }
186
187    #[inline]
188    unsafe fn pop_scratch(&mut self, ptr: NonNull<u8>, layout: Layout) -> Result<(), Self::Error> {
189        self.scratch
190            .pop_scratch(ptr, layout)
191            .map_err(CompositeSerializerError::ScratchSpaceError)
192    }
193}
194
195impl<S: Fallible, C: Fallible, H: SharedSerializeRegistry> SharedSerializeRegistry
196    for CompositeSerializer<S, C, H>
197{
198    #[inline]
199    fn get_shared_ptr(&self, value: *const u8) -> Option<usize> {
200        self.shared.get_shared_ptr(value)
201    }
202
203    #[inline]
204    fn add_shared_ptr(&mut self, value: *const u8, pos: usize) -> Result<(), Self::Error> {
205        self.shared
206            .add_shared_ptr(value, pos)
207            .map_err(CompositeSerializerError::SharedError)
208    }
209}
210
211/// A serializer suitable for environments where allocations cannot be made.
212///
213/// `CoreSerializer` takes two arguments: the amount of serialization memory to allocate and the
214/// amount of scratch space to allocate. If you run out of either while serializing, the serializer
215/// will return an error.
216pub type CoreSerializer<const S: usize, const C: usize> = CompositeSerializer<
217    BufferSerializer<AlignedBytes<S>>,
218    BufferScratch<AlignedBytes<C>>,
219    Infallible,
220>;
221
222/// A general-purpose serializer suitable for environments where allocations can be made.
223///
224/// `AllocSerializer` takes one argument: the amount of scratch space to allocate before spilling
225/// allocations over into heap memory. A large amount of scratch space may result in some of it not
226/// being used, but too little scratch space will result in many allocations and decreased
227/// performance. You should consider your use case carefully when determining how much scratch space
228/// to pre-allocate.
229#[cfg(feature = "alloc")]
230pub type AllocSerializer<const N: usize> = CompositeSerializer<
231    AlignedSerializer<AlignedVec>,
232    FallbackScratch<HeapScratch<N>, AllocScratch>,
233    SharedSerializeMap,
234>;