absurd_future/lib.rs
1//! A future adapter that turns a future that never resolves (i.e., returns `Infallible`)
2//! into a future that can resolve to any type.
3//!
4//! This is useful in scenarios where you have a task that runs forever (like a background
5//! service) but need to integrate it into an API that expects a specific return type,
6//! such as `tokio::task::JoinSet`.
7//!
8//! The core of this crate is the [`AbsurdFuture`] struct and the convenient
9//! [`absurd_future`] function.
10//!
11//! For a detailed explanation of the motivation behind this crate and the concept of
12//! uninhabited types in Rust async code, see the blog post:
13//! [How to use Rust's never type (!) to write cleaner async code](https://academy.fpblock.com/blog/rust-never-type-async-code).
14//!
15//! # Example
16//!
17//! ```
18//! use std::convert::Infallible;
19//! use std::future;
20//! use absurd_future::absurd_future;
21//!
22//! // A future that never completes.
23//! async fn task_that_never_returns() -> Infallible {
24//! loop {
25//! // In a real scenario, this might be `tokio::time::sleep` or another
26//! // future that never resolves. For this example, we'll just pend forever.
27//! future::pending::<()>().await;
28//! }
29//! }
30//!
31//! async fn main() {
32//! // We have a task that never returns, but we want to use it in a
33//! // context that expects a `Result<(), &str>`.
34//! let future = task_that_never_returns();
35//!
36//! // Wrap it with `absurd_future` to change its output type.
37//! let adapted_future: _ = absurd_future::<_, Result<(), &str>>(future);
38//!
39//! // This adapted future will now pend forever, just like the original,
40//! // but its type signature satisfies the requirement.
41//! }
42//! ```
43
44use std::{
45 convert::Infallible,
46 future::Future,
47 marker::PhantomData,
48 pin::Pin,
49 task::{Context, Poll},
50};
51
52/// Turn a never-returning future into a future yielding any desired type.
53///
54/// This struct is created by the [`absurd_future`] function.
55///
56/// Useful for async tasks that logically don't complete but need to satisfy an
57/// interface expecting a concrete output type. Because the inner future never
58/// resolves, this future will also never resolve, so the output type `T` is
59/// never actually produced.
60#[must_use = "futures do nothing unless polled"]
61pub struct AbsurdFuture<F, T> {
62 inner: Pin<Box<F>>,
63 _marker: PhantomData<fn() -> T>,
64}
65
66impl<F, T> AbsurdFuture<F, T> {
67 /// Creates a new `AbsurdFuture` that wraps the given future.
68 ///
69 /// The inner future must have an output type of `Infallible`.
70 pub fn new(inner: F) -> Self {
71 Self {
72 inner: Box::pin(inner),
73 _marker: PhantomData,
74 }
75 }
76}
77
78impl<F, T> Future for AbsurdFuture<F, T>
79where
80 F: Future<Output = Infallible>,
81{
82 type Output = T;
83
84 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
85 let inner = self.get_mut().inner.as_mut();
86 match Future::poll(inner, cx) {
87 Poll::Pending => Poll::Pending,
88 Poll::Ready(never) => match never {},
89 }
90 }
91}
92
93/// Wraps a future that never returns and gives it an arbitrary output type.
94///
95/// This function makes it easier to create an [`AbsurdFuture`].
96///
97/// # Type Parameters
98///
99/// - `F`: The type of the inner future, which must return `Infallible`.
100/// - `T`: The desired output type for the wrapped future. This is often inferred.
101pub fn absurd_future<F, T>(future: F) -> AbsurdFuture<F, T>
102where
103 F: Future<Output = Infallible>,
104{
105 AbsurdFuture::new(future)
106}