infinity_pool/handles/
local.rs

1use std::borrow::Borrow;
2use std::cell::RefCell;
3use std::fmt;
4use std::ops::Deref;
5use std::pin::Pin;
6use std::ptr::NonNull;
7use std::rc::Rc;
8
9use crate::{LocalPooledMut, RawOpaquePool, RawPooled, RawPooledMut};
10
11/// A shared single-threaded reference-counting handle for a pooled object.
12#[doc = include_str!("../../doc/snippets/ref_counted_handle_implications.md")]
13#[doc = include_str!("../../doc/snippets/shared_handle_implications.md")]
14///
15/// # Thread safety
16///
17/// This type is single-threaded.
18pub struct LocalPooled<T: ?Sized> {
19    inner: RawPooled<T>,
20    remover: Rc<Remover>,
21}
22
23impl<T: ?Sized> LocalPooled<T> {
24    #[must_use]
25    pub(crate) fn new(inner: RawPooledMut<T>, pool: Rc<RefCell<RawOpaquePool>>) -> Self {
26        let inner = inner.into_shared();
27
28        let remover = Remover {
29            handle: inner.erase(),
30            pool,
31        };
32
33        Self {
34            inner,
35            remover: Rc::new(remover),
36        }
37    }
38
39    #[doc = include_str!("../../doc/snippets/handle_ptr.md")]
40    #[must_use]
41    #[inline]
42    pub fn ptr(&self) -> NonNull<T> {
43        self.inner.ptr()
44    }
45
46    #[doc = include_str!("../../doc/snippets/handle_erase.md")]
47    #[must_use]
48    #[inline]
49    pub fn erase(self) -> LocalPooled<()> {
50        LocalPooled {
51            inner: self.inner.erase(),
52            remover: self.remover,
53        }
54    }
55
56    #[doc = include_str!("../../doc/snippets/ref_counted_as_pin.md")]
57    #[must_use]
58    #[inline]
59    pub fn as_pin(&self) -> Pin<&T> {
60        // SAFETY: Pooled items are always pinned.
61        unsafe { Pin::new_unchecked(self) }
62    }
63
64    /// Casts this handle to reference the target as a trait object.
65    ///
66    /// This method is only intended for use by the [`define_pooled_dyn_cast!`] macro
67    /// for type-safe casting operations.
68    ///
69    /// # Safety
70    ///
71    /// The caller must guarantee that the provided closure's input and output references
72    /// point to the same object.
73    #[doc(hidden)]
74    #[must_use]
75    #[inline]
76    pub unsafe fn __private_cast_dyn_with_fn<U: ?Sized, F>(self, cast_fn: F) -> LocalPooled<U>
77    where
78        F: FnOnce(&T) -> &U,
79    {
80        // SAFETY: Forwarding callback safety guarantees from the caller.
81        // We are a shared handle, so we always have the right to create
82        // shared references to the target of the handle, satisfying that requirement.
83        let new_inner = unsafe { self.inner.__private_cast_dyn_with_fn(cast_fn) };
84
85        LocalPooled {
86            inner: new_inner,
87            remover: self.remover,
88        }
89    }
90}
91
92impl<T: ?Sized> fmt::Debug for LocalPooled<T> {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        f.debug_struct("LocalPooled")
95            .field("inner", &self.inner)
96            .field("remover", &self.remover)
97            .finish()
98    }
99}
100
101impl<T: ?Sized> Deref for LocalPooled<T> {
102    type Target = T;
103
104    #[inline]
105    fn deref(&self) -> &Self::Target {
106        // SAFETY: This is a shared handle - the only references
107        // that can ever exist are shared references.
108        // We guarantee liveness by being a reference counted handle.
109        unsafe { self.ptr().as_ref() }
110    }
111}
112
113impl<T: ?Sized> Borrow<T> for LocalPooled<T> {
114    #[inline]
115    fn borrow(&self) -> &T {
116        self
117    }
118}
119
120impl<T: ?Sized> AsRef<T> for LocalPooled<T> {
121    #[inline]
122    fn as_ref(&self) -> &T {
123        self
124    }
125}
126
127impl<T: ?Sized> Clone for LocalPooled<T> {
128    #[inline]
129    fn clone(&self) -> Self {
130        Self {
131            inner: self.inner,
132            remover: Rc::clone(&self.remover),
133        }
134    }
135}
136
137impl<T: ?Sized> From<LocalPooledMut<T>> for LocalPooled<T> {
138    #[inline]
139    fn from(value: LocalPooledMut<T>) -> Self {
140        value.into_shared()
141    }
142}
143
144/// When dropped, removes an object from a pool.
145#[derive(Debug)]
146struct Remover {
147    handle: RawPooled<()>,
148    pool: Rc<RefCell<RawOpaquePool>>,
149}
150
151impl Drop for Remover {
152    fn drop(&mut self) {
153        let mut pool = self.pool.borrow_mut();
154
155        // SAFETY: The remover controls the shared object lifetime and is the only thing
156        // that can remove the item from the pool.
157        unsafe {
158            pool.remove(self.handle);
159        }
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use static_assertions::assert_not_impl_any;
166
167    use super::*;
168
169    assert_not_impl_any!(LocalPooled<u32>: Send, Sync);
170}