1#[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
17pub trait Positional {
19 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
50pub trait Writer<E = <Self as Fallible>::Error>: Positional {
60 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
82pub trait WriterExt<E>: Writer<E> {
84 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 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 fn align_for<T>(&mut self) -> Result<usize, E> {
105 self.align(mem::align_of::<T>())
106 }
107
108 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 unsafe {
128 resolved.as_mut_ptr().write_bytes(0, 1);
129 }
130 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 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 unsafe {
162 resolved.as_mut_ptr().write_bytes(0, 1);
163 }
164 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(); _ = 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}