use super::chan; use futures::{Poll, Sink, StartSend, Stream}; use std::fmt; /// Send values to the associated `Receiver`. /// /// Instances are created by the [`channel`](fn.channel.html) function. pub struct Sender { chan: chan::Tx, } impl Clone for Sender { fn clone(&self) -> Self { Sender { chan: self.chan.clone() } } } impl fmt::Debug for Sender { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Sender") .field("chan", &self.chan) .finish() } } /// Receive values from the associated `Sender`. /// /// Instances are created by the [`channel`](fn.channel.html) function. pub struct Receiver { /// The channel receiver chan: chan::Rx, } impl fmt::Debug for Receiver { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Receiver") .field("chan", &self.chan) .finish() } } /// Error returned by the `Sender`. #[derive(Debug)] pub struct SendError(()); /// Error returned by `Sender::try_send`. #[derive(Debug)] pub struct TrySendError { kind: ErrorKind, value: T, } #[derive(Debug)] enum ErrorKind { Closed, NoCapacity, } /// Error returned by `Receiver`. #[derive(Debug)] pub struct RecvError(()); /// Create a bounded mpsc channel for communicating between asynchronous tasks, /// returning the sender/receiver halves. /// /// All data sent on `Sender` will become available on `Receiver` in the same /// order as it was sent. /// /// The `Sender` can be cloned to `send` to the same channel from multiple code /// locations. Only one `Receiver` is supported. /// /// If the `Receiver` is disconnected while trying to `send`, the `send` method /// will return a `SendError`. Similarly, if `Sender` is disconnected while /// trying to `recv`, the `recv` method will return a `RecvError`. /// /// # Examples /// /// ```rust /// extern crate futures; /// extern crate tokio; /// /// use tokio::sync::mpsc::channel; /// use tokio::prelude::*; /// use futures::future::lazy; /// /// # fn some_computation() -> impl Future + Send { /// # futures::future::ok::<(), ()>(()) /// # } /// /// tokio::run(lazy(|| { /// let (tx, rx) = channel(100); /// /// tokio::spawn({ /// some_computation() /// .and_then(|value| { /// tx.send(value) /// .map_err(|_| ()) /// }) /// .map(|_| ()) /// .map_err(|_| ()) /// }); /// /// rx.for_each(|value| { /// println!("got value = {:?}", value); /// Ok(()) /// }) /// .map(|_| ()) /// .map_err(|_| ()) /// })); /// ``` pub fn channel(buffer: usize) -> (Sender, Receiver) { assert!(buffer > 0, "mpsc bounded channel requires buffer > 0"); let semaphore = (::semaphore::Semaphore::new(buffer), buffer); let (tx, rx) = chan::channel(semaphore); let tx = Sender::new(tx); let rx = Receiver::new(rx); (tx, rx) } /// Channel semaphore is a tuple of the semaphore implementation and a `usize` /// representing the channel bound. type Semaphore = (::semaphore::Semaphore, usize); impl Receiver { pub(crate) fn new(chan: chan::Rx) -> Receiver { Receiver { chan } } /// Closes the receiving half of a channel, without dropping it. /// /// This prevents any further messages from being sent on the channel while /// still enabling the receiver to drain messages that are buffered. pub fn close(&mut self) { self.chan.close(); } } impl Stream for Receiver { type Item = T; type Error = RecvError; fn poll(&mut self) -> Poll, Self::Error> { self.chan.recv() .map_err(|_| RecvError(())) } } impl Sender { pub(crate) fn new(chan: chan::Tx) -> Sender { Sender { chan } } /// Check if the `Sender` is ready to handle a value. /// /// Polls the channel to determine if there is guaranteed capacity to send /// at least one item without waiting. /// /// When `poll_ready` returns `Ready`, the channel reserves capacity for one /// message for this `Sender` instance. The capacity is held until a message /// is send or the `Sender` instance is dropped. Callers should ensure a /// message is sent in a timely fashion in order to not starve other /// `Sender` instances. /// /// # Return value /// /// This method returns: /// /// - `Ok(Async::Ready(_))` if capacity is reserved for a single message. /// - `Ok(Async::NotReady)` if the channel may not have capacity, in which /// case the current task is queued to be notified once /// capacity is available; /// - `Err(SendError)` if the receiver has been dropped. pub fn poll_ready(&mut self) -> Poll<(), SendError> { self.chan.poll_ready() .map_err(|_| SendError(())) } /// Attempts to send a message on this `Sender`, returning the message /// if there was an error. pub fn try_send(&mut self, message: T) -> Result<(), TrySendError> { self.chan.try_send(message)?; Ok(()) } } impl Sink for Sender { type SinkItem = T; type SinkError = SendError; fn start_send(&mut self, msg: T) -> StartSend { use futures::AsyncSink; use futures::Async::*; match self.poll_ready()? { Ready(_) => { self.try_send(msg).map_err(|_| SendError(()))?; Ok(AsyncSink::Ready) } NotReady => { Ok(AsyncSink::NotReady(msg)) } } } fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { use futures::Async::Ready; Ok(Ready(())) } fn close(&mut self) -> Poll<(), Self::SinkError> { use futures::Async::Ready; Ok(Ready(())) } } // ===== impl SendError ===== impl fmt::Display for SendError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { use std::error::Error; write!(fmt, "{}", self.description()) } } impl ::std::error::Error for SendError { fn description(&self) -> &str { "channel closed" } } // ===== impl TrySendError ===== impl TrySendError { /// Get the inner value. pub fn into_inner(self) -> T { self.value } /// Did the send fail because the channel has been closed? pub fn is_closed(&self) -> bool { if let ErrorKind::Closed = self.kind { true } else { false } } /// Did the send fail because the channel was at capacity? pub fn is_full(&self) -> bool { if let ErrorKind::NoCapacity = self.kind { true } else { false } } } impl fmt::Display for TrySendError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { use std::error::Error; write!(fmt, "{}", self.description()) } } impl ::std::error::Error for TrySendError { fn description(&self) -> &str { match self.kind { ErrorKind::Closed => "channel closed", ErrorKind::NoCapacity => "no available capacity", } } } impl From<(T, chan::TrySendError)> for TrySendError { fn from((value, err): (T, chan::TrySendError)) -> TrySendError { TrySendError { value, kind: match err { chan::TrySendError::Closed => ErrorKind::Closed, chan::TrySendError::NoPermits => ErrorKind::NoCapacity, } } } }