Skip to main content

async_slot/
unsync.rs

1//! A single-thread variant of an unbounded channel that only stores
2//! last value sent
3
4use std::rc::{Rc, Weak};
5use std::cell::RefCell;
6
7use futures::task::{self, Task};
8use futures::{Sink, Stream, AsyncSink, Async, Poll, StartSend};
9
10use SendError;
11
12/// Slot is very similar to unbounded channel but only stores last value sent
13///
14/// I.e. if you want to send some value between from producer to a consumer
15/// and if consumer is slow it should skip old values, the slot is
16/// a structure for the task.
17
18/// The transmission end of a channel which is used to send values
19///
20/// If the receiver is not fast enough only the last value is preserved and
21/// other ones are discarded.
22#[derive(Debug)]
23pub struct Sender<T> {
24    inner: Weak<RefCell<Inner<T>>>,
25}
26
27/// The receiving end of a channel which preserves only the last value
28#[derive(Debug)]
29pub struct Receiver<T> {
30    inner: Rc<RefCell<Inner<T>>>,
31}
32
33#[derive(Debug)]
34struct Inner<T> {
35    value: Option<T>,
36    read_task: Option<Task>,
37    cancel_task: Option<Task>,
38}
39
40impl<T> Sender<T> {
41    /// Sets the new new value of the stream and notifies the consumer if any.
42    ///
43    /// This function will store the `value` provided as the current value for
44    /// this channel, replacing any previous value that may have been there. If
45    /// the receiver may still be able to receive this message, then `Ok` is
46    /// returned with the previous value that was in this channel.
47    ///
48    /// If `Ok(Some)` is returned then this value overwrote a previous value,
49    /// and the value was never received by the receiver. If `Ok(None)` is
50    /// returned, then no previous value was found and the `value` is queued up
51    /// to be received by the receiver.
52    ///
53    /// # Errors
54    ///
55    /// This function will return an `Err` if the receiver has gone away and
56    /// it's impossible to send this value to the receiver. The error returned
57    /// retains ownership of the `value` provided and can be extracted, if
58    /// necessary.
59    pub fn swap(&self, value: T) -> Result<Option<T>, SendError<T>> {
60        let result;
61        // Do this step first so that the cell is dropped when
62        // `unpark` is called
63        let task = {
64            if let Some(ref cell) = self.inner.upgrade() {
65                let mut inner = cell.borrow_mut();
66                result = inner.value.take();
67                inner.value = Some(value);
68                inner.read_task.take()
69            } else {
70                return Err(SendError(value));
71            }
72        };
73        if let Some(task) = task {
74            task.notify();
75        }
76        return Ok(result);
77    }
78    /// Polls this `Sender` half to detect whether the `Receiver` this has
79    /// paired with has gone away.
80    ///
81    /// This function can be used to learn about when the `Receiver` (consumer)
82    /// half has gone away and nothing will be able to receive a message sent
83    /// from `send` (or `swap`).
84    ///
85    /// If `Ready` is returned then it means that the `Receiver` has disappeared
86    /// and the result this `Sender` would otherwise produce should no longer
87    /// be produced.
88    ///
89    /// If `NotReady` is returned then the `Receiver` is still alive and may be
90    /// able to receive a message if sent. The current task, however, is
91    /// scheduled to receive a notification if the corresponding `Receiver` goes
92    /// away.
93    ///
94    /// # Panics
95    ///
96    /// Like `Future::poll`, this function will panic if it's not called from
97    /// within the context of a task. In other words, this should only ever be
98    /// called from inside another future.
99    ///
100    /// If you're calling this function from a context that does not have a
101    /// task, then you can use the `is_canceled` API instead.
102    pub fn poll_cancel(&mut self) -> Poll<(), ()> {
103        if let Some(ref cell) = self.inner.upgrade() {
104            let mut inner = cell.borrow_mut();
105            inner.cancel_task = Some(task::current());
106            Ok(Async::NotReady)
107        } else {
108            Ok(Async::Ready(()))
109        }
110    }
111
112    /// Tests to see whether this `Sender`'s corresponding `Receiver`
113    /// has gone away.
114    ///
115    /// This function can be used to learn about when the `Receiver` (consumer)
116    /// half has gone away and nothing will be able to receive a message sent
117    /// from `send`.
118    ///
119    /// Note that this function is intended to *not* be used in the context of a
120    /// future. If you're implementing a future you probably want to call the
121    /// `poll_cancel` function which will block the current task if the
122    /// cancellation hasn't happened yet. This can be useful when working on a
123    /// non-futures related thread, though, which would otherwise panic if
124    /// `poll_cancel` were called.
125    pub fn is_canceled(&self) -> bool {
126        self.inner.upgrade().is_none()
127    }
128}
129
130impl<T> Sink for Sender<T> {
131    type SinkItem = T;
132    type SinkError = SendError<T>;
133    fn start_send(&mut self, item: T) -> StartSend<T, SendError<T>> {
134        self.swap(item)?;
135        Ok(AsyncSink::Ready)
136    }
137    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
138        Ok(Async::Ready(()))
139    }
140    fn close(&mut self) -> Poll<(), Self::SinkError> {
141        // Do this step first so that the cell is dropped *and*
142        // weakref is dropped when `unpark` is called
143        let task = self.inner.upgrade()
144            .and_then(|inner| inner.borrow_mut().read_task.take());
145        self.inner = Weak::new();
146        // notify on any drop of a sender, so eventually receiver wakes up
147        // when there are no senders and closes the stream
148        if let Some(task) = task {
149            task.notify();
150        }
151        Ok(Async::Ready(()))
152    }
153}
154
155impl<T> Drop for Sender<T> {
156    fn drop(&mut self) {
157        self.close().ok();
158    }
159}
160
161impl<T> Stream for Receiver<T> {
162    type Item = T;
163    type Error = ();  // actually void
164    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
165        let result = {
166            let mut inner = self.inner.borrow_mut();
167            if inner.value.is_none() {
168                if Rc::weak_count(&self.inner) == 0 {
169                    // no senders, terminate the stream
170                    return Ok(Async::Ready(None));
171                } else {
172                    inner.read_task = Some(task::current());
173                }
174            }
175            inner.value.take()
176        };
177        match result {
178            Some(value) => Ok(Async::Ready(Some(value))),
179            None => Ok(Async::NotReady),
180        }
181    }
182}
183
184/// Creates an in-memory Stream which only preserves last value
185///
186/// This method is somewhat similar to `channel(1)` but instead of preserving
187/// first value sent (and erroring on sender side) it replaces value if
188/// consumer is not fast enough and preserves last values sent on any
189/// poll of a stream.
190///
191/// # Example
192///
193/// ```
194/// extern crate futures;
195/// extern crate async_slot;
196///
197/// use futures::prelude::*;
198/// use futures::stream::iter_ok;
199///
200/// # fn main() {
201/// let (tx, rx) = async_slot::unsync::channel::<i32>();
202///
203/// tx.send_all(iter_ok(vec![1, 2, 3])).wait();
204///
205/// let received = rx.collect().wait().unwrap();
206/// assert_eq!(received, vec![3]);
207/// # }
208/// ```
209pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
210    let inner = Rc::new(RefCell::new(Inner {
211        value: None,
212        read_task: None,
213        cancel_task: None,
214    }));
215    return (Sender { inner: Rc::downgrade(&inner) },
216            Receiver { inner: inner });
217}