Struct sharded_slab::pool::OwnedRefMut
source · pub struct OwnedRefMut<T, C = DefaultConfig>where
T: Clear + Default,
C: Config,{ /* private fields */ }
Expand description
An owned guard that allows exclusive, mutable access to an object in a pool.
An OwnedRefMut<T>
functions more or less identically to an owned
Box<T>
: it can be passed to functions, stored in structure fields, and
borrowed mutably or immutably, and can be owned for arbitrary lifetimes.
The difference is that, unlike a Box<T>
, the memory allocation for the
T
lives in the Pool
; when an OwnedRefMut
is created, it may reuse
memory that was allocated for a previous pooled object that has been
cleared. Additionally, the OwnedRefMut
may be downgraded to an
OwnedRef
which may be shared freely, essentially turning the Box
into an Arc
.
This is returned by Pool::create_owned
.
While the guard exists, it indicates to the pool that the item the guard references is currently being accessed. If the item is removed from the pool while the guard exists, theremoval will be deferred until all guards are dropped.
Unlike RefMut
, which borrows the pool, an OwnedRefMut
clones the Arc
around the pool. Therefore, it keeps the pool from being dropped until all
such guards have been dropped. This means that an OwnedRefMut
may be held for
an arbitrary lifetime.
Examples
use std::sync::Arc;
let pool: Arc<Pool<String>> = Arc::new(Pool::new());
// Create a new pooled item, returning an owned guard that allows mutable
// access to the new item.
let mut item = pool.clone().create_owned().unwrap();
// Return a key that allows indexing the created item once the guard
// has been dropped.
let key = item.key();
// Mutate the item.
item.push_str("Hello");
// Drop the guard, releasing mutable access to the new item.
drop(item);
/// Other threads may now (immutably) access the item using the returned key.
thread::spawn(move || {
assert_eq!(pool.get(key).unwrap(), String::from("Hello"));
}).join().unwrap();
use std::sync::Arc;
let pool: Arc<Pool<String>> = Arc::new(Pool::new());
// Create a new item, returning an owned, mutable guard.
let mut value = pool.clone().create_owned().unwrap();
// Now, the original `Arc` clone of the pool may be dropped, but the
// returned `OwnedRefMut` can still access the value.
drop(pool);
value.push_str("hello world");
assert_eq!(value, String::from("hello world"));
Unlike RefMut
, an OwnedRefMut
may be stored in a struct which must live
for the 'static
lifetime:
use sharded_slab::pool::OwnedRefMut;
use std::sync::Arc;
pub struct MyStruct {
pool_ref: OwnedRefMut<String>,
// ... other fields ...
}
// Suppose this is some arbitrary function which requires a value that
// lives for the 'static lifetime...
fn function_requiring_static<T: 'static>(t: &T) {
// ... do something extremely important and interesting ...
}
let pool: Arc<Pool<String>> = Arc::new(Pool::new());
// Create a new item, returning a mutable owned reference.
let pool_ref = pool.clone().create_owned().unwrap();
let my_struct = MyStruct {
pool_ref,
// ...
};
// We can use `my_struct` anywhere where it is required to have the
// `'static` lifetime:
function_requiring_static(&my_struct);
OwnedRefMut
s may be sent between threads:
use std::{thread, sync::Arc};
let pool: Arc<Pool<String>> = Arc::new(Pool::new());
let mut value = pool.clone().create_owned().unwrap();
let key = value.key();
thread::spawn(move || {
value.push_str("hello world");
// ...
}).join().unwrap();
// Once the `OwnedRefMut` has been dropped by the other thread, we may
// now access the value immutably on this thread.
assert_eq!(pool.get(key).unwrap(), String::from("hello world"));
Downgrading from a mutable to an immutable reference:
use std::{thread, sync::Arc};
let pool: Arc<Pool<String>> = Arc::new(Pool::new());
let mut value = pool.clone().create_owned().unwrap();
let key = value.key();
value.push_str("hello world");
// Downgrade the mutable owned ref to an immutable owned ref.
let value = value.downgrade();
// Once the `OwnedRefMut` has been downgraded, other threads may
// immutably access the pooled value:
thread::spawn(move || {
assert_eq!(pool.get(key).unwrap(), String::from("hello world"));
}).join().unwrap();
// This thread can still access the pooled value through the
// immutable owned ref:
assert_eq!(value, String::from("hello world"));
Implementations§
source§impl<T, C> OwnedRefMut<T, C>where
T: Clear + Default,
C: Config,
impl<T, C> OwnedRefMut<T, C>where
T: Clear + Default,
C: Config,
sourcepub fn downgrade(self) -> OwnedRef<T, C>
pub fn downgrade(self) -> OwnedRef<T, C>
Downgrades the owned mutable guard to an owned immutable guard, allowing access to the pooled value from other threads.
Examples
let pool = Arc::new(Pool::<String>::new());
let mut guard_mut = pool.clone().create_owned().unwrap();
let key = guard_mut.key();
guard_mut.push_str("Hello");
// The pooled string is currently borrowed mutably, so other threads
// may not access it.
let pool2 = pool.clone();
thread::spawn(move || {
assert!(pool2.get(key).is_none())
}).join().unwrap();
// Downgrade the guard to an immutable reference.
let guard = guard_mut.downgrade();
// Now, other threads may also access the pooled value.
let pool2 = pool.clone();
thread::spawn(move || {
let guard = pool2.get(key)
.expect("the item may now be referenced by other threads");
assert_eq!(guard, String::from("Hello"));
}).join().unwrap();
// We can still access the value immutably through the downgraded guard.
assert_eq!(guard, String::from("Hello"));