infinity_pool/handles/
raw.rs

1use std::fmt;
2use std::pin::Pin;
3use std::ptr::NonNull;
4
5use crate::{RawPooledMut, SlabHandle};
6
7/// A shared handle to an object in an object pool.
8#[doc = include_str!("../../doc/snippets/raw_handle_implications.md")]
9#[doc = include_str!("../../doc/snippets/shared_handle_implications.md")]
10#[doc = include_str!("../../doc/snippets/shared_raw_handle_implications.md")]
11#[doc = include_str!("../../doc/snippets/nonlocal_handle_thread_safety.md")]
12pub struct RawPooled<T>
13where
14    // We support casting to trait objects, hence `?Sized`.
15    T: ?Sized,
16{
17    /// Index of the slab in the pool. Slabs are guaranteed to stay at the same index unless
18    /// the pool is shrunk (which can only happen when the affected slabs are empty, in which
19    /// case all existing handles are already invalidated).
20    slab_index: usize,
21
22    /// Handle to the object in the slab. This grants us access to the object's pointer
23    /// and allows us to operate on the object (e.g. to remove it or create a reference).
24    slab_handle: SlabHandle<T>,
25}
26
27impl<T: ?Sized> RawPooled<T> {
28    #[must_use]
29    pub(crate) fn new(slab_index: usize, slab_handle: SlabHandle<T>) -> Self {
30        Self {
31            slab_index,
32            slab_handle,
33        }
34    }
35
36    /// Get the index of the slab in the pool.
37    ///
38    /// This is used by the pool itself to identify the slab in which the object resides.
39    #[must_use]
40    pub(crate) fn slab_index(&self) -> usize {
41        self.slab_index
42    }
43
44    /// Get the slab handle for this pool handle.
45    ///
46    /// This is used by the pool itself to perform operations on the object in the slab.
47    #[must_use]
48    pub(crate) fn slab_handle(&self) -> SlabHandle<T> {
49        self.slab_handle
50    }
51
52    #[doc = include_str!("../../doc/snippets/handle_ptr.md")]
53    #[must_use]
54    #[inline]
55    pub fn ptr(&self) -> NonNull<T> {
56        self.slab_handle.ptr()
57    }
58
59    #[doc = include_str!("../../doc/snippets/handle_erase.md")]
60    #[must_use]
61    #[inline]
62    pub fn erase(self) -> RawPooled<()> {
63        RawPooled {
64            slab_index: self.slab_index,
65            slab_handle: self.slab_handle.erase(),
66        }
67    }
68
69    #[doc = include_str!("../../doc/snippets/raw_as_pin.md")]
70    #[must_use]
71    #[inline]
72    pub unsafe fn as_pin(&self) -> Pin<&T> {
73        // SAFETY: Forwarding safety guarantees from the caller.
74        let as_ref = unsafe { self.as_ref() };
75
76        // SAFETY: Pooled items are always pinned.
77        unsafe { Pin::new_unchecked(as_ref) }
78    }
79
80    #[doc = include_str!("../../doc/snippets/raw_as_ref.md")]
81    #[must_use]
82    #[inline]
83    pub unsafe fn as_ref(&self) -> &T {
84        // SAFETY: This is a unique handle, so we guarantee borrow safety
85        // of the target object by borrowing the handle itself. Pointer validity
86        // requires pool to be alive, which is a safety requirement of this function.
87        unsafe { self.ptr().as_ref() }
88    }
89
90    /// Casts this handle to reference the target as a trait object.
91    ///
92    /// This method is only intended for use by the [`define_pooled_dyn_cast!`] macro
93    /// for type-safe casting operations.
94    ///
95    /// # Safety
96    ///
97    /// The caller must guarantee that the provided closure's input and output references
98    /// point to the same object.
99    ///
100    /// The caller must guarantee that the pool will remain alive for the duration the returned
101    /// reference is used.
102    #[doc(hidden)]
103    #[must_use]
104    #[inline]
105    pub unsafe fn __private_cast_dyn_with_fn<U: ?Sized, F>(self, cast_fn: F) -> RawPooled<U>
106    where
107        F: FnOnce(&T) -> &U,
108    {
109        // SAFETY: Forwarding callback safety guarantees from the caller.
110        // We are a shared handle, so we always have the right to create
111        // shared references to the target of the handle, satisfying that requirement.
112        let new_handle = unsafe { self.slab_handle.cast_with(cast_fn) };
113
114        RawPooled {
115            slab_index: self.slab_index,
116            slab_handle: new_handle,
117        }
118    }
119}
120
121impl<T: ?Sized> Clone for RawPooled<T> {
122    #[inline]
123    fn clone(&self) -> Self {
124        *self
125    }
126}
127
128impl<T: ?Sized> Copy for RawPooled<T> {}
129
130impl<T: ?Sized> fmt::Debug for RawPooled<T> {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        f.debug_struct("RawPooled")
133            .field("slab_index", &self.slab_index)
134            .field("slab_handle", &self.slab_handle)
135            .finish()
136    }
137}
138
139impl<T: ?Sized> From<RawPooledMut<T>> for RawPooled<T> {
140    #[inline]
141    fn from(value: RawPooledMut<T>) -> Self {
142        value.into_shared()
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use std::cell::Cell;
149
150    use static_assertions::{assert_impl_all, assert_not_impl_any};
151
152    use super::*;
153
154    // u32 is Sync, so RawPooled<u32> should be Send (but not Sync).
155    assert_impl_all!(RawPooled<u32>: Send);
156    assert_not_impl_any!(RawPooled<u32>: Sync);
157
158    // Cell is Send but not Sync, so RawPooled<Cell> should be neither Send nor Sync.
159    assert_not_impl_any!(RawPooled<Cell<u32>>: Send, Sync);
160}