Rocket icon indicating copy to clipboard operation
Rocket copied to clipboard

DefaultListener::bindable() isn’t usable

Open palant opened this issue 4 months ago • 8 comments

Rocket Version

0.6.0 rev f75fb63

Operating System

Fedora Linux 39

Rust Toolchain Version

rustc 1.78.0-nightly (2bf78d12d 2024-02-18) and rustc 1.76.0 (07dca489a 2024-02-04)

What happened?

A low-level connection interface has been added in #1070 which I’m trying to use to implement more advanced TLS support. I’ve hit a roadblock however, as Rust won’t let me use the Bindable returned by DefaultListener::bindable(). I’ve been unable to find a work-around other than making DefaultListener::base_bindable() public or making DefaultListener::bindable() return Either<TlsBindable<std::net::SocketAddr>, TlsBindable<super::unix::UdsConfig>> explicitly instead of impl Binding. It is my understanding that the latter shouldn’t have any impact, but for some reason it does.

Note that having DefaultListener::base_bindable() public would be helpful regardless. Currently I have to remove TLS configuration from DefaultListener to make sure it won’t give me a TLS bindable.

Test Case

#[rocket::main]
async fn main() -> Result<(), rocket::Error> {
    let rocket = rocket::build();
    let config = rocket
        .figment()
        .extract::<rocket::listener::DefaultListener>()?;
    rocket.launch_on(config.bindable()?).await?;
    Ok(())
}

Log Output

error[E0277]: `impl std::future::Future<Output = Result<<impl Bindable as Bindable>::Listener, <impl Bindable as Bindable>::Error>>` cannot be sent between threads safely
   --> src/main.rs:2:46
    |
2   |   async fn main() -> Result<(), rocket::Error> {
    |  ______________________________________________^
3   | |     let rocket = rocket::build();
4   | |     let config = rocket.figment().extract::<rocket::listener::DefaultListener>()?;
5   | |     rocket.launch_on(config.bindable()?)
6   | |         .await?;
7   | |     Ok(())
8   | | }
    | | ^
    | | |
    | |_`impl std::future::Future<Output = Result<<impl Bindable as Bindable>::Listener, <impl Bindable as Bindable>::Error>>` cannot be sent between threads safely
    |   within this `{async block@src/main.rs:2:46: 8:2}`
    |
    = help: within `{async block@src/main.rs:2:46: 8:2}`, the trait `std::marker::Send` is not implemented for `impl std::future::Future<Output = Result<<impl Bindable as Bindable>::Listener, <impl Bindable as Bindable>::Error>>`, which is required by `{async block@src/main.rs:2:46: 8:2}: std::marker::Send`
note: `<impl Bindable as Bindable>::bind` is an `async fn` in trait, which does not automatically imply that its future is `std::marker::Send`
   --> Rocket/core/lib/src/listener/bindable.rs:10:5
    |
10  |     async fn bind(self) -> Result<Self::Listener, Self::Error>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: required because it captures the following types: `Rocket<Ignite>`, `impl std::future::Future<Output = Result<<impl Bindable as Bindable>::Listener, <impl Bindable as Bindable>::Error>>`, `impl std::future::Future<Output = Result<Rocket<Ignite>, rocket::Error>>`
note: required because it's used within this `async` fn body
   --> Rocket/core/lib/src/rocket.rs:690:90
    |
690 |       async fn _launch_on<B: Bindable>(self, bindable: B) -> Result<Rocket<Ignite>, Error> {
    |  __________________________________________________________________________________________^
691 | |         let listener = bindable.bind().await.map_err(|e| ErrorKind::Bind(Box::new(e)))?;
692 | |         self.serve(listener).await
693 | |     }
    | |_____^
    = note: required because it captures the following types: `Rocket<Build>`, `impl Bindable`, `rocket::phase::State`, `ControlFlow<Result<Infallible, rocket::Error>, Rocket<Ignite>>`, `impl std::future::Future<Output = Result<Rocket<Ignite>, rocket::Error>>`, `impl std::future::Future<Output = Result<Rocket<Ignite>, rocket::Error>>`, `impl std::future::Future<Output = Result<Rocket<Ignite>, rocket::Error>>`
note: required because it's used within this `async` fn body
   --> Rocket/core/lib/src/rocket.rs:944:93
    |
