rkyv/place.rs
1//! An initialized, writeable location in memory.
2
3use core::{mem::size_of, ptr::NonNull};
4
5use munge::{Borrow, Destructure, Restructure};
6
7use crate::traits::{LayoutRaw, NoUndef};
8
9/// A place to write a `T` paired with its position in the output buffer.
10pub struct Place<T: ?Sized> {
11 pos: usize,
12 ptr: NonNull<T>,
13}
14
15impl<T: ?Sized> Clone for Place<T> {
16 fn clone(&self) -> Self {
17 *self
18 }
19}
20
21impl<T: ?Sized> Copy for Place<T> {}
22
23impl<T: ?Sized> Place<T> {
24 /// Creates a new `Place` from an output pointer.
25 ///
26 /// # Safety
27 ///
28 /// `ptr` must be properly aligned, dereferenceable, and all of its bytes
29 /// must be initialized.
30 pub unsafe fn new_unchecked(pos: usize, ptr: *mut T) -> Self {
31 unsafe {
32 Self {
33 pos,
34 ptr: NonNull::new_unchecked(ptr),
35 }
36 }
37 }
38
39 /// Creates a new `Place` from a parent pointer and the field the place
40 /// points to.
41 ///
42 /// # Safety
43 ///
44 /// - `ptr` must point to a field of `parent`
45 /// - `ptr` must be properly aligned, dereferenceable, and all of its bytes
46 /// must be initialized
47 pub unsafe fn from_field_unchecked<U: ?Sized>(
48 parent: Place<U>,
49 ptr: *mut T,
50 ) -> Self {
51 // SAFETY: We won't write anything to the parent pointer, so we
52 // definitely won't write any uninitialized bytes.
53 let parent_ptr = unsafe { parent.ptr() };
54 let offset = ptr as *mut () as usize - parent_ptr as *mut () as usize;
55 // SAFETY: The caller has guaranteed that `ptr` is properly aligned,
56 // dereferenceable, and all of its bytes are initialized.
57 unsafe { Self::new_unchecked(parent.pos() + offset, ptr) }
58 }
59
60 /// Returns the position of the place.
61 pub fn pos(&self) -> usize {
62 self.pos
63 }
64
65 /// Returns the pointer associated with this place.
66 ///
67 /// # Safety
68 ///
69 /// Uninitialized bytes must not be written to the returned pointer.
70 pub unsafe fn ptr(&self) -> *mut T {
71 self.ptr.as_ptr()
72 }
73
74 /// Writes the provided value to this place.
75 ///
76 /// # Safety
77 ///
78 /// `value` must not have any uninitialized bytes (e.g. padding).
79 pub unsafe fn write_unchecked(&self, value: T)
80 where
81 T: Sized,
82 {
83 unsafe {
84 self.ptr().write(value);
85 }
86 }
87
88 /// Writes the provided value to this place.
89 pub fn write(&self, value: T)
90 where
91 T: NoUndef + Sized,
92 {
93 unsafe {
94 self.write_unchecked(value);
95 }
96 }
97
98 /// Returns this place casted to the given type.
99 ///
100 /// # Safety
101 ///
102 /// This place must point to a valid `U`.
103 pub unsafe fn cast_unchecked<U>(&self) -> Place<U>
104 where
105 T: Sized,
106 {
107 Place {
108 pos: self.pos,
109 ptr: self.ptr.cast(),
110 }
111 }
112
113 /// Returns a slice of the bytes this place points to.
114 pub fn as_slice(&self) -> &[u8]
115 where
116 T: LayoutRaw,
117 {
118 let ptr = self.ptr.as_ptr();
119 let len = T::layout_raw(ptr_meta::metadata(ptr)).unwrap().size();
120 // SAFETY: The pointers of places are always properly aligned and
121 // dereferenceable. All of the bytes this place points to are guaranteed
122 // to be initialized at all times.
123 unsafe { core::slice::from_raw_parts(ptr.cast::<u8>(), len) }
124 }
125}
126
127impl<T> Place<[T]> {
128 /// Gets a `Place` to the `i`-th element of the slice.
129 ///
130 /// # Safety
131 ///
132 /// `i` must be in-bounds for the slice pointed to by this place.
133 pub unsafe fn index(&self, i: usize) -> Place<T> {
134 // SAFETY: The caller has guaranteed that `i` is in-bounds for the slice
135 // pointed to by this place.
136 let ptr = unsafe { self.ptr().cast::<T>().add(i) };
137 // SAFETY: `ptr` is an element of `self`, and so is also properly
138 // aligned, dereferenceable, and all of its bytes are initialized.
139 unsafe { Place::new_unchecked(self.pos() + i * size_of::<T>(), ptr) }
140 }
141}
142
143impl<T, const N: usize> Place<[T; N]> {
144 /// Gets a `Place` to the `i`-th element of the array.
145 ///
146 /// # Safety
147 ///
148 /// `i` must be in-bounds for the array pointed to by this place.
149 pub unsafe fn index(&self, i: usize) -> Place<T> {
150 // SAFETY: The caller has guaranteed that `i` is in-bounds for the array
151 // pointed to by this place.
152 let ptr = unsafe { self.ptr().cast::<T>().add(i) };
153 // SAFETY: `ptr` is an element of `self`, and so is also properly
154 // aligned, dereferenceable, and all of its bytes are initialized.
155 unsafe { Place::new_unchecked(self.pos() + i * size_of::<T>(), ptr) }
156 }
157}
158
159unsafe impl<T: ?Sized> Destructure for Place<T> {
160 type Underlying = T;
161 type Destructuring = Borrow;
162
163 fn underlying(&mut self) -> *mut Self::Underlying {
164 self.ptr.as_ptr()
165 }
166}
167
168unsafe impl<T: ?Sized, U: ?Sized> Restructure<U> for Place<T> {
169 type Restructured = Place<U>;
170
171 unsafe fn restructure(&self, ptr: *mut U) -> Self::Restructured {
172 // SAFETY: `ptr` is a pointer to a subfield of the underlying pointer,
173 // and so is also properly aligned, dereferenceable, and all of its
174 // bytes are initialized.
175 unsafe { Place::from_field_unchecked(*self, ptr) }
176 }
177}