PooledMut

Struct PooledMut 

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

Exclusive handle to a pooled item that prevents double-use through the type system.

PooledMut<T> provides exclusive ownership of an item stored in an OpaquePool and ensures that each handle can only be used once. Unlike Pooled<T>, this type does not implement Copy or Clone, making it impossible to accidentally create multiple handles to the same pooled item or use a handle after it has been consumed.

This is the recommended handle type for most use cases as it provides stronger safety guarantees and enables safe removal operations without requiring unsafe code.

§Key Features

  • Exclusive ownership: Each handle represents unique access to one pooled item
  • Single-use guarantee: Cannot be copied, cloned, or reused after consumption
  • Safe removal: Removal methods consume the handle, preventing use-after-free
  • Direct value access: Implements std::ops::Deref and std::ops::DerefMut
  • Mutable access: Full read-write access to the stored value
  • Conversion to shared: Use into_shared() to enable copying
  • Pinning support: Safe std::pin::Pin access for both &T and &mut T
  • Type erasure: Use erase() to convert to PooledMut<()>
  • Pointer access: Raw pointer access via ptr() for advanced cases

§Safety Benefits

PooledMut<T> provides stronger compile-time guarantees than Pooled<T>:

  • No double-use: Cannot be copied or cloned, preventing accidental reuse
  • Safe removal: Pool removal methods consume the handle, making reuse impossible
  • Move semantics: Handle is moved/consumed by operations, enforcing single use
  • Type system enforcement: Rust’s ownership system prevents use-after-move errors

§Relationship with Pooled<T>

PooledMut<T> can be converted to Pooled<T> using into_shared() when you need to share access across multiple references. This conversion is one-way; you cannot convert back from Pooled<T> to PooledMut<T>.

§Examples

§Safe exclusive access and removal

use opaque_pool::OpaquePool;

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

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

// Direct access through Deref and DerefMut
assert_eq!(&*item, "Hello");
item.push_str(", World!");
assert_eq!(&*item, "Hello, World!");

// Safe removal - handle is consumed, preventing reuse
pool.remove_mut(item);
// item is now moved and cannot be used again!

§Converting to shared access

use opaque_pool::OpaquePool;

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

// SAFETY: u64 matches the layout used to create the pool
let exclusive = unsafe { pool.insert(42_u64) };

// Convert to shared handle for copying
let shared = exclusive.into_shared();
let shared_copy = shared; // Now can copy freely

assert_eq!(*shared_copy, 42);

// Removal now requires unsafe since multiple handles could exist
// SAFETY: No other copies of the handle will be used after this call
unsafe { pool.remove(&shared_copy) };

§Pinning support

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 item = unsafe { pool.insert("Pinned".to_string()) };

// Get pinned references safely
let pinned_ref: Pin<&String> = item.as_pin();
assert_eq!(&**pinned_ref, "Pinned");

pool.remove_mut(item);

§Thread Safety

This type has the same thread safety properties as Pooled<T>. It is thread-safe (Send + Sync) if and only if T implements Sync. When T is Sync, the handle can be moved between threads or shared between threads safely.

Implementations§

Source§

impl<T: ?Sized> PooledMut<T>

Source

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

Returns a pointer to the inserted value.

This provides access to 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 mut item = unsafe { pool.insert("Hello".to_string()) };

// Read data back using Deref.
assert_eq!(&*item, "Hello");

// Can also write to it using DerefMut.
item.push_str(", World!");
assert_eq!(&*item, "Hello, World!");
Source

pub fn into_shared(self) -> Pooled<T>

Converts this exclusive handle to a shared handle.

This allows multiple shared handles to exist to the same pooled item. The returned Pooled<T> handle can be copied and shared, but removal operations will require unsafe code again.

§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 item = unsafe { pool.insert("Test".to_string()) };

// Convert to shared handle.
let shared = item.into_shared();

// Can now copy the handle.
let shared_copy = shared;

// But removal requires unsafe again.
unsafe { pool.remove(&shared_copy) };
Source

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

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

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 item = unsafe { pool.insert("Test".to_string()) };

// Erase type information.
let erased = item.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.
pool.remove_mut(erased);
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()) };

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

pub fn as_pin_mut(&mut self) -> Pin<&mut T>

Returns a pinned mutable 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<&mut 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 mut handle = unsafe { pool.insert("hello".to_string()) };

let mut pinned: Pin<&mut String> = handle.as_pin_mut();
// Can use Pin methods or deref to &mut String

Trait Implementations§

Source§

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

Source§

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

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

impl<T: ?Sized> Deref for PooledMut<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.

§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()) };

// 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> DerefMut for PooledMut<T>

Source§

fn deref_mut(&mut self) -> &mut Self::Target

Provides direct mutable access to the value stored in the pool.

This allows the handle to be used as if it were a mutable reference to the stored value.

§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 mut string_handle = unsafe { pool.insert("hello".to_string()) };

// Mutate the string directly.
string_handle.push_str(" world");
assert_eq!(*string_handle, "hello world");
Source§

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

Source§

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

Auto Trait Implementations§

§

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

§

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

§

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

§

impl<T> UnwindSafe for PooledMut<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> 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, 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.