//! API is similar to [`futures::sync::BiLock`](https://docs.rs/futures/0.1.11/futures/sync/struct.BiLock.html)
//! However, it can be cloned into as many handles as desired.
//!
externcratefutures;
externcratecrossbeam;
usestd::ops::{Deref,DerefMut};
usestd::mem;
usestd::sync::Arc;
usestd::sync::atomic::{Ordering,AtomicBool};
usestd::cell::UnsafeCell;
usecrossbeam::sync::MsQueue;
usefutures::task::{current,Task};
usefutures::{Future,Poll,Async};
#[derive(Debug)]
structInner<T>{
wait_queue: MsQueue<Task>,
locked: AtomicBool,
data: UnsafeCell<T>
}
impl<T>DropforInner<T>{
fndrop(&mutself){
assert!(!self.locked.load(Ordering::SeqCst))
}
}
unsafeimpl<T: Send>SendforInner<T>{}
unsafeimpl<T: Send>SyncforInner<T>{}
/// A Mutex designed for use inside Futures. Works like `BiLock<T>` from the `futures` crate, but
/// with more than 2 handles.
///
/// **THIS IS NOT A GENRAL PURPOSE MUTEX! IF YOU CALL `poll_lock` OR `lock` OUTSIDE THE CONTEXT OF A TASK, IT WILL PANIC AND EAT YOUR LAUNDRY.**
///
/// This type provides a Mutex that will track tasks that are requesting the Mutex, and will unpark
/// them in the order they request the lock.
///
/// *As of now, there is no strong guarantee that a particular handle of the lock won't be starved. Hopefully the use of the queue will prevent this, but I haven't tried to test that.*
#[derive(Debug)]
pubstructMutex<T>{
inner: Arc<Inner<T>>
}
impl<T>Mutex<T>{
/// Create a new Mutex wrapping around a value `t`
pubfnnew(t: T)-> Mutex<T>{
letinner=Arc::new(Inner{
wait_queue: MsQueue::new(),
locked: AtomicBool::new(false),
data: UnsafeCell::new(t)
});
Mutex{
inner: inner
}
}
/// This will attempt a non-blocking lock on the mutex, returning `Async::NotReady` if it
/// can't be acquired.
///
/// This function will return immediatly with a `MutexGuard` if the lock was acquired
/// successfully. When it drops, the lock will be unlocked.
///
/// If it can't acquire the lock, it will schedule the current task to be unparked when it
/// might be able lock the mutex again.
///
/// # Panics
///
/// This function will panic if called outside the context of a future's task.