Returning a `Future` which is `Send` whenever it can

Hi,

I'm writing a small tool for handling keyboard interrupts as errors on top of tokio_signal. The draft code is available here but I have encountered a problem with the Send trait.

I'd like to support both single- and multi-threaded tokio runtime. This means that:

  • if the base future implements Send, the return future should also implement Send
  • if the base future doesn't implement Send then the return future obviously can't implement Send
  • I don't want to create two traits that the user has to handle manually - this defies the purpose, the crate should be easy to use

In my current implementation I can only choose one of them - either to support Send futures or support non-Send futures. Is there any way I could support them both?
Is there any way I could hint the compiler, so that it infers Send for the dyn Future whenever possible? What should I do in this case? Maybe I could tell the compiler to prefer the more specific implementation, whenever possible?

Sidenote: the compiler error is completely useless in this case and doesn't even mention that the issue is the Send trait. I'm pasting it here for reference.

error[E0599]: no method named `handle_ctrlc` found for type `std::boxed::Box<(dyn futures::future::Future<Item = (), Error = failure::error::Error> + 'static)>` in the current scope
   = note: the method `handle_ctrlc` exists but the following trait bounds were not satisfied:
           `&dyn futures::future::Future<Item = (), Error = failure::error::Error> : AsyncCtrlc<_>`
           `&mut (dyn futures::future::Future<Item = (), Error = failure::error::Error> + 'static) : AsyncCtrlc<_>`
           `&mut std::boxed::Box<(dyn futures::future::Future<Item = (), Error = failure::error::Error> + 'static)> : AsyncCtrlc<_>`
           `&std::boxed::Box<dyn futures::future::Future<Item = (), Error = failure::error::Error>> : AsyncCtrlc<_>`
           `dyn futures::future::Future<Item = (), Error = failure::error::Error> : AsyncCtrlc<_>`
           `std::boxed::Box<dyn futures::future::Future<Item = (), Error = failure::error::Error>> : AsyncCtrlc<_>`

You could create a CtrlCFuture<T> struct, which contains your Box and a PhantomData<T>. Now you can implement Future on this struct (just forward to the box) and add an unsafe impl<T: Send> Send for CtrlCFuture<T>.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.