infinity_pool/handles/
managed.rs1use std::any::type_name;
2use std::borrow::Borrow;
3use std::fmt;
4use std::ops::Deref;
5use std::pin::Pin;
6use std::ptr::NonNull;
7use std::sync::Arc;
8
9use parking_lot::Mutex;
10
11use crate::{PooledMut, RawOpaquePoolThreadSafe, RawPooled, RawPooledMut};
12
13#[doc = include_str!("../../doc/snippets/ref_counted_handle_implications.md")]
19#[doc = include_str!("../../doc/snippets/shared_handle_implications.md")]
20#[doc = include_str!("../../doc/snippets/nonlocal_handle_thread_safety.md")]
21pub struct Pooled<T: ?Sized> {
22 inner: RawPooled<T>,
24
25 remover: Arc<Remover>,
26}
27
28impl<T: ?Sized> Pooled<T> {
29 #[must_use]
35 pub(crate) unsafe fn new(
36 inner: RawPooledMut<T>,
37 pool: Arc<Mutex<RawOpaquePoolThreadSafe>>,
38 ) -> Self {
39 let inner = inner.into_shared();
40
41 let remover = Remover {
42 handle: unsafe { inner.erase_raw() },
46 pool,
47 };
48
49 Self {
50 inner,
51 remover: Arc::new(remover),
52 }
53 }
54
55 #[doc = include_str!("../../doc/snippets/handle_ptr.md")]
56 #[must_use]
57 #[inline]
58 #[cfg_attr(test, mutants::skip)] pub fn ptr(&self) -> NonNull<T> {
60 self.inner.ptr()
61 }
62
63 #[doc = include_str!("../../doc/snippets/ref_counted_as_pin.md")]
64 #[must_use]
65 #[inline]
66 #[cfg_attr(test, mutants::skip)] pub fn as_pin(&self) -> Pin<&T> {
68 unsafe { Pin::new_unchecked(self) }
70 }
71
72 #[doc(hidden)]
82 #[must_use]
83 #[inline]
84 pub unsafe fn __private_cast_dyn_with_fn<U: ?Sized, F>(self, cast_fn: F) -> Pooled<U>
85 where
86 F: FnOnce(&T) -> &U,
87 {
88 let new_inner = unsafe { self.inner.__private_cast_dyn_with_fn(cast_fn) };
92
93 Pooled {
94 inner: new_inner,
95 remover: self.remover,
96 }
97 }
98
99 #[must_use]
105 #[inline]
106 #[cfg_attr(test, mutants::skip)] pub fn erase(self) -> Pooled<()> {
108 Pooled {
109 inner: unsafe { self.inner.erase_raw() },
113 remover: self.remover,
114 }
115 }
116}
117
118#[cfg_attr(coverage_nightly, coverage(off))] impl<T: ?Sized> fmt::Debug for Pooled<T> {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 f.debug_struct(type_name::<Self>())
122 .field("inner", &self.inner)
123 .field("remover", &self.remover)
124 .finish()
125 }
126}
127
128impl<T: ?Sized> Deref for Pooled<T> {
129 type Target = T;
130
131 #[inline]
132 #[cfg_attr(test, mutants::skip)] fn deref(&self) -> &Self::Target {
134 unsafe { self.ptr().as_ref() }
138 }
139}
140
141impl<T: ?Sized> Borrow<T> for Pooled<T> {
142 #[inline]
143 #[cfg_attr(test, mutants::skip)] fn borrow(&self) -> &T {
145 self
146 }
147}
148
149impl<T: ?Sized> AsRef<T> for Pooled<T> {
150 #[inline]
151 #[cfg_attr(test, mutants::skip)] fn as_ref(&self) -> &T {
153 self
154 }
155}
156
157impl<T: ?Sized> Clone for Pooled<T> {
158 #[inline]
159 fn clone(&self) -> Self {
160 Self {
161 inner: self.inner,
162 remover: Arc::clone(&self.remover),
163 }
164 }
165}
166
167impl<T: ?Sized> From<PooledMut<T>> for Pooled<T> {
168 #[inline]
169 fn from(value: PooledMut<T>) -> Self {
170 value.into_shared()
171 }
172}
173
174struct Remover {
176 handle: RawPooled<()>,
177 pool: Arc<Mutex<RawOpaquePoolThreadSafe>>,
178}
179
180#[cfg_attr(coverage_nightly, coverage(off))] impl fmt::Debug for Remover {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 f.debug_struct(type_name::<Self>())
184 .field("handle", &self.handle)
185 .field("pool", &"<pool>")
186 .finish()
187 }
188}
189
190impl Drop for Remover {
191 fn drop(&mut self) {
192 let mut pool = self.pool.lock();
193
194 unsafe {
197 pool.remove(self.handle);
198 }
199 }
200}
201
202unsafe impl Sync for Remover {}
207
208#[cfg(test)]
209#[cfg_attr(coverage_nightly, coverage(off))]
210mod tests {
211 use static_assertions::{assert_impl_all, assert_not_impl_any};
212
213 use super::*;
214 use crate::{NotSendNotSync, NotSendSync, SendAndSync, SendNotSync};
215
216 assert_impl_all!(Pooled<SendAndSync>: Send, Sync);
217 assert_impl_all!(Pooled<SendNotSync>: Send, Sync);
218 assert_impl_all!(Pooled<NotSendNotSync>: Sync);
219 assert_impl_all!(Pooled<NotSendSync>: Sync);
220
221 assert_not_impl_any!(Pooled<NotSendNotSync>: Send);
222 assert_not_impl_any!(Pooled<NotSendSync>: Send);
223
224 assert_impl_all!(Pooled<SendAndSync>: Clone);
226
227 assert_impl_all!(Remover: Send, Sync);
228
229 assert_impl_all!(Remover: Drop);
231
232 #[test]
233 fn erase_extends_lifetime() {
234 use crate::OpaquePool;
235
236 let pool = OpaquePool::with_layout_of::<u32>();
237 let handle = pool.insert(42);
238 let shared = handle.into_shared();
239
240 let erased = shared.clone().erase();
242
243 assert_eq!(pool.len(), 1);
245 assert_eq!(*shared, 42);
246
247 drop(shared);
249
250 assert_eq!(pool.len(), 1);
252
253 drop(erased);
255 assert_eq!(pool.len(), 0);
256 }
257
258 #[test]
259 fn erase_multiple_clones() {
260 use crate::OpaquePool;
261
262 let pool = OpaquePool::with_layout_of::<String>();
263 let handle = pool.insert(String::from("test"));
264 let shared = handle.into_shared();
265
266 let clone1 = shared.clone();
267 let clone2 = shared.clone();
268 let erased1 = clone1.erase();
269 let erased2 = clone2.erase();
270
271 assert_eq!(pool.len(), 1);
272 assert_eq!(*shared, "test");
273
274 drop(shared);
275 assert_eq!(pool.len(), 1);
276
277 drop(erased1);
278 assert_eq!(pool.len(), 1);
279
280 drop(erased2);
281 assert_eq!(pool.len(), 0);
282 }
283
284 #[test]
285 fn erase_works_with_not_unpin_types() {
286 use std::marker::PhantomPinned;
287
288 use crate::OpaquePool;
289
290 struct NotUnpin {
292 #[allow(dead_code, reason = "Field used to give struct non-zero size")]
293 data: i32,
294 _marker: PhantomPinned,
295 }
296
297 let pool = OpaquePool::with_layout_of::<NotUnpin>();
298 let handle = pool.insert(NotUnpin {
299 data: 42,
300 _marker: PhantomPinned,
301 });
302
303 let erased = handle.into_shared().erase();
306
307 assert_eq!(pool.len(), 1);
308
309 drop(erased);
310 assert_eq!(pool.len(), 0);
311 }
312}