I'm using the open source rust pcap library (https://github.com/rust-pcap/pcap) whose main Capture struct uses a system of market traits to denote which functions are available during which lifecycle state/phase of the capture (e.g., you can't 'sendpacket' on a Capture in the "DEAD" state). It has a hierarchy of State traits such that, e.g., "Activated" is a trait that is implemented by both the "Active", "Dead" and "Offline" states:
pub trait Activated: State {}
impl Activated for Active {}
impl Activated for Offline {}
impl Activated for Dead {}
pub trait State {}
impl State for Inactive {}
impl State for Active {}
impl State for Offline {}
impl State for Dead {}
pub struct Capture<T: State + ?Sized> {
...
}
With that code, I am trying unsuccessfully to convert from a parameterized+bounded trait as a <T: Activated + ?Sized> to a Capture, e.g., :
fn foo<T: Activated + ?Sized>(&mut capture: Capture<T>) {
bar(capture as Capture<dyn Activated>);
}
fn bar(&mut capture: Capture<dyn Activated>) {
...
}
... but am getting an error:
non-primitive cast:
&mut pcap::Capture<T>
as&mut pcap::Capture<dyn pcap::Activated>
as
expression can only be used to convert between primitive types or to coerce to a specific trait object
... which I don't understand at all, despite a fair bit of reading on this. Can someone please explain to me how to do this (or why it's wrong to think this should work)? Thank you in advance!
In current Rust, you can only coerce from Foo<T>
to Foo<dyn Trait>
if T
is a sized type. This is because the conversion requires attaching a vtable pointer for Trait
, and said vtable is only available when T
is a regular, non-dyn
type. So, this code,
fn foo<T: Activated + ?Sized>(&mut capture: Capture<T>) {
bar(capture as Capture<dyn Activated>);
}
will always fail to compile because T: ?Sized
, meaning that T
might be already a dyn
, and you can't cast from a dyn
to an arbitrary different dyn
.
There is an unstable feature, trait_upcasting
(#65991) that will enable dyn conversions to supertraits, like Capture<dyn Activated>
to Capture<dyn State>
, but that still does not include conversion from an arbitrary T: ?Sized
. (In fact, if T = [Foo]
, a type that is dynamically sized for a different reason, then it's impossible for an entirely different reason than traits — the compiler does not support a type being simultaneously vtable-based (having a pointer) and a slice (having a length). That restriction could in principle be lifted, but it'd be more new territory.)
To recap: You will need to organize your program so that you do not need to convert a ?Sized
type to a trait object, because that is not possible.