944 |       pub async fn launch_on<B: Bindable>(self, bindable: B) -> Result<Rocket<Ignite>, Error> {
    |  _____________________________________________________________________________________________^
945 | |         match self.0.into_state() {
946 | |             State::Build(s) => Rocket::from(s).ignite().await?._launch_on(bindable).await,
947 | |             State::Ignite(s) => Rocket::from(s)._launch_on(bindable).await,
948 | |             State::Orbit(s) => Ok(Rocket::from(s).into_ignite())
949 | |         }
950 | |     }
    | |_____^
    = note: required because it captures the following types: `Rocket<Build>`, `DefaultListener`, `ControlFlow<Result<Infallible, rocket::Error>, impl Bindable>`, `impl std::future::Future<Output = Result<Rocket<Ignite>, rocket::Error>>`
note: required because it's used within this `async` block
   --> src/main.rs:2:46
    |
2   |   async fn main() -> Result<(), rocket::Error> {
    |  ______________________________________________^
3   | |     let rocket = rocket::build();
4   | |     let config = rocket.figment().extract::<rocket::listener::DefaultListener>()?;
5   | |     rocket.launch_on(config.bindable()?)
6   | |         .await?;
7   | |     Ok(())
8   | | }
    | |_^
note: required by a bound in `async_main`
   --> Rocket/core/lib/src/lib.rs:252:66
    |
