use std::{ptr, mem};
use std::sync::Arc;
use std::sync::atomic::{AtomicPtr, Ordering};
#[cfg(feature = "futures")]
use futures::{Async, Poll, Future, IntoFuture};
#[cfg(feature = "futures")]
use futures::task::AtomicTask;
pub use super::SendError;
#[derive(Debug)]
pub enum ReceiveError<T> {
Empty(Receiver<T>),
Disconnected,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct SenderDisconnectedError;
pub fn channel<T: Send + Sync>() -> (Sender<T>, Receiver<T>) {
let inner = Arc::new(Inner::new());
(Sender { inner: inner.clone() }, Receiver { inner: inner })
}
#[derive(Debug)]
pub struct Sender<T> {
inner: Arc<Inner<T>>,
}
impl<T> Sender<T> {
pub fn send(self, value: T) -> Result<(), SendError<T>> {
if self.is_disconnected() {
Err(SendError(value))
} else {
let value_ptr = Box::into_raw(Box::new(value));
self.inner.value.store(value_ptr, Ordering::Relaxed);
Ok(())
}
}
fn is_disconnected(&self) -> bool {
Arc::strong_count(&self.inner) == 1
}
}
#[cfg(feature = "futures")]
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
self.inner.task.notify();
}
}
#[derive(Debug)]
pub struct Receiver<T> {
inner: Arc<Inner<T>>,
}
impl<T> Receiver<T> {
pub fn try_receive(self) -> Result<T, ReceiveError<T>> {
let value_ptr = self.inner.value.swap(ptr::null_mut(), Ordering::Relaxed);
if !value_ptr.is_null() {
let value = unsafe { Box::from_raw(value_ptr) };
Ok(*value)
} else if self.is_disconnected() {
Err(ReceiveError::Disconnected)
} else {
Err(ReceiveError::Empty(self))
}
}
fn is_disconnected(&self) -> bool {
Arc::strong_count(&self.inner) == 1
}
}
#[cfg(feature = "futures")]
impl<T> IntoFuture for Receiver<T> {
type Future = ReceiveFuture<T>;
type Item = T;
type Error = SenderDisconnectedError;
fn into_future(self) -> ReceiveFuture<T> {
ReceiveFuture {
receiver: Some(self),
}
}
}
#[cfg(feature = "futures")]
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct ReceiveFuture<T> {
receiver: Option<Receiver<T>>,
}
#[cfg(feature = "futures")]
impl<T> Future for ReceiveFuture<T> {
type Item = T;
type Error = SenderDisconnectedError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
use self::ReceiveError::*;
match self.receiver.take() {
Some(receiver) => {
receiver.inner.task.register();
match receiver.try_receive() {
Ok(value) => Ok(Async::Ready(value)),
Err(Empty(receiver)) => {
self.receiver = Some(receiver);
Ok(Async::NotReady)
},
Err(Disconnected) => Err(SenderDisconnectedError),
}
},
None => panic!("tried to poll ReceiveFuture after completion"),
}
}
}
#[derive(Debug)]
struct Inner<T> {
value: AtomicPtr<T>,
#[cfg(feature = "futures")]
task: AtomicTask,
}
impl<T> Inner<T> {
fn new() -> Inner<T> {
Inner {
value: AtomicPtr::default(),
#[cfg(feature = "futures")]
task: AtomicTask::new()
}
}
}
impl<T> Drop for Inner<T> {
fn drop(&mut self) {
let value_ptr = self.value.load(Ordering::Relaxed);
if !value_ptr.is_null() {
mem::drop(unsafe { Box::from_raw(value_ptr) })
}
}
}