Needing PhantomData
does not necessarily mean you need PhantomData<T>
.
The official documentation doesn't do a great job of explaining this, but the type argument for PhantomData
should be chosen to have the same semantics as the type that holds it. This includes variance as well as drop behavior and auto traits such as Unpin
. That means you should not use PhantomData<T>
unless you're writing a type that semantically contains a T
.
I'm not sure PhantomData
is the right solution at all, but if it is, you need to use a type argument that conveys the actual relationship between WrapperSink<_, T>
and T
. It doesn't contain a T
, but it can consume a T
, at least, that seems to be the intended purpose. So try PhantomData<fn(T)>
. Function pointers have no drop behavior, and they are Sync
, Send
, and Unpin
, so you don't need to add a T: Unpin
bound to make WrapperSink<_, T>: Unpin
.
PhantomData<fn(T)>
is contravariant in T
, which is correct for a struct that does not store or produce a T
. If you're writing any unsafe
code, you might need PhantomData<fn(T) -> T>
instead, which is invariant in T
. Invariance is always the safest choice, so if you're unsure you might want to start with that and relax it to PhantomData<fn(T)>
only when you encounter lifetime errors.