Rust seems to have the restriction that any Boxed trait
needs to specify whether it has a Send
bound or not.
If your library works with user defined types, and you use a lot of Pin<Box<dyn Future...>>
and others, it becomes quickly problematic to work on both Send
and !Send
types.
As an example, actix's send method requires Send
on all Message types.
The result it seems would be the need to duplicate almost an entire library in Send
and !Send
halves, which obviously doesn't keep it DRY.
So far, the solution I have found is kind of hacky, so I'm hoping someone here will have a better one, and otherwise it might still serve others:
You can access the same code through different paths using the module system. The actual code can be symlinked under two different modules, and can then use super::BoxedFuture
for any types that might have a Send
bound in them. You can use both type and trait aliases in the super modules:
send.rs:
--------
mod inner;
pub use inner::*;
type BoxFuture<T> = Pin<Box< dyn Future<Outcome=T> + Send >>;
trait SomeTrait: OtherTrait + Send {}
not_send.rs:
------------
mod inner;
pub use inner::*;
type BoxFuture<T> = Pin<Box< dyn Future<Outcome=T> >>;
trait SomeTrait: OtherTrait {}
inner.rs
--------
use super::*;
pub struct SomeFunctionality;
// use BoxFuture which might or might not be Send
Now we symlink inner.rs
under send/inner.rs
and not_send/inner.rs
The super modules can also publicly re-export everything from the inner module. Now you can access your code as:
send::SomeFunctionality
vs not_send::SomeFunctionality
.
Both will refer to the same code, symlinked in two places.
Warning: I don't think the compiler team wants to make any guarantees on the forward compatibility of such hacks, but it does seem to work for me. I figure if I have to duplicate my entire library, I might as well do it when this breaks in the future rather than now.
Have yet to try it on a realistic sized lib.