infinity_pool/handles/
blind_local_mut.rs

1use std::borrow::{Borrow, BorrowMut};
2use std::cell::RefCell;
3use std::ops::{Deref, DerefMut};
4use std::pin::Pin;
5use std::ptr::NonNull;
6use std::{fmt, mem, ptr};
7
8use crate::{LayoutKey, LocalBlindPoolCore, LocalBlindPooled, RawPooledMut};
9
10/// A unique single-threaded reference-counting handle for a pooled object.
11#[doc = include_str!("../../doc/snippets/ref_counted_handle_implications.md")]
12#[doc = include_str!("../../doc/snippets/unique_handle_implications.md")]
13///
14/// # Thread safety
15///
16/// This type is single-threaded.
17pub struct LocalBlindPooledMut<T: ?Sized> {
18    inner: RawPooledMut<T>,
19    key: LayoutKey,
20    core: LocalBlindPoolCore,
21}
22
23impl<T: ?Sized> LocalBlindPooledMut<T> {
24    #[must_use]
25    pub(crate) fn new(inner: RawPooledMut<T>, key: LayoutKey, core: LocalBlindPoolCore) -> Self {
26        Self { inner, key, core }
27    }
28
29    #[doc = include_str!("../../doc/snippets/handle_ptr.md")]
30    #[must_use]
31    #[inline]
32    #[cfg_attr(test, mutants::skip)] // cargo-mutants tries many unviable mutations, wasting precious build minutes.
33    pub fn ptr(&self) -> NonNull<T> {
34        self.inner.ptr()
35    }
36
37    #[doc = include_str!("../../doc/snippets/handle_into_shared.md")]
38    #[must_use]
39    #[inline]
40    #[cfg_attr(test, mutants::skip)] // cargo-mutants tries many unviable mutations, wasting precious build minutes.
41    pub fn into_shared(self) -> LocalBlindPooled<T> {
42        let (inner, layout, core) = self.into_parts();
43
44        LocalBlindPooled::new(inner, layout, core)
45    }
46
47    #[cfg_attr(test, mutants::skip)] // cargo-mutants tries many unviable mutations, wasting precious build minutes.
48    fn into_parts(self) -> (RawPooledMut<T>, LayoutKey, LocalBlindPoolCore) {
49        // We transfer these fields to the caller, so we do not want the current handle
50        // to be dropped. Hence we perform raw reads to extract the fields directly.
51
52        // SAFETY: The target is valid for reads.
53        let inner = unsafe { ptr::read(&raw const self.inner) };
54        // SAFETY: The target is valid for reads.
55        let key = unsafe { ptr::read(&raw const self.key) };
56        // SAFETY: The target is valid for reads.
57        let core = unsafe { ptr::read(&raw const self.core) };
58
59        // We are just "destructuring with Drop" here.
60        mem::forget(self);
61
62        (inner, key, core)
63    }
64
65    #[doc = include_str!("../../doc/snippets/ref_counted_as_pin.md")]
66    #[must_use]
67    #[inline]
68    #[cfg_attr(test, mutants::skip)] // cargo-mutants tries many unviable mutations, wasting precious build minutes.
69    pub fn as_pin(&self) -> Pin<&T> {
70        // SAFETY: LocalBlindPooled items are always pinned.
71        unsafe { Pin::new_unchecked(self) }
72    }
73
74    #[doc = include_str!("../../doc/snippets/ref_counted_as_pin_mut.md")]
75    #[must_use]
76    #[inline]
77    #[cfg_attr(test, mutants::skip)] // cargo-mutants tries many unviable mutations, wasting precious build minutes.
78    pub fn as_pin_mut(&mut self) -> Pin<&mut T> {
79        // SAFETY: This is a unique handle, so we guarantee borrow safety
80        // of the target object by borrowing the handle itself.
81        let as_mut = unsafe { self.ptr().as_mut() };
82
83        // SAFETY: LocalBlindPooled items are always pinned.
84        unsafe { Pin::new_unchecked(as_mut) }
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    #[doc(hidden)]
97    #[must_use]
98    #[inline]
99    pub unsafe fn __private_cast_dyn_with_fn<U: ?Sized, F>(
100        self,
101        cast_fn: F,
102    ) -> LocalBlindPooledMut<U>
103    where
104        F: FnOnce(&mut T) -> &mut U,
105    {
106        let (inner, key, core) = self.into_parts();
107
108        // SAFETY: Forwarding callback safety guarantees from the caller.
109        // We are an exclusive handle, so we always have the right to create
110        // exclusive references to the target of the handle, satisfying that requirement.
111        let new_inner = unsafe { inner.__private_cast_dyn_with_fn(cast_fn) };
112
113        LocalBlindPooledMut {
114            inner: new_inner,
115            key,
116            core,
117        }
118    }
119}
120
121impl<T> LocalBlindPooledMut<T>
122where
123    T: Unpin,
124{
125    #[doc = include_str!("../../doc/snippets/ref_counted_into_inner.md")]
126    #[must_use]
127    #[inline]
128    #[cfg_attr(test, mutants::skip)] // cargo-mutants tries many unviable mutations, wasting precious build minutes.
129    pub fn into_inner(self) -> T {
130        let (inner, key, core) = self.into_parts();
131
132        let mut core = RefCell::borrow_mut(&core);
133
134        let pool = core
135            .get_mut(&key)
136            .expect("if the handle still exists, the inner pool must still exist");
137
138        pool.remove_mut_unpin(inner)
139    }
140}
141
142impl<T: ?Sized> fmt::Debug for LocalBlindPooledMut<T> {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        f.debug_struct("LocalBlindPooledMut")
145            .field("inner", &self.inner)
146            .field("key", &self.key)
147            .field("core", &self.core)
148            .finish()
149    }
150}
151
152impl<T: ?Sized> Deref for LocalBlindPooledMut<T> {
153    type Target = T;
154
155    #[inline]
156    fn deref(&self) -> &Self::Target {
157        // SAFETY: This is a unique handle, so we guarantee borrow safety
158        // of the target object by borrowing the handle itself.
159        // We guarantee liveness by being a reference counted handle.
160        unsafe { self.ptr().as_ref() }
161    }
162}
163
164impl<T> DerefMut for LocalBlindPooledMut<T>
165where
166    T: ?Sized + Unpin,
167{
168    #[inline]
169    fn deref_mut(&mut self) -> &mut Self::Target {
170        // SAFETY: This is a unique handle, so we guarantee borrow safety
171        // of the target object by borrowing the handle itself.
172        // We guarantee liveness by being a reference counted handle.
173        unsafe { self.ptr().as_mut() }
174    }
175}
176
177impl<T: ?Sized> Borrow<T> for LocalBlindPooledMut<T> {
178    #[inline]
179    fn borrow(&self) -> &T {
180        self
181    }
182}
183
184impl<T> BorrowMut<T> for LocalBlindPooledMut<T>
185where
186    T: ?Sized + Unpin,
187{
188    #[inline]
189    fn borrow_mut(&mut self) -> &mut T {
190        self
191    }
192}
193
194impl<T: ?Sized> AsRef<T> for LocalBlindPooledMut<T> {
195    #[inline]
196    fn as_ref(&self) -> &T {
197        self
198    }
199}
200
201impl<T> AsMut<T> for LocalBlindPooledMut<T>
202where
203    T: ?Sized + Unpin,
204{
205    #[inline]
206    fn as_mut(&mut self) -> &mut T {
207        self
208    }
209}
210
211impl<T: ?Sized> Drop for LocalBlindPooledMut<T> {
212    fn drop(&mut self) {
213        // While `RawLocalBlindPooledMut` is technically not Copy, we use our insider knowledge
214        // that actually it is in reality just a fat pointer, so we can actually copy it.
215        // The only reason it is not Copy is to ensure uniqueness, which we do not care
216        // about here because the copy in `self` is going away. We just do not want to
217        // insert an Option that we have to check in every method.
218        //
219        // SAFETY: The target is valid for reads.
220        let inner = unsafe { ptr::read(&raw const self.inner) };
221
222        let mut core = RefCell::borrow_mut(&self.core);
223
224        let pool = core
225            .get_mut(&self.key)
226            .expect("if the handle still exists, the inner pool must still exist");
227
228        pool.remove_mut(inner);
229    }
230}
231
232#[cfg(test)]
233mod tests {
234    use static_assertions::assert_not_impl_any;
235
236    use super::*;
237
238    assert_not_impl_any!(LocalBlindPooledMut<u32>: Send, Sync);
239
240    // We expect no destructor because we treat it as `Copy` in our own Drop::drop().
241    assert_not_impl_any!(RawPooledMut<()>: Drop);
242}