optional_future/
lib.rs

1use std::{
2  future::Future,
3  mem,
4  ops::{Deref, DerefMut},
5  pin::Pin,
6  task::{Context, Poll},
7};
8
9use futures_core::FusedFuture;
10use pin_project_lite::pin_project;
11
12/// A boxed [`OptionalFuture`].
13pub type BoxOptionalFuture<T> = OptionalFuture<Pin<Box<dyn Future<Output = T> + Send + 'static>>>;
14
15pin_project! {
16  /// A future wrapped in an option. If the option is [`None`], then it can never resolve. This is
17  /// useful when you want have a select! on a future that is only sometimes valid.
18  #[derive(Debug)]
19  #[must_use = "futures do nothing unless you `.await` or poll them"]
20  pub struct OptionalFuture<Fut> {
21    #[pin]
22    inner: Option<Fut>,
23  }
24}
25
26impl<Fut> OptionalFuture<Fut> {
27  /// Replaces the the actual value in the option by the value in the parameter, returning the old
28  /// value if present, leaving a [`Some`] in its place without deinitializing either one.
29  pub fn replace(&mut self, value: Fut) -> Option<Fut> {
30    mem::replace(&mut self.inner, Some(value))
31  }
32
33  /// Takes the value out of the option, leaving a [`None`] in its place.
34  pub fn take(&mut self) -> Option<Fut> {
35    mem::take(&mut self.inner)
36  }
37
38  /// Returns `true` if the option is a [`None`] value.
39  pub fn is_none(&self) -> bool {
40    self.inner.is_none()
41  }
42
43  /// Returns `true` if the option is a [`Some`] value.
44  pub fn is_some(&self) -> bool {
45    self.inner.is_some()
46  }
47
48  /// Gets the contained `Option<Fut>`` as an `Option<&Fut>`.
49  pub fn as_ref(&self) -> Option<&Fut> {
50    self.inner.as_ref()
51  }
52}
53
54/// Returns [`None`].
55impl<Fut> Default for OptionalFuture<Fut> {
56  fn default() -> Self {
57    Self { inner: None }
58  }
59}
60
61/// Creates a new optional future from an Option.
62pub fn optional_future<Fut>(option: Option<Fut>) -> OptionalFuture<Fut>
63where
64  Fut: Future,
65{
66  OptionalFuture { inner: option }
67}
68
69impl<Fut> Future for OptionalFuture<Fut>
70where
71  Fut: Future,
72{
73  type Output = Fut::Output;
74
75  fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
76    match self.project().inner.as_pin_mut() {
77      Some(inner) => inner.poll(cx),
78      None => Poll::Pending,
79    }
80  }
81}
82
83impl<Fut> FusedFuture for OptionalFuture<Fut>
84where
85  Fut: FusedFuture,
86{
87  fn is_terminated(&self) -> bool {
88    match &self.inner {
89      Some(inner) => inner.is_terminated(),
90      None => true, // this can never change from Pending
91    }
92  }
93}
94
95impl<Fut> From<Option<Fut>> for OptionalFuture<Fut> {
96  fn from(value: Option<Fut>) -> Self {
97    Self { inner: value }
98  }
99}
100
101impl<Fut> Clone for OptionalFuture<Fut>
102where
103  Fut: Clone,
104{
105  fn clone(&self) -> Self {
106    Self {
107      inner: self.inner.clone(),
108    }
109  }
110}
111
112impl<Fut> Deref for OptionalFuture<Fut> {
113  type Target = Option<Fut>;
114
115  fn deref(&self) -> &Self::Target {
116    &self.inner
117  }
118}
119
120impl<Fut> DerefMut for OptionalFuture<Fut> {
121  fn deref_mut(&mut self) -> &mut Self::Target {
122    &mut self.inner
123  }
124}