summaryrefslogtreecommitdiffstats
path: root/third_party/rust/futures/tests/eager_drop.rs
blob: 992507774c57932daaad329508e25fa28f8947d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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::<Result<i32, i32>>(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::<Result<i32, i32>>(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<F, T> {
    _data: T,
    #[pin]
    future: F,
}

impl<F: Future, T: Send + 'static> Future for FutureData<F, T> {
    type Output = F::Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<F::Output> {
        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::<Result<(), ()>>();
    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::<Result<(), ()>>();
    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::<Result<(), ()>>(Ok(()))
        })
        .run_in_background();

    assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv());
    tx0.send(Err(())).unwrap();
    rx2.recv().unwrap();
}