rkyv/ser/writer/
mod.rs

1//! Writing backends for serializers.
2
3#[cfg(feature = "alloc")]
4mod alloc;
5mod core;
6#[cfg(feature = "std")]
7mod std;
8
9use ::core::mem;
10use rancor::{Fallible, Strategy};
11
12pub use self::core::*;
13#[cfg(feature = "std")]
14pub use self::std::*;
15use crate::{Archive, ArchiveUnsized, Place, RelPtr};
16
17/// A writer that knows its current position.
18pub trait Positional {
19    /// Returns the current position of the writer.
20    fn pos(&self) -> usize;
21}
22
23impl<T> Positional for &T
24where
25    T: Positional + ?Sized,
26{
27    fn pos(&self) -> usize {
28        T::pos(*self)
29    }
30}
31
32impl<T> Positional for &mut T
33where
34    T: Positional + ?Sized,
35{
36    fn pos(&self) -> usize {
37        T::pos(*self)
38    }
39}
40
41impl<T, E> Positional for Strategy<T, E>
42where
43    T: Positional + ?Sized,
44{
45    fn pos(&self) -> usize {
46        T::pos(self)
47    }
48}
49
50/// A type that writes bytes to some output.
51///
52/// A type that is [`Write`](::std::io::Write) can be wrapped in an [`IoWriter`]
53/// to equip it with `Writer`.
54///
55/// It's important that the memory for archived objects is properly aligned
56/// before attempting to read objects out of it; use an
57/// [`AlignedVec`](crate::util::AlignedVec) or the [`Align`](crate::util::Align)
58/// wrapper as appropriate.
59pub trait Writer<E = <Self as Fallible>::Error>: Positional {
60    /// Attempts to write the given bytes to the serializer.
61    fn write(&mut self, bytes: &[u8]) -> Result<(), E>;
62}
63
64impl<T, E> Writer<E> for &mut T
65where
66    T: Writer<E> + ?Sized,
67{
68    fn write(&mut self, bytes: &[u8]) -> Result<(), E> {
69        T::write(*self, bytes)
70    }
71}
72
73impl<T, E> Writer<E> for Strategy<T, E>
74where
75    T: Writer<E> + ?Sized,
76{
77    fn write(&mut self, bytes: &[u8]) -> Result<(), E> {
78        T::write(self, bytes)
79    }
80}
81
82/// Helper methods for [`Writer`].
83pub trait WriterExt<E>: Writer<E> {
84    /// Advances the given number of bytes as padding.
85    fn pad(&mut self, padding: usize) -> Result<(), E> {
86        const MAX_ZEROS: usize = 32;
87        const ZEROS: [u8; MAX_ZEROS] = [0; MAX_ZEROS];
88        debug_assert!(padding < MAX_ZEROS);
89
90        self.write(&ZEROS[0..padding])
91    }
92
93    /// Aligns the position of the serializer to the given alignment.
94    fn align(&mut self, align: usize) -> Result<usize, E> {
95        let mask = align - 1;
96        debug_assert_eq!(align & mask, 0);
97
98        self.pad((align - (self.pos() & mask)) & mask)?;
99        Ok(self.pos())
100    }
101
102    /// Aligns the position of the serializer to be suitable to write the given
103    /// type.
104    fn align_for<T>(&mut self) -> Result<usize, E> {
105        self.align(mem::align_of::<T>())
106    }
107
108    /// Resolves the given value with its resolver and writes the archived type.
109    ///
110    /// Returns the position of the written archived type.
111    ///
112    /// # Safety
113    ///
114    /// - `resolver` must be the result of serializing `value`
115    /// - The serializer must be aligned for a `T::Archived`
116    unsafe fn resolve_aligned<T: Archive + ?Sized>(
117        &mut self,
118        value: &T,
119        resolver: T::Resolver,
120    ) -> Result<usize, E> {
121        let pos = self.pos();
122        debug_assert_eq!(pos & (mem::align_of::<T::Archived>() - 1), 0);
123
124        let mut resolved = mem::MaybeUninit::<T::Archived>::uninit();
125        // SAFETY: `resolved` is properly aligned and valid for writes of
126        // `size_of::<T::Archived>()` bytes.
127        unsafe {
128            resolved.as_mut_ptr().write_bytes(0, 1);
129        }
130        // SAFETY: `resolved.as_mut_ptr()` points to a local zeroed
131        // `MaybeUninit`, and so is properly aligned, dereferenceable, and all
132        // of its bytes are initialized.
133        let out = unsafe { Place::new_unchecked(pos, resolved.as_mut_ptr()) };
134        value.resolve(resolver, out);
135        self.write(out.as_slice())?;
136        Ok(pos)
137    }
138
139    /// Resolves the given reference with its resolver and writes the archived
140    /// reference.
141    ///
142    /// Returns the position of the written archived `RelPtr`.
143    ///
144    /// # Safety
145    ///
146    /// The serializer must be aligned for a `RelPtr<T::Archived>`.
147    unsafe fn resolve_unsized_aligned<T: ArchiveUnsized + ?Sized>(
148        &mut self,
149        value: &T,
150        to: usize,
151    ) -> Result<usize, E> {
152        let from = self.pos();
153        debug_assert_eq!(
154            from & (mem::align_of::<RelPtr<T::Archived>>() - 1),
155            0
156        );
157
158        let mut resolved = mem::MaybeUninit::<RelPtr<T::Archived>>::uninit();
159        // SAFETY: `resolved` is properly aligned and valid for writes of
160        // `size_of::<RelPtr<T::Archived>>()` bytes.
161        unsafe {
162            resolved.as_mut_ptr().write_bytes(0, 1);
163        }
164        // SAFETY: `resolved.as_mut_ptr()` points to a local zeroed
165        // `MaybeUninit`, and so is properly aligned, dereferenceable, and all
166        // of its bytes are initialized.
167        let out = unsafe { Place::new_unchecked(from, resolved.as_mut_ptr()) };
168        RelPtr::emplace_unsized(to, value.archived_metadata(), out);
169
170        self.write(out.as_slice())?;
171        Ok(from)
172    }
173}
174
175impl<T, E> WriterExt<E> for T where T: Writer<E> + ?Sized {}
176
177#[cfg(test)]
178mod tests {
179    #[cfg(feature = "alloc")]
180    #[test]
181    fn reusable_writer() {
182        use rend::{u16_le, u32_le};
183
184        use crate::{api::high::to_bytes_in, util::AlignedVec};
185
186        let mut writer = AlignedVec::<16>::new();
187
188        _ = to_bytes_in::<_, rancor::Error>(
189            &u32_le::from_native(42),
190            &mut writer,
191        );
192        assert_eq!(&writer[..], &[42, 0, 0, 0]);
193        writer.clear(); // keeps capacity of 4
194
195        _ = to_bytes_in::<_, rancor::Error>(
196            &u16_le::from_native(1337),
197            &mut writer,
198        );
199        assert_eq!(&writer[..], &[57, 5]);
200        writer.clear();
201
202        assert_eq!(writer.capacity(), 4);
203    }
204}