252 | pub fn async_main<R>(fut: impl std::future::Future<Output = R> + Send) -> R {
    |                                                                  ^^^^ required by this bound in `async_main`

error[E0277]: `impl std::future::Future<Output = Result<<<impl Bindable as Bindable>::Listener as Listener>::Accept, std::io::Error>>` cannot be sent between threads safely
   --> src/main.rs:2:46
    |
2   |   async fn main() -> Result<(), rocket::Error> {
    |  ______________________________________________^
3   | |     let rocket = rocket::build();
4   | |     let config = rocket.figment().extract::<rocket::listener::DefaultListener>()?;
5   | |     rocket.launch_on(config.bindable()?)
6   | |         .await?;
7   | |     Ok(())
8   | | }
    | | ^
    | | |
    | |_`impl std::future::Future<Output = Result<<<impl Bindable as Bindable>::Listener as Listener>::Accept, std::io::Error>>` cannot be sent between threads safely
    |   within this `{async block@src/main.rs:2:46: 8:2}`
    |
    = help: within `{async block@src/main.rs:2:46: 8:2}`, the trait `std::marker::Send` is not implemented for `impl std::future::Future<Output = Result<<<impl Bindable as Bindable>::Listener as Listener>::Accept, std::io::Error>>`, which is required by `{async block@src/main.rs:2:46: 8:2}: std::marker::Send`
note: `<<impl Bindable as Bindable>::Listener as Listener>::accept` is an `async fn` in trait, which does not automatically imply that its future is `std::marker::Send`
   --> Rocket/core/lib/src/listener/listener.rs:13:5
    |
13  |     async fn accept(&self) -> io::Result<Self::Accept>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: required because it captures the following types: `&listener::bounced::Bounced<<impl Bindable as Bindable>::Listener>`, `Result<<<impl Bindable as Bindable>::Listener as Listener>::Accept, std::io::Error>`, `impl std::future::Future<Output = Result<<<impl Bindable as Bindable>::Listener as Listener>::Accept, std::io::Error>>`, `std::io::Error`, `Sleep`
note: required because it's used within this `async` fn body
   --> Rocket/core/lib/src/listener/bounced.rs:28:67
    |
28  |       pub async fn accept_next(&self) -> <Self as Listener>::Accept {
    |  ___________________________________________________________________^
29  | |         loop {
30  | |             match self.listener.accept().await {
31  | |                 Ok(accept) => return accept,
...   |
38  | |         }
39  | |     }
    | |_____^
    = note: required because it captures the following types: `impl std::future::Future<Output = <listener::bounced::Bounced<<impl Bindable as Bindable>::Listener> as Listener>::Accept>`, `rocket::futures::future::Select<Pin<&mut impl std::future::Future<Output = <listener::bounced::Bounced<<impl Bindable as Bindable>::Listener> as Listener>::Accept>>, rocket::Shutdown>`
note: required because it's used within this `async` fn body
   --> Rocket/core/lib/src/listener/cancellable.rs:111:75
    |
111 |       pub async fn accept_next(&self) -> Option<<Self as Listener>::Accept> {
    |  ___________________________________________________________________________^
112 | |         let next = std::pin::pin!(self.listener.accept_next());
113 | |         match select(next, self.trigger.clone()).await {
114 | |             Either::Left((next, _)) => Some(next),
115 | |             Either::Right(_) => None,
116 | |         }
117 | |     }
    | |_____^
    = note: required because it captures the following types: `Rocket<Ignite>`, `hyper_util::server::conn::auto::Builder<hyper_util::rt::tokio::TokioExecutor>`, `std::time::Duration`, `listener::cancellable::CancellableListener<rocket::Shutdown, listener::bounced::Bounced<<impl Bindable as Bindable>::Listener>>`, `Arc<Rocket<Orbit>>`, `rocket::tokio::task::JoinHandle<()>`, `Arc<hyper_util::server::conn::auto::Builder<hyper_util::rt::tokio::TokioExecutor>>`, `Arc<listener::cancellable::CancellableListener<rocket::Shutdown, listener::bounced::Bounced<<impl Bindable as Bindable>::Listener>>>`, `impl std::future::Future<Output = std::option::Option<<listener::cancellable::CancellableListener<rocket::Shutdown, listener::bounced::Bounced<<impl Bindable as Bindable>::Listener>> as Listener>::Accept>>`, `std::array::IntoIter<std::time::Duration, 5>`, `Sleep`
note: required because it's used within this `async` fn body
   --> Rocket/core/lib/src/server.rs:89:5
    |
89  | /     {
90  | |         let mut builder = Builder::new(TokioExecutor::new());
91  | |         let keep_alive = Duration::from_secs(self.config.keep_alive.into());
92  | |         builder.http1()
...   |
178 | |         }
179 | |     }
    | |_____^
    = note: required because it captures the following types: `Rocket<Ignite>`, `impl std::future::Future<Output = Result<<impl Bindable as Bindable>::Listener, <impl Bindable as Bindable>::Error>>`, `impl std::future::Future<Output = Result<Rocket<Ignite>, rocket::Error>>`
note: required because it's used within this `async` fn body
   --> Rocket/core/lib/src/rocket.rs:690:90
    |
690 |       async fn _launch_on<B: Bindable>(self, bindable: B) -> Result<Rocket<Ignite>, Error> {
    |  __________________________________________________________________________________________^
691 | |         let listener = bindable.bind().await.map_err(|e| ErrorKind::Bind(Box::new(e)))?;
692 | |         self.serve(listener).await
693 | |     }
    | |_____^
    = note: required because it captures the following types: `Rocket<Build>`, `impl Bindable`, `rocket::phase::State`, `ControlFlow<Result<Infallible, rocket::Error>, Rocket<Ignite>>`, `impl std::future::Future<Output = Result<Rocket<Ignite>, rocket::Error>>`, `impl std::future::Future<Output = Result<Rocket<Ignite>, rocket::Error>>`, `impl std::future::Future<Output = Result<Rocket<Ignite>, rocket::Error>>`
note: required because it's used within this `async` fn body
   --> Rocket/core/lib/src/rocket.rs:944:93
    |
944 |       pub async fn launch_on<B: Bindable>(self, bindable: B) -> Result<Rocket<Ignite>, Error> {
    |  _____________________________________________________________________________________________^
945 | |         match self.0.into_state() {
946 | |             State::Build(s) => Rocket::from(s).ignite().await?._launch_on(bindable).await,
947 | |             State::Ignite(s) => Rocket::from(s)._launch_on(bindable).await,
948 | |             State::Orbit(s) => Ok(Rocket::from(s).into_ignite())
949 | |         }
950 | |     }
    | |_____^
    = note: required because it captures the following types: `Rocket<Build>`, `DefaultListener`, `ControlFlow<Result<Infallible, rocket::Error>, impl Bindable>`, `impl std::future::Future<Output = Result<Rocket<Ignite>, rocket::Error>>`
note: required because it's used within this `async` block
   --> src/main.rs:2:46
    |
2   |   async fn main() -> Result<(), rocket::Error> {
    |  ______________________________________________^
3   | |     let rocket = rocket::build();
4   | |     let config = rocket.figment().extract::<rocket::listener::DefaultListener>()?;
5   | |     rocket.launch_on(config.bindable()?)
6   | |         .await?;
7   | |     Ok(())
8   | | }
    | |_^
note: required by a bound in `async_main`
   --> Rocket/core/lib/src/lib.rs:252:66
    |
252 | pub fn async_main<R>(fut: impl std::future::Future<Output = R> + Send) -> R {
    |                                                                  ^^^^ required by this bound in `async_main`

For more information about this error, try `rustc --explain E0277`.

Additional Context

No response

System Checks

  • [X] My bug report relates to functionality.
  • [X] I have tested against the latest Rocket release or a recent git commit.
  • [X] I have tested against the latest stable rustc toolchain.
  • [X] I was unable to find this issue previously reported.

palant avatar Feb 19 '24 11:02 palant