infinity_pool/handles/
blind_local.rs1use std::any::type_name;
2use std::borrow::Borrow;
3use std::cell::RefCell;
4use std::fmt;
5use std::ops::Deref;
6use std::pin::Pin;
7use std::ptr::NonNull;
8use std::rc::Rc;
9
10use crate::{LayoutKey, LocalBlindPoolCore, LocalBlindPooledMut, RawPooled, RawPooledMut};
11
12#[doc = include_str!("../../doc/snippets/ref_counted_handle_implications.md")]
14#[doc = include_str!("../../doc/snippets/shared_handle_implications.md")]
15pub struct LocalBlindPooled<T: ?Sized> {
20 inner: RawPooled<T>,
21
22 remover: Rc<Remover>,
27}
28
29impl<T: ?Sized> LocalBlindPooled<T> {
30 #[must_use]
31 pub(crate) fn new(inner: RawPooledMut<T>, key: LayoutKey, core: LocalBlindPoolCore) -> Self {
32 let inner = inner.into_shared();
33
34 let remover = Remover {
35 handle: unsafe { inner.erase_raw() },
37 key,
38 core,
39 };
40
41 Self {
42 inner,
43 remover: Rc::new(remover),
44 }
45 }
46
47 #[doc = include_str!("../../doc/snippets/handle_ptr.md")]
48 #[must_use]
49 #[inline]
50 #[cfg_attr(test, mutants::skip)] pub fn ptr(&self) -> NonNull<T> {
52 self.inner.ptr()
53 }
54
55 #[doc = include_str!("../../doc/snippets/ref_counted_as_pin.md")]
56 #[must_use]
57 #[inline]
58 #[cfg_attr(test, mutants::skip)] pub fn as_pin(&self) -> Pin<&T> {
60 unsafe { Pin::new_unchecked(self) }
62 }
63
64 #[doc(hidden)]
74 #[must_use]
75 #[inline]
76 pub unsafe fn __private_cast_dyn_with_fn<U: ?Sized, F>(self, cast_fn: F) -> LocalBlindPooled<U>
77 where
78 F: FnOnce(&T) -> &U,
79 {
80 let new_inner = unsafe { self.inner.__private_cast_dyn_with_fn(cast_fn) };
84
85 LocalBlindPooled {
86 inner: new_inner,
87 remover: self.remover,
88 }
89 }
90
91 #[must_use]
97 #[inline]
98 #[cfg_attr(test, mutants::skip)] pub fn erase(self) -> LocalBlindPooled<()> {
100 LocalBlindPooled {
101 inner: unsafe { self.inner.erase_raw() },
103 remover: self.remover,
104 }
105 }
106}
107
108#[cfg_attr(coverage_nightly, coverage(off))] impl<T: ?Sized> fmt::Debug for LocalBlindPooled<T> {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 f.debug_struct(type_name::<Self>())
112 .field("inner", &self.inner)
113 .field("remover", &self.remover)
114 .finish()
115 }
116}
117
118impl<T: ?Sized> Deref for LocalBlindPooled<T> {
119 type Target = T;
120
121 #[inline]
122 #[cfg_attr(test, mutants::skip)] fn deref(&self) -> &Self::Target {
124 unsafe { self.ptr().as_ref() }
128 }
129}
130
131impl<T: ?Sized> Borrow<T> for LocalBlindPooled<T> {
132 #[inline]
133 #[cfg_attr(test, mutants::skip)] fn borrow(&self) -> &T {
135 self
136 }
137}
138
139impl<T: ?Sized> AsRef<T> for LocalBlindPooled<T> {
140 #[inline]
141 #[cfg_attr(test, mutants::skip)] fn as_ref(&self) -> &T {
143 self
144 }
145}
146
147impl<T: ?Sized> Clone for LocalBlindPooled<T> {
148 #[inline]
149 fn clone(&self) -> Self {
150 Self {
151 inner: self.inner,
152 remover: Rc::clone(&self.remover),
153 }
154 }
155}
156
157impl<T: ?Sized> From<LocalBlindPooledMut<T>> for LocalBlindPooled<T> {
158 #[inline]
159 fn from(value: LocalBlindPooledMut<T>) -> Self {
160 value.into_shared()
161 }
162}
163
164#[derive(Debug)]
166struct Remover {
167 handle: RawPooled<()>,
168 key: LayoutKey,
169 core: LocalBlindPoolCore,
170}
171
172impl Drop for Remover {
173 fn drop(&mut self) {
174 let mut core = RefCell::borrow_mut(&self.core);
175
176 let pool = core
177 .get_mut(&self.key)
178 .expect("if the handle still exists, the inner pool must still exist");
179
180 unsafe {
184 pool.remove(self.handle);
185 }
186 }
187}
188
189#[cfg(test)]
190#[cfg_attr(coverage_nightly, coverage(off))]
191mod tests {
192 use std::borrow::Borrow;
193
194 use static_assertions::{assert_impl_all, assert_not_impl_any};
195
196 use super::*;
197 use crate::{LocalBlindPool, NotSendNotSync, NotSendSync, SendAndSync, SendNotSync};
198
199 assert_not_impl_any!(LocalBlindPooled<SendAndSync>: Send, Sync);
200 assert_not_impl_any!(LocalBlindPooled<SendNotSync>: Send, Sync);
201 assert_not_impl_any!(LocalBlindPooled<NotSendNotSync>: Send, Sync);
202 assert_not_impl_any!(LocalBlindPooled<NotSendSync>: Send, Sync);
203
204 assert_impl_all!(LocalBlindPooled<SendAndSync>: Clone);
206
207 assert_not_impl_any!(Remover: Send, Sync);
208
209 assert_impl_all!(Remover: Drop);
211
212 #[test]
213 fn as_pin_returns_pinned_reference() {
214 let pool = LocalBlindPool::new();
215 let shared = pool.insert(42_u32).into_shared();
216
217 let pinned = shared.as_pin();
218 assert_eq!(*pinned.get_ref(), 42);
219 }
220
221 #[test]
222 fn deref_returns_reference_to_value() {
223 let pool = LocalBlindPool::new();
224 let shared = pool.insert(42_u32).into_shared();
225
226 assert_eq!(*shared, 42);
227 }
228
229 #[test]
230 fn borrow_returns_reference() {
231 let pool = LocalBlindPool::new();
232 let shared = pool.insert(42_u32).into_shared();
233
234 let borrowed: &u32 = shared.borrow();
235 assert_eq!(*borrowed, 42);
236 }
237
238 #[test]
239 fn as_ref_returns_reference() {
240 let pool = LocalBlindPool::new();
241 let shared = pool.insert(42_u32).into_shared();
242
243 let reference: &u32 = shared.as_ref();
244 assert_eq!(*reference, 42);
245 }
246
247 #[test]
248 fn erase_extends_lifetime() {
249 let pool = LocalBlindPool::new();
250 let shared = pool.insert(42_u32).into_shared();
251
252 let erased = shared.clone().erase();
253
254 assert_eq!(pool.len(), 1);
255 assert_eq!(*shared, 42);
256
257 drop(shared);
258 assert_eq!(pool.len(), 1);
259
260 drop(erased);
261 assert_eq!(pool.len(), 0);
262 }
263
264 #[test]
265 fn clone_creates_independent_handle() {
266 let pool = LocalBlindPool::new();
267 let shared = pool.insert(42_u32).into_shared();
268
269 let cloned = shared.clone();
270 assert_eq!(*cloned, 42);
271
272 drop(shared);
273 assert_eq!(pool.len(), 1);
274 assert_eq!(*cloned, 42);
275
276 drop(cloned);
277 assert_eq!(pool.len(), 0);
278 }
279
280 #[test]
281 fn from_mut_converts_to_shared() {
282 let pool = LocalBlindPool::new();
283 let handle = pool.insert(42_u32);
284
285 let shared: LocalBlindPooled<u32> = LocalBlindPooled::from(handle);
286 assert_eq!(*shared, 42);
287 assert_eq!(pool.len(), 1);
288 }
289
290 assert_impl_all!(Remover: Drop);
292}