Pooled

Struct Pooled 

Source
pub struct Pooled<T: ?Sized> { /* private fields */ }
Expand description

Shared handle to a pooled item that allows multiple references to the same value.

Pooled<T> provides shared access to items stored in an OpaquePool and can be copied and cloned freely. This is the “shared reference” counterpart to crate::PooledMut<T>’s “exclusive ownership” model, enabling flexible access patterns for pooled data.

Multiple Pooled<T> handles can refer to the same stored value simultaneously, making this type ideal for scenarios where you need to share access to pooled data across different parts of your code.

§Key Features

  • Copyable handles: Implements Copy and Clone for easy duplication
  • Shared access: Multiple handles can reference the same pooled value
  • Direct value access: Implements std::ops::Deref for transparent access
  • Type safety: Generic parameter T provides compile-time type checking
  • Type erasure: Use erase() to convert to Pooled<()>
  • Pinning support: Safe std::pin::Pin access via as_pin()
  • Pointer access: Raw pointer access via ptr() for advanced use cases

§Relationship with PooledMut<T>

Pooled<T> handles are typically created by converting from crate::PooledMut<T> using into_shared(). While crate::PooledMut<T> provides exclusive ownership with safe removal, Pooled<T> trades some safety for flexibility by allowing multiple references to the same value.

§Safety Considerations

Unlike crate::PooledMut<T>, removing items via Pooled<T> requires unsafe code because the compiler cannot prevent use-after-free when multiple handles to the same value exist. The caller must ensure no other copies of the handle are used after removal.

§Examples

§Basic shared access

use opaque_pool::OpaquePool;

let mut pool = OpaquePool::builder().layout_of::<String>().build();

// SAFETY: String matches the layout used to create the pool
let exclusive = unsafe { pool.insert("Hello".to_string()) };

// Convert to shared handle for copying
let shared = exclusive.into_shared();
let shared_copy = shared; // Can copy freely
let shared_clone = shared.clone();

// All handles refer to the same value and support Deref
assert_eq!(&*shared_copy, "Hello");
assert_eq!(&*shared_clone, "Hello");
assert_eq!(shared_copy.len(), 5);

// Removal requires unsafe - caller ensures no other copies are used
// SAFETY: No other copies of the handle will be used after this call
unsafe { pool.remove(&shared_copy) };

§Type erasure and casting

use opaque_pool::OpaquePool;

let mut pool = OpaquePool::builder().layout_of::<String>().build();

// SAFETY: String matches the layout used to create the pool
let item = unsafe { pool.insert("Hello".to_string()) }.into_shared();

// Erase type information
let erased = item.erase();

// Both refer to the same value
// SAFETY: Both pointers are valid and point to the same String
let original_ptr = item.ptr().as_ptr() as *const ();
let erased_ptr = erased.ptr().as_ptr();
assert_eq!(original_ptr, erased_ptr);

// SAFETY: No other copies will be used after removal
unsafe { pool.remove(&erased) };

§Thread Safety

This type is thread-safe (Send + Sync) if and only if T implements Sync. When T is Sync, multiple threads can safely share handles to the same data. When T is not Sync, the handle cannot be moved between threads or shared between threads, preventing invalid access to non-thread-safe data.

Implementations§

Source§

impl<T: ?Sized> Pooled<T>

Source

pub fn ptr(&self) -> NonNull<T>

Returns a pointer to the inserted value.

This is the only way to access the value stored in the pool. The owner of the handle has exclusive access to the value and may both read and write and may create both & shared and &mut exclusive references to the item.

§Example
use std::alloc::Layout;

use opaque_pool::OpaquePool;

let mut pool = OpaquePool::builder().layout_of::<String>().build();

// SAFETY: String matches the layout used to create the pool.
let pooled = unsafe { pool.insert("Hello".to_string()) };

// Access data using Deref.
assert_eq!(&*pooled, "Hello");
Source

pub fn as_pin(&self) -> Pin<&T>

Returns a pinned reference to the value stored in the pool.

Since values in the pool are always pinned (they never move once inserted), this method provides safe access to Pin<&T> without requiring unsafe code.

§Example
use std::pin::Pin;

use opaque_pool::OpaquePool;

let mut pool = OpaquePool::builder().layout_of::<String>().build();

// SAFETY: String matches the layout used to create the pool.
let handle = unsafe { pool.insert("hello".to_string()) }.into_shared();

let pinned: Pin<&String> = handle.as_pin();
assert_eq!(pinned.len(), 5);
Source

pub fn erase(self) -> Pooled<()>

Erases the type information from this Pooled<T> handle, returning a Pooled<()>.

This is useful when you want to store handles of different types in the same collection or pass them to code that doesn’t need to know the specific type.

The handle remains functionally equivalent and can still be used to remove the item from the pool and drop it. The only change is the removal of the type information.

§Example
use std::alloc::Layout;

use opaque_pool::OpaquePool;

let mut pool = OpaquePool::builder().layout_of::<String>().build();

// SAFETY: String matches the layout used to create the pool.
let pooled = unsafe { pool.insert("Test".to_string()) }.into_shared();

// Erase type information.
let erased = pooled.erase();

// Cast back to original type for safe access.
// SAFETY: We know this contains a String.
let typed_ptr = erased.ptr().cast::<String>();
let value = unsafe { typed_ptr.as_ref() };
assert_eq!(value, "Test");

// Can still remove the item.
unsafe { pool.remove(&erased) };

Trait Implementations§

Source§

impl<T: ?Sized> Clone for Pooled<T>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: ?Sized> Debug for Pooled<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: ?Sized> Deref for Pooled<T>

Source§

fn deref(&self) -> &Self::Target

Provides direct access to the value stored in the pool.

This allows the handle to be used as if it were a reference to the stored value. Since Pooled<T> provides shared access, this returns a shared reference.

§Example
use opaque_pool::OpaquePool;

let mut pool = OpaquePool::builder().layout_of::<String>().build();

// SAFETY: String matches the layout used to create the pool.
let string_handle = unsafe { pool.insert("hello".to_string()) }.into_shared();

// Access string methods directly.
assert_eq!(string_handle.len(), 5);
assert!(string_handle.starts_with("he"));
Source§

type Target = T

The resulting type after dereferencing.
Source§

impl<T: ?Sized> Copy for Pooled<T>

Source§

impl<T: ?Sized + Sync> Send for Pooled<T>

Source§

impl<T: ?Sized + Sync> Sync for Pooled<T>

Auto Trait Implementations§

§

impl<T> Freeze for Pooled<T>
where T: ?Sized,

§

impl<T> RefUnwindSafe for Pooled<T>
where T: RefUnwindSafe + ?Sized,

§

impl<T> Unpin for Pooled<T>
where T: ?Sized,

§

impl<T> UnwindSafe for Pooled<T>
where T: RefUnwindSafe + ?Sized,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.