ser_raw/serializer_traits/ptr_writing.rs
1use crate::{
2 pos::{Addr, PosMapping},
3 ser_traits::PosTracking,
4 storage::Storage,
5};
6
7/// Trait for serializers which overwrite pointers in output.
8///
9/// Used by `CompleteSerializer` and `PtrOffsetSerializer`, provided by this
10/// crate.
11pub trait PtrWriting: PosTracking {
12 /// Overwrite a pointer in output.
13 ///
14 /// # Safety
15 ///
16 /// * `ptr_pos` must be less than or equal to
17 /// `capacity - mem::size_of::<usize>()`
18 /// (i.e. a position which is within the output)
19 /// * `target_pos` must be less than or equal to
20 /// `capacity - mem::size_of_val(value)`
21 /// where `value` is the value being pointed to.
22 ///
23 /// Some serializers may also impose requirements concerning alignment which
24 /// caller must satisfy.
25 unsafe fn write_ptr(&mut self, ptr_pos: usize, target_pos: usize) -> ();
26
27 // Skip recording position mapping here because no further processing of the
28 // slice, but still write pointer
29 #[inline]
30 fn do_push_slice<T>(&mut self, slice: &[T], ptr_addr: Self::Addr) {
31 // Align storage, ready to write slice
32 self.storage_mut().align_for::<T>();
33
34 // Overwrite pointer with position within output (relative to start of output)
35 unsafe { self.write_ptr(self.pos_mapping().pos_for_addr(ptr_addr.addr()), self.pos()) };
36
37 // Push slice to storage.
38 // `push_slice_unaligned`'s requirements are satisfied by `align_for::<T>()` and
39 // `align_after::<T>()`.
40 unsafe { self.storage_mut().push_slice_unaligned(slice) };
41 self.storage_mut().align_after::<T>();
42 }
43
44 #[inline]
45 fn do_push_and_process_slice<T, P: FnOnce(&mut Self)>(
46 &mut self,
47 slice: &[T],
48 ptr_addr: Self::Addr,
49 process: P,
50 ) {
51 // Get position mapping before this push
52 let pos_mapping_before = *self.pos_mapping();
53
54 // Align storage, ready to write slice
55 self.storage_mut().align_for::<T>();
56
57 // Overwrite pointer with position within output (relative to start of output)
58 unsafe { self.write_ptr(pos_mapping_before.pos_for_addr(ptr_addr.addr()), self.pos()) };
59
60 // Record position mapping for this slice
61 self.set_pos_mapping(PosMapping::new(slice.as_ptr() as usize, self.pos()));
62
63 // Push slice to storage.
64 // `push_slice_unaligned`'s requirements are satisfied by `align_for::<T>()` and
65 // `align_after::<T>()`.
66 unsafe { self.storage_mut().push_slice_unaligned(slice) };
67 self.storage_mut().align_after::<T>();
68
69 // Call `process` function (which may use the position mapping we set)
70 process(self);
71
72 // Reset position mapping back to as it was before
73 self.set_pos_mapping(pos_mapping_before);
74 }
75}