If you are doing FFI with a T
pointee, then chances are that T : 'static
already (otherwise it's easy to get use-after-frees in some patterns). In that case, there is no variance to talk about in the T
parameter, since you won't have lifetime-based subtyping in there.
Moreover, assuming you didn't have that 'static
parameter, since the FFI is able to mutate it, then you're effectively having a mutable handle to a T
, such as &Cell<T>
or &mut T
. Both of these cases are to be invariant (the rule of thumb is that a borrow able to mutate a T
must be invariant in T
for soundness).
Remember the rule of thumb:
- (Regarding
'a
, the lifetime of the borrow itself, since shrinking that "knowledge" about the exact duration of the borrow can't cause unsoundness, you can venture into being covariant in that parameter)
But again, try to go for a conceptual level, and you'll rarely be wrong: if you have 'a
-borrowed shared (&
) mutable (Cell
; very typical semantics in the FFI world) access to a T
, then do add a PhantomData<&'a Cell<T>>
. While you could also use PhantomData<&'a mut T>
, many FFI APIs do not deal with the very strong and strict unique reference semantics of Rust, so I find those ill-suited for FFI: &'a Cell<T>
would be more honest.