I'd like to define a trait which forces its implementors to under no circumstances be sent to, or shared between, threads. It should suffice to mark the trait as !Send
, but Rust doesn't seem to let me.
Is it possible?
Example (playground):
#![feature(optin_builtin_traits)]
// This is a syntax error
//trait ThreadThing : !Send {}
// This doesn't work either
trait ThreadThing { }
impl !Send for ThreadThing {}
No, you can't make !Send
a condition of ThreadThing
. The compiler just doesn't support that kind of logic.
If it would be possible for someone using your crate to make a type that is implicitly Send
, contains no unsafe code in its implementation anywhere, and make it unsafe just by implementing ThreadThing
for it -- in that case, you would make ThreadThing
an unsafe trait
to indicate that there is unsafe code somewhere that relies on an invariant that can't be described in the type system: the invariant "Things that are Send
don't implement ThreadThing
".
If, as is more likely, it's only unsafe to implement Send
manually for a type that implements ThreadThing
-- in that case, you don't need to do anything, because manually implementing Send
is unsafe already. If an implementor of ThreadThing
decides to manually implement Send
, they take on the burden of guaranteeing not only their own invariants, but also ThreadThing
's.
The answer is: yes, you can, under some very specific conditions. Whether you should need to do this is another matter.
You can define a negative trait implementation for another trait if the trait you are negating is:
- an auto-trait.
- from the current crate.
So the following will work (playground):
#![feature(optin_builtin_traits)]
auto trait Scary {}
trait ThreadThing { }
impl !Scary for ThreadThing {}
But it would not work if you were trying to do:
impl !Send for ThreadThing {}
Or if Scary
was not an auto-trait.
Note however that, in general it should not be necessary to mark a trait !Send
in this way. The concrete implementations of the trait will be marked Send
or !Send
by the Rust compiler based upon the contents of the implementing struct.