/
fuse.rs
90 lines (82 loc) · 2.67 KB
/
fuse.rs
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
use core::pin::Pin;
use futures_core::future::{Future, FusedFuture};
use futures_core::task::{Context, Poll};
use pin_utils::unsafe_pinned;
/// Future for the [`fuse`](super::FutureExt::fuse) method.
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Fuse<Fut: Future> {
future: Option<Fut>,
}
impl<Fut: Future> Fuse<Fut> {
unsafe_pinned!(future: Option<Fut>);
pub(super) fn new(f: Fut) -> Fuse<Fut> {
Fuse {
future: Some(f),
}
}
/// Creates a new `Fuse`-wrapped future which is already terminated.
///
/// This can be useful in combination with looping and the `select!`
/// macro, which bypasses terminated futures.
///
/// # Examples
///
/// ```
/// # futures::executor::block_on(async {
/// use futures::channel::mpsc;
/// use futures::future::{Fuse, FusedFuture, FutureExt};
/// use futures::select;
/// use futures::stream::StreamExt;
/// use futures::pin_mut;
///
/// let (sender, mut stream) = mpsc::unbounded();
///
/// // Send a few messages into the stream
/// sender.unbounded_send(()).unwrap();
/// sender.unbounded_send(()).unwrap();
/// drop(sender);
///
/// // Use `Fuse::termianted()` to create an already-terminated future
/// // which may be instantiated later.
/// let foo_printer = Fuse::terminated();
/// pin_mut!(foo_printer);
///
/// loop {
/// select! {
/// _ = foo_printer => {},
/// () = stream.select_next_some() => {
/// if !foo_printer.is_terminated() {
/// println!("Foo is already being printed!");
/// } else {
/// foo_printer.set(async {
/// // do some other async operations
/// println!("Printing foo from `foo_printer` future");
/// }.fuse());
/// }
/// },
/// complete => break, // `foo_printer` is terminated and the stream is done
/// }
/// }
/// # });
/// ```
pub fn terminated() -> Fuse<Fut> {
Fuse { future: None }
}
}
impl<Fut: Future> FusedFuture for Fuse<Fut> {
fn is_terminated(&self) -> bool {
self.future.is_none()
}
}
impl<Fut: Future> Future for Fuse<Fut> {
type Output = Fut::Output;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Fut::Output> {
let v = match self.as_mut().future().as_pin_mut() {
Some(fut) => ready!(fut.poll(cx)),
None => return Poll::Pending,
};
self.as_mut().future().set(None);
Poll::Ready(v)
}
}