infinity_pool/handles/
blind_raw_mut.rs

1use std::any::type_name;
2use std::fmt;
3use std::pin::Pin;
4use std::ptr::NonNull;
5
6use crate::{LayoutKey, RawBlindPooled, RawPooledMut};
7
8/// A unique handle to an object in a [`RawBlindPool`][crate::RawBlindPool].
9#[doc = include_str!("../../doc/snippets/raw_handle_implications.md")]
10#[doc = include_str!("../../doc/snippets/unique_handle_implications.md")]
11#[doc = include_str!("../../doc/snippets/unique_raw_handle_implications.md")]
12#[doc = include_str!("../../doc/snippets/nonlocal_handle_thread_safety.md")]
13pub struct RawBlindPooledMut<T>
14where
15    // We support casting to trait objects, hence `?Sized`.
16    T: ?Sized,
17{
18    key: LayoutKey,
19
20    // We inherit our thread-safety traits from this one (Send from T, Sync always).
21    inner: RawPooledMut<T>,
22}
23
24impl<T: ?Sized> RawBlindPooledMut<T> {
25    #[must_use]
26    pub(crate) fn new(key: LayoutKey, inner: RawPooledMut<T>) -> Self {
27        Self { key, inner }
28    }
29
30    #[doc = include_str!("../../doc/snippets/handle_ptr.md")]
31    #[must_use]
32    #[inline]
33    #[cfg_attr(test, mutants::skip)] // cargo-mutants tries many unviable mutations, wasting precious build minutes.
34    pub fn ptr(&self) -> NonNull<T> {
35        self.inner.ptr()
36    }
37
38    /// Transforms the unique handle into a shared handle that can be cloned and copied freely.
39    ///
40    /// A shared handle does not support the creation of exclusive references to the target object
41    /// and requires the caller to guarantee that no further access is attempted through any handle
42    /// after removing the object from the pool.
43    #[must_use]
44    #[inline]
45    #[cfg_attr(test, mutants::skip)] // cargo-mutants tries many unviable mutations, wasting precious build minutes.
46    pub fn into_shared(self) -> RawBlindPooled<T> {
47        RawBlindPooled::new(self.key, self.inner.into_shared())
48    }
49
50    #[doc = include_str!("../../doc/snippets/raw_as_pin.md")]
51    #[must_use]
52    #[inline]
53    #[cfg_attr(test, mutants::skip)] // cargo-mutants tries many unviable mutations, wasting precious build minutes.
54    pub unsafe fn as_pin(&self) -> Pin<&T> {
55        // SAFETY: Forwarding safety guarantees from the caller.
56        let as_ref = unsafe { self.as_ref() };
57
58        // SAFETY: Pooled items are always pinned.
59        unsafe { Pin::new_unchecked(as_ref) }
60    }
61
62    #[doc = include_str!("../../doc/snippets/raw_as_pin_mut.md")]
63    #[must_use]
64    #[inline]
65    #[cfg_attr(test, mutants::skip)] // cargo-mutants tries many unviable mutations, wasting precious build minutes.
66    pub unsafe fn as_pin_mut(&mut self) -> Pin<&mut T> {
67        // SAFETY: This is a unique handle, so we guarantee borrow safety
68        // of the target object by borrowing the handle itself. Pointer validity
69        // requires pool to be alive, which is a safety requirement of this function.
70        let as_mut = unsafe { self.ptr().as_mut() };
71
72        // SAFETY: Pooled items are always pinned.
73        unsafe { Pin::new_unchecked(as_mut) }
74    }
75
76    #[doc = include_str!("../../doc/snippets/raw_mut_as_ref.md")]
77    #[must_use]
78    #[inline]
79    #[cfg_attr(test, mutants::skip)] // cargo-mutants tries many unviable mutations, wasting precious build minutes.
80    pub unsafe fn as_ref(&self) -> &T {
81        // SAFETY: This is a unique handle, so we guarantee borrow safety
82        // of the target object by borrowing the handle itself. Pointer validity
83        // requires pool to be alive, which is a safety requirement of this function.
84        unsafe { self.ptr().as_ref() }
85    }
86
87    /// Casts this handle to reference the target as a trait object.
88    ///
89    /// This method is only intended for use by the [`define_pooled_dyn_cast!`] macro
90    /// for type-safe casting operations.
91    ///
92    /// # Safety
93    ///
94    /// The caller must guarantee that the provided closure's input and output references
95    /// point to the same object.
96    ///
97    /// The caller must guarantee that the pool will remain alive for the duration the returned
98    /// reference is used.
99    #[doc(hidden)]
100    #[must_use]
101    #[inline]
102    pub unsafe fn __private_cast_dyn_with_fn<U: ?Sized, F>(self, cast_fn: F) -> RawBlindPooledMut<U>
103    where
104        F: FnOnce(&mut T) -> &mut U,
105    {
106        // SAFETY: Forwarding callback safety guarantees from the caller.
107        // We are an exclusive handle, so we always have the right to create
108        // exclusive references to the target of the handle, satisfying that requirement.
109        let new_inner = unsafe { self.inner.__private_cast_dyn_with_fn(cast_fn) };
110
111        RawBlindPooledMut {
112            key: self.key,
113            inner: new_inner,
114        }
115    }
116
117    /// Erase the type information from this handle, converting it to `RawBlindPooledMut<()>`.
118    ///
119    /// This is useful for extending the lifetime of an object in the pool without retaining
120    /// type information. The type-erased handle prevents access to the object but ensures
121    /// it remains in the pool.
122    #[must_use]
123    #[inline]
124    #[cfg_attr(test, mutants::skip)] // All mutations unviable - save some time.
125    pub fn erase(self) -> RawBlindPooledMut<()>
126    where
127        T: Send,
128    {
129        RawBlindPooledMut {
130            key: self.key,
131            // This is safe only because `RawBlindPool` is always `!Send`, requiring unsafe code
132            // to send across threads (which implies the user manually guaranteeing only `T: Send`
133            // are placed into the pool). This is a behavior that the inner handle relies upon.
134            // It assumes (correctly) that the pool it is associated with cannot be sent to another
135            // thread (via safe code) unless `T: Send`. In our case, we just blanket-disable it
136            // for soundness, as we cannot programmatically know whether everything in the pool
137            // is `Send` or not.
138            inner: self.inner.erase(),
139        }
140    }
141}
142
143impl<T: ?Sized + Unpin> RawBlindPooledMut<T> {
144    #[doc = include_str!("../../doc/snippets/raw_as_mut.md")]
145    #[must_use]
146    #[inline]
147    #[cfg_attr(test, mutants::skip)] // Cargo-mutants does not understand this signature - every mutation is unviable waste of time.
148    pub unsafe fn as_mut(&mut self) -> &mut T {
149        // SAFETY: This is a unique handle, so we guarantee borrow safety
150        // of the target object by borrowing the handle itself. Pointer validity
151        // requires pool to be alive, which is a safety requirement of this function.
152        unsafe { self.ptr().as_mut() }
153    }
154}
155
156impl<T: ?Sized> fmt::Debug for RawBlindPooledMut<T> {
157    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158        f.debug_struct(type_name::<Self>())
159            .field("key", &self.key)
160            .field("inner", &self.inner)
161            .finish()
162    }
163}
164
165#[cfg(test)]
166mod tests {
167    use std::cell::Cell;
168    use std::thread;
169
170    use static_assertions::{assert_impl_all, assert_not_impl_any};
171
172    use super::*;
173    use crate::{NotSendNotSync, NotSendSync, SendAndSync, SendNotSync};
174
175    assert_impl_all!(RawBlindPooledMut<SendAndSync>: Send, Sync);
176    assert_impl_all!(RawBlindPooledMut<SendNotSync>: Send, Sync);
177    assert_impl_all!(RawBlindPooledMut<NotSendNotSync>: Sync);
178    assert_impl_all!(RawBlindPooledMut<NotSendSync>: Sync);
179
180    assert_not_impl_any!(RawBlindPooledMut<NotSendNotSync>: Send);
181    assert_not_impl_any!(RawBlindPooledMut<NotSendSync>: Send);
182
183    // This is a unique handle, it cannot be cloneable/copyable.
184    assert_not_impl_any!(RawBlindPooledMut<SendAndSync>: Clone, Copy);
185
186    // This is not strictly a requirement but a destructor is not something we expect here.
187    assert_not_impl_any!(RawBlindPooledMut<SendAndSync>: Drop);
188
189    #[test]
190    fn unique_handle_can_cross_threads_with_send_only() {
191        use crate::RawBlindPool;
192
193        // A type that is Send but not Sync.
194        struct Counter {
195            value: Cell<i32>,
196        }
197
198        // SAFETY: Counter is designed to be Send but not Sync for testing.
199        unsafe impl Send for Counter {}
200
201        impl Counter {
202            fn new(value: i32) -> Self {
203                Self {
204                    value: Cell::new(value),
205                }
206            }
207
208            fn increment(&self) {
209                self.value.set(self.value.get() + 1);
210            }
211
212            fn get(&self) -> i32 {
213                self.value.get()
214            }
215        }
216
217        let mut pool = RawBlindPool::new();
218        let handle = pool.insert(Counter::new(0));
219
220        // Increment in main thread.
221        // SAFETY: Handle is valid and pool is still alive.
222        unsafe { handle.ptr().as_ref() }.increment();
223        // SAFETY: Handle is valid and pool is still alive.
224        assert_eq!(unsafe { handle.ptr().as_ref() }.get(), 1);
225
226        // Move handle to another thread (requires Send but not Sync).
227        let handle_in_thread = thread::spawn(move || {
228            // SAFETY: Handle is valid and pool is still alive.
229            unsafe { handle.ptr().as_ref() }.increment();
230            // SAFETY: Handle is valid and pool is still alive.
231            assert_eq!(unsafe { handle.ptr().as_ref() }.get(), 2);
232            handle
233        })
234        .join()
235        .unwrap();
236
237        // Back in main thread.
238        // SAFETY: Handle is valid and pool is still alive.
239        assert_eq!(unsafe { handle_in_thread.ptr().as_ref() }.get(), 2);
240    }
241}