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}