use futures::channel::oneshot; use futures::future::{self, Future, FutureExt, TryFutureExt}; use futures::task::{Context, Poll}; use futures_test::future::FutureTestExt; use pin_project::pin_project; use std::pin::Pin; use std::sync::mpsc; #[test] fn map_ok() { // The closure given to `map_ok` should have been dropped by the time `map` // runs. let (tx1, rx1) = mpsc::channel::<()>(); let (tx2, rx2) = mpsc::channel::<()>(); future::ready::>(Err(1)) .map_ok(move |_| { let _tx1 = tx1; panic!("should not run"); }) .map(move |_| { assert!(rx1.recv().is_err()); tx2.send(()).unwrap() }) .run_in_background(); rx2.recv().unwrap(); } #[test] fn map_err() { // The closure given to `map_err` should have been dropped by the time `map` // runs. let (tx1, rx1) = mpsc::channel::<()>(); let (tx2, rx2) = mpsc::channel::<()>(); future::ready::>(Ok(1)) .map_err(move |_| { let _tx1 = tx1; panic!("should not run"); }) .map(move |_| { assert!(rx1.recv().is_err()); tx2.send(()).unwrap() }) .run_in_background(); rx2.recv().unwrap(); } #[pin_project] struct FutureData { _data: T, #[pin] future: F, } impl Future for FutureData { type Output = F::Output; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { self.project().future.poll(cx) } } #[test] fn then_drops_eagerly() { let (tx0, rx0) = oneshot::channel::<()>(); let (tx1, rx1) = mpsc::channel::<()>(); let (tx2, rx2) = mpsc::channel::<()>(); FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| panic!()) } .then(move |_| { assert!(rx1.recv().is_err()); // tx1 should have been dropped tx2.send(()).unwrap(); future::ready(()) }) .run_in_background(); assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv()); tx0.send(()).unwrap(); rx2.recv().unwrap(); } #[test] fn and_then_drops_eagerly() { let (tx0, rx0) = oneshot::channel::>(); let (tx1, rx1) = mpsc::channel::<()>(); let (tx2, rx2) = mpsc::channel::<()>(); FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| panic!()) } .and_then(move |_| { assert!(rx1.recv().is_err()); // tx1 should have been dropped tx2.send(()).unwrap(); future::ready(Ok(())) }) .run_in_background(); assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv()); tx0.send(Ok(())).unwrap(); rx2.recv().unwrap(); } #[test] fn or_else_drops_eagerly() { let (tx0, rx0) = oneshot::channel::>(); let (tx1, rx1) = mpsc::channel::<()>(); let (tx2, rx2) = mpsc::channel::<()>(); FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| panic!()) } .or_else(move |_| { assert!(rx1.recv().is_err()); // tx1 should have been dropped tx2.send(()).unwrap(); future::ready::>(Ok(())) }) .run_in_background(); assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv()); tx0.send(Err(())).unwrap(); rx2.recv().unwrap(); }