fix(client): send an Error::Cancel if a queued request is dropped

Adds `Error::Cancel` variant.
This commit is contained in:
Sean McArthur
2018-02-07 13:12:33 -08:00
parent a821a366f1
commit 88f01793be
3 changed files with 104 additions and 5 deletions

View File

@@ -69,21 +69,66 @@ impl<T, U> Stream for Receiver<T, U> {
}
}
//TODO: Drop for Receiver should consume inner
impl<T, U> Drop for Receiver<T, U> {
fn drop(&mut self) {
self.canceled.cancel();
self.inner.close();
// This poll() is safe to call in `Drop`, because we've
// called, `close`, which promises that no new messages
// will arrive, and thus, once we reach the end, we won't
// see a `NotReady` (and try to park), but a Ready(None).
//
// All other variants:
// - Ready(None): the end. we want to stop looping
// - NotReady: unreachable
// - Err: unreachable
while let Ok(Async::Ready(Some((_val, cb)))) = self.inner.poll() {
// maybe in future, we pass the value along with the error?
let _ = cb.send(Err(::Error::new_canceled()));
}
}
}
#[cfg(test)]
mod tests {
extern crate pretty_env_logger;
#[cfg(feature = "nightly")]
extern crate test;
use futures::{future, Future};
#[cfg(feature = "nightly")]
use futures::{Future, Stream};
use futures::{Stream};
#[test]
fn drop_receiver_sends_cancel_errors() {
let _ = pretty_env_logger::try_init();
future::lazy(|| {
#[derive(Debug)]
struct Custom(i32);
let (tx, rx) = super::channel::<Custom, ()>();
let promise = tx.send(Custom(43)).unwrap();
drop(rx);
promise.then(|fulfilled| {
let res = fulfilled.expect("fulfilled");
match res.unwrap_err() {
::Error::Cancel(_) => (),
e => panic!("expected Error::Cancel(_), found {:?}", e),
}
Ok::<(), ()>(())
})
}).wait().unwrap();
}
#[cfg(feature = "nightly")]
#[bench]
fn cancelable_queue_throughput(b: &mut test::Bencher) {
let (tx, mut rx) = super::channel::<i32, ()>();
b.iter(move || {