use std::ops::Deref;
use std::ops::DerefMut;
use std::rc;
use std::sync;
pub struct ArcRwLockReadGuardian<T: ?Sized + 'static> {
_handle: sync::Arc<sync::RwLock<T>>,
inner: Option<sync::RwLockReadGuard<'static, T>>,
}
pub struct ArcRwLockWriteGuardian<T: ?Sized + 'static> {
_handle: sync::Arc<sync::RwLock<T>>,
inner: Option<sync::RwLockWriteGuard<'static, T>>,
}
pub struct ArcMutexGuardian<T: ?Sized + 'static> {
_handle: sync::Arc<sync::Mutex<T>>,
inner: Option<sync::MutexGuard<'static, T>>,
}
pub struct RcRwLockReadGuardian<T: ?Sized + 'static> {
_handle: rc::Rc<sync::RwLock<T>>,
inner: Option<sync::RwLockReadGuard<'static, T>>,
}
pub struct RcRwLockWriteGuardian<T: ?Sized + 'static> {
_handle: rc::Rc<sync::RwLock<T>>,
inner: Option<sync::RwLockWriteGuard<'static, T>>,
}
pub struct RcMutexGuardian<T: ?Sized + 'static> {
_handle: rc::Rc<sync::Mutex<T>>,
inner: Option<sync::MutexGuard<'static, T>>,
}
impl<T: ?Sized> Deref for ArcRwLockReadGuardian<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner.as_ref().expect("inner is None only in drop")
}
}
impl<T: ?Sized> Deref for ArcRwLockWriteGuardian<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner.as_ref().expect("inner is None only in drop")
}
}
impl<T: ?Sized> Deref for ArcMutexGuardian<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner.as_ref().expect("inner is None only in drop")
}
}
impl<T: ?Sized> Deref for RcRwLockReadGuardian<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner.as_ref().expect("inner is None only in drop")
}
}
impl<T: ?Sized> Deref for RcRwLockWriteGuardian<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner.as_ref().expect("inner is None only in drop")
}
}
impl<T: ?Sized> Deref for RcMutexGuardian<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner.as_ref().expect("inner is None only in drop")
}
}
impl<T: ?Sized> DerefMut for ArcRwLockWriteGuardian<T> {
fn deref_mut(&mut self) -> &mut T {
self.inner.as_mut().expect("inner is None only in drop")
}
}
impl<T: ?Sized> DerefMut for RcRwLockWriteGuardian<T> {
fn deref_mut(&mut self) -> &mut T {
self.inner.as_mut().expect("inner is None only in drop")
}
}
impl<T: ?Sized> DerefMut for ArcMutexGuardian<T> {
fn deref_mut(&mut self) -> &mut T {
self.inner.as_mut().expect("inner is None only in drop")
}
}
impl<T: ?Sized> DerefMut for RcMutexGuardian<T> {
fn deref_mut(&mut self) -> &mut T {
self.inner.as_mut().expect("inner is None only in drop")
}
}
impl<T: ?Sized> From<sync::Arc<sync::RwLock<T>>> for ArcRwLockReadGuardian<T> {
fn from(handle: sync::Arc<sync::RwLock<T>>) -> Self {
ArcRwLockReadGuardian::take(handle).unwrap()
}
}
impl<T: ?Sized> From<sync::Arc<sync::RwLock<T>>> for ArcRwLockWriteGuardian<T> {
fn from(handle: sync::Arc<sync::RwLock<T>>) -> Self {
ArcRwLockWriteGuardian::take(handle).unwrap()
}
}
impl<T: ?Sized> From<sync::Arc<sync::Mutex<T>>> for ArcMutexGuardian<T> {
fn from(handle: sync::Arc<sync::Mutex<T>>) -> Self {
ArcMutexGuardian::take(handle).unwrap()
}
}
impl<T: ?Sized> From<rc::Rc<sync::RwLock<T>>> for RcRwLockReadGuardian<T> {
fn from(handle: rc::Rc<sync::RwLock<T>>) -> Self {
RcRwLockReadGuardian::take(handle).unwrap()
}
}
impl<T: ?Sized> From<rc::Rc<sync::RwLock<T>>> for RcRwLockWriteGuardian<T> {
fn from(handle: rc::Rc<sync::RwLock<T>>) -> Self {
RcRwLockWriteGuardian::take(handle).unwrap()
}
}
impl<T: ?Sized> From<rc::Rc<sync::Mutex<T>>> for RcMutexGuardian<T> {
fn from(handle: rc::Rc<sync::Mutex<T>>) -> Self {
RcMutexGuardian::take(handle).unwrap()
}
}
unsafe fn make_static<T: ?Sized>(r: &T) -> &'static T {
&*(r as *const T)
}
macro_rules! take {
( $handle: ident, $guard:ty, $guardian:ident, $lfunc:ident ) => {{
let lock: sync::LockResult<$guard> = unsafe { make_static(&$handle).$lfunc() };
match lock {
Ok(guard) => Ok($guardian {
_handle: $handle,
inner: Some(guard),
}),
Err(guard) => Err(sync::PoisonError::new($guardian {
_handle: $handle,
inner: Some(guard.into_inner()),
})),
}
}};
}
macro_rules! try_take {
( $handle: ident, $guard:ty, $guardian:ident, $lfunc:ident ) => {{
use std::sync::TryLockError::{Poisoned, WouldBlock};
let lock: sync::TryLockResult<$guard> = unsafe { make_static(&$handle).$lfunc() };
match lock {
Ok(guard) => Some(Ok($guardian {
_handle: $handle,
inner: Some(guard),
})),
Err(WouldBlock) => None,
Err(Poisoned(guard)) => Some(Err(sync::PoisonError::new($guardian {
_handle: $handle,
inner: Some(guard.into_inner()),
}))),
}
}};
}
impl<T: ?Sized> ArcRwLockReadGuardian<T> {
pub fn take(handle: sync::Arc<sync::RwLock<T>>) -> sync::LockResult<ArcRwLockReadGuardian<T>> {
take!(
handle,
sync::RwLockReadGuard<'static, T>,
ArcRwLockReadGuardian,
read
)
}
pub fn try_take(
handle: sync::Arc<sync::RwLock<T>>,
) -> Option<sync::LockResult<ArcRwLockReadGuardian<T>>> {
try_take!(
handle,
sync::RwLockReadGuard<'static, T>,
ArcRwLockReadGuardian,
try_read
)
}
}
impl<T: ?Sized> ArcRwLockWriteGuardian<T> {
pub fn take(handle: sync::Arc<sync::RwLock<T>>) -> sync::LockResult<ArcRwLockWriteGuardian<T>> {
take!(
handle,
sync::RwLockWriteGuard<'static, T>,
ArcRwLockWriteGuardian,
write
)
}
pub fn try_take(
handle: sync::Arc<sync::RwLock<T>>,
) -> Option<sync::LockResult<ArcRwLockWriteGuardian<T>>> {
try_take!(
handle,
sync::RwLockWriteGuard<'static, T>,
ArcRwLockWriteGuardian,
try_write
)
}
}
impl<T: ?Sized> ArcMutexGuardian<T> {
pub fn take(handle: sync::Arc<sync::Mutex<T>>) -> sync::LockResult<ArcMutexGuardian<T>> {
take!(handle, sync::MutexGuard<'static, T>, ArcMutexGuardian, lock)
}
pub fn try_take(
handle: sync::Arc<sync::Mutex<T>>,
) -> Option<sync::LockResult<ArcMutexGuardian<T>>> {
try_take!(
handle,
sync::MutexGuard<'static, T>,
ArcMutexGuardian,
try_lock
)
}
}
impl<T: ?Sized> RcRwLockReadGuardian<T> {
pub fn take(handle: rc::Rc<sync::RwLock<T>>) -> sync::LockResult<RcRwLockReadGuardian<T>> {
take!(
handle,
sync::RwLockReadGuard<'static, T>,
RcRwLockReadGuardian,
read
)
}
pub fn try_take(
handle: rc::Rc<sync::RwLock<T>>,
) -> Option<sync::LockResult<RcRwLockReadGuardian<T>>> {
try_take!(
handle,
sync::RwLockReadGuard<'static, T>,
RcRwLockReadGuardian,
try_read
)
}
}
impl<T: ?Sized> RcRwLockWriteGuardian<T> {
pub fn take(handle: rc::Rc<sync::RwLock<T>>) -> sync::LockResult<RcRwLockWriteGuardian<T>> {
take!(
handle,
sync::RwLockWriteGuard<'static, T>,
RcRwLockWriteGuardian,
write
)
}
pub fn try_take(
handle: rc::Rc<sync::RwLock<T>>,
) -> Option<sync::LockResult<RcRwLockWriteGuardian<T>>> {
try_take!(
handle,
sync::RwLockWriteGuard<'static, T>,
RcRwLockWriteGuardian,
try_write
)
}
}
impl<T: ?Sized> RcMutexGuardian<T> {
pub fn take(handle: rc::Rc<sync::Mutex<T>>) -> sync::LockResult<RcMutexGuardian<T>> {
take!(handle, sync::MutexGuard<'static, T>, RcMutexGuardian, lock)
}
pub fn try_take(
handle: rc::Rc<sync::Mutex<T>>,
) -> Option<sync::LockResult<RcMutexGuardian<T>>> {
try_take!(
handle,
sync::MutexGuard<'static, T>,
RcMutexGuardian,
try_lock
)
}
}
impl<T: ?Sized> Drop for ArcRwLockReadGuardian<T> {
fn drop(&mut self) {
self.inner.take();
}
}
impl<T: ?Sized> Drop for ArcRwLockWriteGuardian<T> {
fn drop(&mut self) {
self.inner.take();
}
}
impl<T: ?Sized> Drop for ArcMutexGuardian<T> {
fn drop(&mut self) {
self.inner.take();
}
}
impl<T: ?Sized> Drop for RcRwLockReadGuardian<T> {
fn drop(&mut self) {
self.inner.take();
}
}
impl<T: ?Sized> Drop for RcRwLockWriteGuardian<T> {
fn drop(&mut self) {
self.inner.take();
}
}
impl<T: ?Sized> Drop for RcMutexGuardian<T> {
fn drop(&mut self) {
self.inner.take();
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::rc;
use std::sync;
#[test]
fn arc_rw_read() {
let base = sync::Arc::new(sync::RwLock::new(true));
let x2 = {
let x1 = base.read().unwrap();
let x2 = ArcRwLockReadGuardian::take(base.clone()).unwrap();
assert_eq!(&*x1, &*x2);
drop(x1);
assert!(base.try_write().is_err(), "guardian holds read lock");
x2
};
{
let x1 = base.read().unwrap();
let x2_ = x2;
assert_eq!(&*x1, &*x2_);
drop(x1);
assert!(base.try_write().is_err(), "guardian still holds read lock");
drop(x2_);
assert!(base.try_write().is_ok(), "guardian drops read lock");
}
let x = ArcRwLockReadGuardian::take(base).unwrap();
assert_eq!(&*x, &true);
}
#[test]
fn arc_rw_write() {
let base = sync::Arc::new(sync::RwLock::new(true));
let mut x = ArcRwLockWriteGuardian::take(base.clone()).unwrap();
assert_eq!(&*x, &true);
*x = false;
assert_eq!(&*x, &false);
assert!(base.try_read().is_err(), "guardian holds write lock");
let x_ = x;
assert_eq!(&*x_, &false);
assert!(base.try_read().is_err(), "guardian still holds write lock");
drop(x_);
assert!(base.try_read().is_ok(), "guardian drops write lock");
let x = ArcRwLockWriteGuardian::take(base).unwrap();
assert_eq!(&*x, &false);
}
#[test]
fn arc_rw_try() {
let base = sync::Arc::new(sync::RwLock::new(true));
let mut x = ArcRwLockWriteGuardian::try_take(base.clone())
.unwrap()
.unwrap();
assert_eq!(&*x, &true);
*x = false;
assert_eq!(&*x, &false);
assert!(base.try_read().is_err(), "guardian holds write lock");
let x_ = x;
assert_eq!(&*x_, &false);
assert!(base.try_read().is_err(), "guardian still holds write lock");
assert!(ArcRwLockWriteGuardian::try_take(base.clone()).is_none());
assert!(ArcRwLockReadGuardian::try_take(base.clone()).is_none());
drop(x_);
assert!(base.try_read().is_ok(), "guardian drops write lock");
let x = ArcRwLockWriteGuardian::take(base).unwrap();
assert_eq!(&*x, &false);
}
#[test]
fn arc_mu() {
let base = sync::Arc::new(sync::Mutex::new(true));
let mut x = ArcMutexGuardian::take(base.clone()).unwrap();
assert_eq!(&*x, &true);
*x = false;
assert_eq!(&*x, &false);
assert!(base.try_lock().is_err(), "guardian holds lock");
let x_ = x;
assert_eq!(&*x_, &false);
assert!(base.try_lock().is_err(), "guardian still holds lock");
drop(x_);
assert!(base.try_lock().is_ok(), "guardian drops lock");
let x = ArcMutexGuardian::take(base).unwrap();
assert_eq!(&*x, &false);
}
#[test]
fn arc_mu_try() {
let base = sync::Arc::new(sync::Mutex::new(true));
let mut x = ArcMutexGuardian::try_take(base.clone()).unwrap().unwrap();
assert_eq!(&*x, &true);
*x = false;
assert_eq!(&*x, &false);
assert!(base.try_lock().is_err(), "guardian holds lock");
let x_ = x;
assert_eq!(&*x_, &false);
assert!(base.try_lock().is_err(), "guardian still holds lock");
assert!(ArcMutexGuardian::try_take(base.clone()).is_none());
drop(x_);
assert!(base.try_lock().is_ok(), "guardian drops lock");
let x = ArcMutexGuardian::take(base).unwrap();
assert_eq!(&*x, &false);
}
#[test]
fn rc_rw_read() {
let base = rc::Rc::new(sync::RwLock::new(true));
let x2 = {
let x1 = base.read().unwrap();
let x2 = RcRwLockReadGuardian::take(base.clone()).unwrap();
assert_eq!(&*x1, &*x2);
drop(x1);
assert!(base.try_write().is_err(), "guardian holds read lock");
x2
};
{
let x1 = base.read().unwrap();
let x2_ = x2;
assert_eq!(&*x1, &*x2_);
drop(x1);
assert!(base.try_write().is_err(), "guardian still holds read lock");
drop(x2_);
assert!(base.try_write().is_ok(), "guardian drops read lock");
}
let x = RcRwLockReadGuardian::take(base).unwrap();
assert_eq!(&*x, &true);
}
#[test]
fn rc_rw_write() {
let base = rc::Rc::new(sync::RwLock::new(true));
let mut x = RcRwLockWriteGuardian::take(base.clone()).unwrap();
assert_eq!(&*x, &true);
*x = false;
assert_eq!(&*x, &false);
assert!(base.try_read().is_err(), "guardian holds write lock");
let x_ = x;
assert_eq!(&*x_, &false);
assert!(base.try_read().is_err(), "guardian still holds write lock");
drop(x_);
assert!(base.try_read().is_ok(), "guardian drops write lock");
let x = RcRwLockWriteGuardian::take(base).unwrap();
assert_eq!(&*x, &false);
}
#[test]
fn rc_rw_try() {
let base = rc::Rc::new(sync::RwLock::new(true));
let mut x = RcRwLockWriteGuardian::try_take(base.clone())
.unwrap()
.unwrap();
assert_eq!(&*x, &true);
*x = false;
assert_eq!(&*x, &false);
assert!(base.try_read().is_err(), "guardian holds write lock");
let x_ = x;
assert_eq!(&*x_, &false);
assert!(base.try_read().is_err(), "guardian still holds write lock");
assert!(RcRwLockWriteGuardian::try_take(base.clone()).is_none());
assert!(RcRwLockReadGuardian::try_take(base.clone()).is_none());
drop(x_);
assert!(base.try_read().is_ok(), "guardian drops write lock");
let x = RcRwLockWriteGuardian::take(base).unwrap();
assert_eq!(&*x, &false);
}
#[test]
fn rc_mu() {
let base = rc::Rc::new(sync::Mutex::new(true));
let mut x = RcMutexGuardian::take(base.clone()).unwrap();
assert_eq!(&*x, &true);
*x = false;
assert_eq!(&*x, &false);
assert!(base.try_lock().is_err(), "guardian holds lock");
let x_ = x;
assert_eq!(&*x_, &false);
assert!(base.try_lock().is_err(), "guardian still holds lock");
drop(x_);
assert!(base.try_lock().is_ok(), "guardian drops lock");
let x = RcMutexGuardian::take(base).unwrap();
assert_eq!(&*x, &false);
}
#[test]
fn rc_mu_try() {
let base = rc::Rc::new(sync::Mutex::new(true));
let mut x = RcMutexGuardian::take(base.clone()).unwrap();
assert_eq!(&*x, &true);
*x = false;
assert_eq!(&*x, &false);
assert!(base.try_lock().is_err(), "guardian holds lock");
let x_ = x;
assert_eq!(&*x_, &false);
assert!(base.try_lock().is_err(), "guardian still holds lock");
assert!(RcMutexGuardian::try_take(base.clone()).is_none());
drop(x_);
assert!(base.try_lock().is_ok(), "guardian drops lock");
let x = RcMutexGuardian::take(base).unwrap();
assert_eq!(&*x, &false);
}
}