Repository: tokio-rs/tokio (language: rust)

Issue:
tokio::time::timeout should support std::future::IntoFuture
Tokio APIs don't currently support `std::future::IntoFuture`. In particular `tokio::time::timeout` & `timeout_at`.

## Example: timeout
```rust
struct IntoFooture;

impl std::future::IntoFuture for IntoFooture {
    type Output = ();
    type IntoFuture = std::future::Ready<()>;

    fn into_future(self) -> Self::IntoFuture {
        std::future::ready(())
    }
}

fn foo() -> IntoFooture {
    IntoFooture
}

foo().await; // works

_ = tokio::time::timeout(Duration::from_secs(4), foo()).await; // !compile: `IntoFooture` is not a future
```
So currently the future must be explicitly converted here to use `timeout`.
```rust
_ = tokio::time::timeout(Duration::from_secs(4), foo().into_future()).await; // works
```

## Solution: Support `IntoFuture`
If we updated the timeout method to:
```rust
pub fn timeout<F>(duration: Duration, future: F) -> Timeout<F::IntoFuture>
where
    F: std::future::IntoFuture,
{...}
```
The original example would work without the `.into_future()` explicit call.

## MSRV
Note: This requires bumping the msrv to 1.64 as this version stabilised IntoFuture.


Discussion / hints:

Fix patch:
diff --git a/tokio/src/time/timeout.rs b/tokio/src/time/timeout.rs
index 52ab9891c69..fa93a16910e 100644
--- a/tokio/src/time/timeout.rs
+++ b/tokio/src/time/timeout.rs
@@ -11,7 +11,7 @@ use crate::{
 };
 
 use pin_project_lite::pin_project;
-use std::future::Future;
+use std::future::{Future, IntoFuture};
 use std::pin::Pin;
 use std::task::{self, Poll};
 
@@ -83,9 +83,9 @@ use std::task::{self, Poll};
 /// [`Builder::enable_time`]: crate::runtime::Builder::enable_time
 /// [`Builder::enable_all`]: crate::runtime::Builder::enable_all
 #[track_caller]
-pub fn timeout<F>(duration: Duration, future: F) -> Timeout<F>
+pub fn timeout<F>(duration: Duration, future: F) -> Timeout<F::IntoFuture>
 where
-    F: Future,
+    F: IntoFuture,
 {
     let location = trace::caller_location();
 
@@ -94,7 +94,7 @@ where
         Some(deadline) => Sleep::new_timeout(deadline, location),
         None => Sleep::far_future(location),
     };
-    Timeout::new_with_delay(future, delay)
+    Timeout::new_with_delay(future.into_future(), delay)
 }
 
 /// Requires a `Future` to complete before the specified instant in time.
@@ -142,14 +142,14 @@ where
 /// }
 /// # }
 /// ```
-pub fn timeout_at<F>(deadline: Instant, future: F) -> Timeout<F>
+pub fn timeout_at<F>(deadline: Instant, future: F) -> Timeout<F::IntoFuture>
 where
-    F: Future,
+    F: IntoFuture,
 {
     let delay = sleep_until(deadline);
 
     Timeout {
-        value: future,
+        value: future.into_future(),
         delay,
     }
 }


Test patch: