Files
iris/core/src/util/handle.rs

228 lines
5.6 KiB
Rust

//! A helper type for Arc<Mutex<T>>
//! Currently there are mut versions (of Ref stuff) which don't do anything different under the hood,
//! leaving them in for now in case I decide RwLock is a desired feature
use std::{
marker::Unsize,
ops::{CoerceUnsized, Deref, DerefMut},
sync::{Arc, MappedMutexGuard, Mutex, MutexGuard, Weak},
};
pub struct Handle<T: ?Sized>(Arc<Mutex<T>>);
pub struct WeakHandle<T: ?Sized>(Weak<Mutex<T>>);
pub type Ref<'a, T> = MutexGuard<'a, T>;
pub type RefMut<'a, T> = MutexGuard<'a, T>;
pub type RefMap<'a, T> = MappedMutexGuard<'a, T>;
pub type RefMapMut<'a, T> = MappedMutexGuard<'a, T>;
impl<T: ?Sized> Handle<T> {
pub fn get(&self) -> Ref<'_, T> {
self.0.lock().unwrap()
}
pub fn get_mut(&self) -> RefMut<'_, T> {
self.0.lock().unwrap()
}
pub fn get_take<'a>(self) -> RefGuard<'a, T> {
let handle = self;
RefGuard {
guard: unsafe {
std::mem::transmute::<MutexGuard<'_, T>, MutexGuard<'_, T>>(
handle.0.lock().unwrap(),
)
},
handle,
}
}
pub fn get_take_mut<'a>(self) -> RefGuardMut<'a, T> {
let handle = self;
RefGuardMut {
guard: unsafe {
std::mem::transmute::<MutexGuard<'_, T>, MutexGuard<'_, T>>(
handle.0.lock().unwrap(),
)
},
handle,
}
}
pub fn refs(&self) -> usize {
Arc::strong_count(&self.0)
}
pub fn weak(&self) -> WeakHandle<T> {
WeakHandle(Arc::downgrade(&self.0))
}
/// # Safety
/// you must guarantee the type outside
/// ideally you check the typeid, but this is often used
/// when the trait object is wrapped one or more times
/// and you'd have to implement each one individually
pub unsafe fn downcast<U: 'static>(self) -> Handle<U>
where
T: 'static,
{
let raw: *const Mutex<T> = Arc::into_raw(self.0);
let raw: *const Mutex<U> = raw.cast();
Handle(unsafe { Arc::from_raw(raw) })
}
}
impl<T: ?Sized> WeakHandle<T> {
pub fn strong(&self) -> Option<Handle<T>> {
Some(Handle(self.0.upgrade()?))
}
pub fn dropped(&self) -> bool {
self.0.strong_count() == 0
}
/// # Safety
/// you must guarantee the type outside
pub unsafe fn downcast<U: 'static>(self) -> WeakHandle<U>
where
T: 'static,
{
let raw: *const Mutex<T> = self.0.into_raw();
let raw: *const Mutex<U> = raw.cast();
WeakHandle(unsafe { Weak::from_raw(raw) })
}
}
impl<T: ?Sized> Clone for Handle<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: ?Sized> Clone for WeakHandle<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: Default> Default for Handle<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<T> From<T> for Handle<T> {
fn from(value: T) -> Self {
Self(Arc::new(Mutex::new(value)))
}
}
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Handle<U>> for Handle<T> {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<WeakHandle<U>> for WeakHandle<T> {}
// yucky
// TODO: is drop order important here?
// something stupid could happen that I don't know about
// if handle is dropped before guard
pub struct RefGuard<'a, T: ?Sized> {
guard: MutexGuard<'a, T>,
handle: Handle<T>,
}
pub struct RefGuardMut<'a, T: ?Sized> {
guard: MutexGuard<'a, T>,
handle: Handle<T>,
}
pub struct MappedRefGuard<'a, T: ?Sized, U> {
guard: MappedMutexGuard<'a, U>,
handle: Handle<T>,
}
pub struct MappedRefGuardMut<'a, T: ?Sized, U> {
guard: MappedMutexGuard<'a, U>,
handle: Handle<T>,
}
impl<'a, T: ?Sized> RefGuard<'a, T> {
pub fn map<U>(s: Self, f: impl FnOnce(&mut T) -> &mut U) -> MappedRefGuard<'a, T, U> {
MappedRefGuard {
guard: MutexGuard::map(s.guard, f),
handle: s.handle,
}
}
}
impl<'a, T: ?Sized> RefGuardMut<'a, T> {
pub fn map<U>(s: Self, f: impl FnOnce(&mut T) -> &mut U) -> MappedRefGuardMut<'a, T, U> {
MappedRefGuardMut {
guard: MutexGuard::map(s.guard, f),
handle: s.handle,
}
}
}
impl<'a, T: ?Sized, U> MappedRefGuard<'a, T, U> {
pub fn map<U2>(s: Self, f: impl FnOnce(&mut U) -> &mut U2) -> MappedRefGuard<'a, T, U2> {
MappedRefGuard {
guard: MappedMutexGuard::map(s.guard, f),
handle: s.handle,
}
}
}
impl<'a, T: ?Sized, U> MappedRefGuardMut<'a, T, U> {
pub fn map<U2>(s: Self, f: impl FnOnce(&mut U) -> &mut U2) -> MappedRefGuardMut<'a, T, U2> {
MappedRefGuardMut {
guard: MappedMutexGuard::map(s.guard, f),
handle: s.handle,
}
}
}
impl<T: ?Sized> Deref for RefGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.guard
}
}
impl<T: ?Sized> Deref for RefGuardMut<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.guard
}
}
impl<T: ?Sized> DerefMut for RefGuardMut<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.guard
}
}
impl<T: ?Sized, U> Deref for MappedRefGuard<'_, T, U> {
type Target = U;
fn deref(&self) -> &Self::Target {
&self.guard
}
}
impl<T: ?Sized, U> Deref for MappedRefGuardMut<'_, T, U> {
type Target = U;
fn deref(&self) -> &Self::Target {
&self.guard
}
}
impl<T: ?Sized, U> DerefMut for MappedRefGuardMut<'_, T, U> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.guard
}
}