Apologies if this is a basic question that's already answered somewhere, I couldn't find it with a search.
I have a trait Foo
, whose behavior should not be customizable by the user for structs are Unpin
. This is because it doesn't make a lot of sense to customize behavior of Foo
for Unpin
types, and thus if the user is trying to do so, it is probably an error as they probably forgot to add a std::marker::PhantomPinned
to their struct.
So I wrote what I thought was correct:
trait Foo { fn foo() {}}
impl<T> Foo for T where T : Unpin {}
Foo is implemented for
Unpin` types, and indeed if I do:
struct Bar {}
fn main() {
<Bar as Foo>::foo()
}
This compiles no problem!
The problem arises when I want to implement Foo
for a !Unpin
type:
struct Baz { _pinned: std::marker::PhantomPinned }
impl Foo for Baz { fn foo() { println!("Customized!") } }
The above yields:
error[E0119]: conflicting implementations of trait `Foo` for type `Baz`:
--> src/main.rs:10:1
|
4 | impl<T> Foo for T where T : Unpin {}
| --------------------------------- first implementation here
...
10 | impl Foo for Baz { fn foo() { println!("Customized!") } }
| ^^^^^^^^^^^^^^^^ conflicting implementation for `Baz`
If I remove the impl Foo for Baz
and try to use the blanket implementation, however...
error[E0277]: `std::marker::PhantomPinned` cannot be unpinned
--> src/main.rs:11:5
|
2 | trait Foo { fn foo() {}}
| -------- required by `Foo::foo`
...
11 | <Baz as Foo>::foo()
| ^^^^^^^^^^^^^^^^^ within `Baz`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
|
= note: required because it appears within the type `Baz`
= note: required because of the requirements on the impl of `Foo` for `Baz`
Having an error here is to be expected, since Baz
is not Unpin
.
However the message of the error informs me that the situation is not as simple as I thought.
It seems that having a PhantomPinned
field makes "being Unpin
" to fail for Baz
, but that it doesn't make Baz
not Unpin
by itself, hence the conflicting implementations?
Is there a way around this particular condition? It is really important to achieve this for my use case.
By contrast, if I blanket-implement Foo
for a different autotrait (such as Copy
), I can do the above and customize the behavior only for non Copy
structs:
trait Foo { fn foo() {println!("Default")}}
impl<T> Foo for T where T : Copy {}
#[derive(Copy, Clone)]
struct Bar {}
struct Baz { }
impl Foo for Baz { fn foo() { println!("Customized") } }
fn main() {
<Bar as Foo>::foo(); // => Default
<Baz as Foo>::foo() // => Customized
}
I would expect the same to work for Unpin
. Is there any workaround to this?