send_future/
lib.rs

1#![no_std]
2
3//! This crate provides [`SendFuture::send`] workaround for compiler bug
4//! [https://github.com/rust-lang/rust/issues/96865](https://github.com/rust-lang/rust/issues/96865)
5//!
6//! See documentation of [`SendFuture`] trait for example usage
7
8/// This trait is used as a workaround for compiler bug
9/// [https://github.com/rust-lang/rust/issues/96865](https://github.com/rust-lang/rust/issues/96865)
10///
11/// Compilation of code calling async methods defined using `impl` syntax within [`Send`] async functions
12/// may fail with hard-to-debug errors.
13///
14/// The following fails to compile with rustc 1.78.0:
15///
16/// ```compile_fail
17/// trait X {
18///     fn test<Y>(&self, x: impl AsRef<[Y]>) -> impl core::future::Future<Output = ()> + Send
19///     where
20///         Y: AsRef<str>;
21/// }
22
23/// fn call_test(x: impl X + Send + Sync) -> impl core::future::Future<Output = ()> + Send {
24///     async move { x.test(["test"]).await }
25/// }
26/// ```
27///
28/// ```text
29/// error: implementation of `AsRef` is not general enough
30///   --> src/lib.rs:66:9
31///    |
32/// 66 |         async move { x.test(["test"]).await }
33///    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `AsRef` is not general enough
34///    |
35///    = note: `[&'0 str; 1]` must implement `AsRef<[&'1 str]>`, for any two lifetimes `'0` and `'1`...
36///    = note: ...but it actually implements `AsRef<[&str]>`
37/// ```
38///
39/// The fix is to call [`send`](SendFuture::send) provided by this trait on the future before awaiting:
40/// ```
41/// use send_future::SendFuture as _;
42///
43/// trait X {
44///     fn test<Y>(&self, x: impl AsRef<[Y]>) -> impl core::future::Future<Output = ()> + Send
45///     where
46///         Y: AsRef<str>;
47/// }
48
49/// fn call_test(x: impl X + Send + Sync) -> impl core::future::Future<Output = ()> + Send {
50///     async move { x.test(["test"]).send().await }
51/// }
52/// ```
53pub trait SendFuture: core::future::Future {
54    fn send(self) -> impl core::future::Future<Output = Self::Output> + Send
55    where
56        Self: Sized + Send,
57    {
58        self
59    }
60}
61
62impl<T: core::future::Future> SendFuture for T {}
63
64#[allow(unused)]
65#[cfg(test)]
66mod tests {
67    use super::SendFuture as _;
68
69    trait X {
70        fn test<Y>(&self, x: impl AsRef<[Y]>) -> impl core::future::Future<Output = ()> + Send
71        where
72            Y: AsRef<str>;
73    }
74
75    fn call_test(x: impl X + Send + Sync) -> impl core::future::Future<Output = ()> + Send {
76        async move { x.test(["test"]).send().await }
77    }
78}