1#[cfg(feature = "alloc")]
4mod alloc;
5mod core;
6
7use ::core::{
8 alloc::LayoutError, error::Error, fmt, mem::transmute, ptr::NonNull,
9};
10use ptr_meta::{from_raw_parts_mut, metadata, DynMetadata, Pointee};
11use rancor::{fail, Fallible, ResultExt as _, Source, Strategy};
12
13#[cfg(feature = "alloc")]
14pub use self::alloc::*;
15pub use self::core::*;
16use crate::{traits::LayoutRaw, ArchiveUnsized, DeserializeUnsized};
17
18#[derive(Clone, Copy)]
20pub union Metadata {
21 unit: (),
22 usize: usize,
23 vtable: DynMetadata<()>,
24}
25
26impl fmt::Debug for Metadata {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 write!(f, "<metadata>")
29 }
30}
31
32impl From<()> for Metadata {
33 fn from(value: ()) -> Self {
34 Self { unit: value }
35 }
36}
37
38impl From<usize> for Metadata {
39 fn from(value: usize) -> Self {
40 Self { usize: value }
41 }
42}
43
44impl<T: ?Sized> From<DynMetadata<T>> for Metadata {
45 fn from(value: DynMetadata<T>) -> Self {
46 Self {
47 vtable: unsafe {
48 transmute::<DynMetadata<T>, DynMetadata<()>>(value)
49 },
50 }
51 }
52}
53
54pub trait FromMetadata {
56 unsafe fn from_metadata(metadata: Metadata) -> Self;
63}
64
65impl FromMetadata for () {
70 unsafe fn from_metadata(metadata: Metadata) -> Self {
71 unsafe { metadata.unit }
72 }
73}
74
75impl FromMetadata for usize {
76 unsafe fn from_metadata(metadata: Metadata) -> Self {
77 unsafe { metadata.usize }
78 }
79}
80
81impl<T: ?Sized> FromMetadata for DynMetadata<T> {
82 unsafe fn from_metadata(metadata: Metadata) -> Self {
83 unsafe { transmute::<DynMetadata<()>, DynMetadata<T>>(metadata.vtable) }
84 }
85}
86
87#[derive(Clone, Copy, Debug)]
89pub struct ErasedPtr {
90 data_address: NonNull<()>,
91 metadata: Metadata,
92}
93
94impl ErasedPtr {
95 #[inline]
97 pub fn new<T>(ptr: NonNull<T>) -> Self
98 where
99 T: Pointee + ?Sized,
100 T::Metadata: Into<Metadata>,
101 {
102 Self {
103 data_address: ptr.cast(),
104 metadata: metadata(ptr.as_ptr()).into(),
105 }
106 }
107
108 #[inline]
110 pub fn data_address(&self) -> *mut () {
111 self.data_address.as_ptr()
112 }
113
114 #[inline]
118 unsafe fn downcast_unchecked<T>(&self) -> *mut T
119 where
120 T: Pointee + ?Sized,
121 T::Metadata: FromMetadata,
122 {
123 from_raw_parts_mut(self.data_address.as_ptr(), unsafe {
124 T::Metadata::from_metadata(self.metadata)
125 })
126 }
127}
128
129pub unsafe trait SharedPointer<T: Pointee + ?Sized> {
136 fn alloc(metadata: T::Metadata) -> Result<*mut T, LayoutError>;
138
139 unsafe fn from_value(ptr: *mut T) -> *mut T;
146
147 unsafe fn drop(ptr: *mut T);
154}
155
156pub enum PoolingState {
158 Started,
161 Pending,
165 Finished(ErasedPtr),
168}
169
170pub trait Pooling<E = <Self as Fallible>::Error> {
174 fn start_pooling(&mut self, address: usize) -> PoolingState;
176
177 unsafe fn finish_pooling(
185 &mut self,
186 address: usize,
187 ptr: ErasedPtr,
188 drop: unsafe fn(ErasedPtr),
189 ) -> Result<(), E>;
190}
191
192impl<T, E> Pooling<E> for Strategy<T, E>
193where
194 T: Pooling<E>,
195{
196 fn start_pooling(&mut self, address: usize) -> PoolingState {
197 T::start_pooling(self, address)
198 }
199
200 unsafe fn finish_pooling(
201 &mut self,
202 address: usize,
203 ptr: ErasedPtr,
204 drop: unsafe fn(ErasedPtr),
205 ) -> Result<(), E> {
206 unsafe { T::finish_pooling(self, address, ptr, drop) }
209 }
210}
211
212#[derive(Debug)]
213struct CyclicSharedPointerError;
214
215impl fmt::Display for CyclicSharedPointerError {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 write!(
218 f,
219 "encountered cyclic shared pointers while deserializing\nhelp: \
220 change your deserialization strategy to `Unpool` or use the \
221 `Unpool` wrapper type to break the cycle",
222 )
223 }
224}
225
226impl Error for CyclicSharedPointerError {}
227
228pub trait PoolingExt<E>: Pooling<E> {
230 fn deserialize_shared<T, P>(
234 &mut self,
235 value: &T::Archived,
236 ) -> Result<*mut T, Self::Error>
237 where
238 T: ArchiveUnsized + Pointee + LayoutRaw + ?Sized,
239 T::Metadata: Into<Metadata> + FromMetadata,
240 T::Archived: DeserializeUnsized<T, Self>,
241 P: SharedPointer<T>,
242 Self: Fallible<Error = E>,
243 E: Source,
244 {
245 unsafe fn drop_shared<T, P>(ptr: ErasedPtr)
246 where
247 T: Pointee + ?Sized,
248 T::Metadata: FromMetadata,
249 P: SharedPointer<T>,
250 {
251 unsafe { P::drop(ptr.downcast_unchecked::<T>()) }
252 }
253
254 let address = value as *const T::Archived as *const () as usize;
255 let metadata = T::Archived::deserialize_metadata(value);
256
257 match self.start_pooling(address) {
258 PoolingState::Started => {
259 let out = P::alloc(metadata).into_error()?;
260 unsafe { value.deserialize_unsized(self, out)? };
261 let ptr = unsafe { NonNull::new_unchecked(P::from_value(out)) };
262
263 unsafe {
264 self.finish_pooling(
265 address,
266 ErasedPtr::new(ptr),
267 drop_shared::<T, P>,
268 )?;
269 }
270
271 Ok(ptr.as_ptr())
272 }
273 PoolingState::Pending => fail!(CyclicSharedPointerError),
274 PoolingState::Finished(ptr) => {
275 Ok(from_raw_parts_mut(ptr.data_address.as_ptr(), metadata))
276 }
277 }
278 }
279}
280
281impl<T, E> PoolingExt<E> for T where T: Pooling<E> + ?Sized {}