Repository: alexcrichton/futures-rs (rust)

Issue:
Add an API for calling `poll_cancel` off task
There generally should be some way to do this (on `oneshot` or any other type w/ `poll_cancel`) as it is common to use these types to feed data into the task system from external sources.

Pull request:
Add `oneshot::Sender::is_canceled`
This is useful to call from an off-futures task when `poll_cancel` would
otherwise panic.

Closes #419

Patch:
diff --git a/src/sync/oneshot.rs b/src/sync/oneshot.rs
index f383edb2..08d9bf29 100644
--- a/src/sync/oneshot.rs
+++ b/src/sync/oneshot.rs
@@ -164,6 +164,10 @@ impl<T> Inner<T> {
         }
     }
 
+    fn is_canceled(&self) -> bool {
+        self.complete.load(SeqCst)
+    }
+
     fn drop_tx(&self) {
         // Flag that we're a completed `Sender` and try to wake up a receiver.
         // Whether or not we actually stored any data will get picked up and
@@ -302,11 +306,7 @@ impl<T> Sender<T> {
     ///
     /// This function can be used to learn about when the `Receiver` (consumer)
     /// half has gone away and nothing will be able to receive a message sent
-    /// from `complete`.
-    ///
-    /// Like `Future::poll`, this function will panic if it's not called from
-    /// within the context of a task. In otherwords, this should only ever be
-    /// called from inside another future.
+    /// from `send`.
     ///
     /// If `Ready` is returned then it means that the `Receiver` has disappeared
     /// and the result this `Sender` would otherwise produce should no longer
@@ -316,9 +316,35 @@ impl<T> Sender<T> {
     /// able to receive a message if sent. The current task, however, is
     /// scheduled to receive a notification if the corresponding `Receiver` goes
     /// away.
+    ///
+    /// # Panics
+    ///
+    /// Like `Future::poll`, this function will panic if it's not called from
+    /// within the context of a task. In other words, this should only ever be
+    /// called from inside another future.
+    ///
+    /// If you're calling this function from a context that does not have a
+    /// task, then you can use the `is_canceled` API instead.
     pub fn poll_cancel(&mut self) -> Poll<(), ()> {
         self.inner.poll_cancel()
     }
+
+    /// Tests to see whether this `Sender`'s corresponding `Receiver`
+    /// has gone away.
+    ///
+    /// This function can be used to learn about when the `Receiver` (consumer)
+    /// half has gone away and nothing will be able to receive a message sent
+    /// from `send`.
+    ///
+    /// Note that this function is intended to *not* be used in the context of a
+    /// future. If you're implementing a future you probably want to call the
+    /// `poll_cancel` function which will block the current task if the
+    /// cancellation hasn't happened yet. This can be useful when working on a
+    /// non-futures related thread, though, which would otherwise panic if
+    /// `poll_cancel` were called.
+    pub fn is_canceled(&self) -> bool {
+        self.inner.is_canceled()
+    }
 }
 
 impl<T> Drop for Sender<T> {


Test patch:
diff --git a/tests/oneshot.rs b/tests/oneshot.rs
index 7097a591..85e5b593 100644
--- a/tests/oneshot.rs
+++ b/tests/oneshot.rs
@@ -89,3 +89,11 @@ fn close_wakes() {
     tx2.send(()).unwrap();
     t.join().unwrap();
 }
+
+#[test]
+fn is_canceled() {
+    let (tx, rx) = channel::<u32>();
+    assert!(!tx.is_canceled());
+    drop(rx);
+    assert!(tx.is_canceled());
+}