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}