Reputation: 234654
I want to declare a generic function that accepts trait objects and only trait objects. I want this because I want to type erase these and pass them as TraitObject
objects across an ABI boundary.
A function written like this will fail to compile...
fn f<T: ?Sized>(t: &T) -> std::raw::TraitObject {
unsafe { std::mem::transmute(t) }
}
... with the following error:
error[E0512]: transmute called with differently sized types: &T (pointer to T) to std::raw::TraitObject (128 bits)
I understand why the compiler complains of different sizes: &T
can be a pointer to a concrete type (like &i32
), which is a single pointer (64 bits), or a trait object (like &Display
), which is going to be two pointers with the same layout as std::raw::TraitObject
(128 bits).
This function should be fine as long as &T
is a trait object, i.e. T
is a trait. Is there a way to express this requirement?
Upvotes: 3
Views: 259
Reputation: 234654
If you use transmute_copy
instead, you can have the compiler ignore the size mismatches. This, however, means you have to handle such issues yourself, by e.g. checking the size yourself and perhaps panicking if there's a mismatch. Not doing so can result in undefined behaviour.
fn f<T: ?Sized>(t: &T) -> std::raw::TraitObject {
assert!(std::mem::size_of::<&T>() == std::mem::size_of::<std::raw::TraitObject>());
unsafe { std::mem::transmute_copy(&r) }
}
Upvotes: 3
Reputation: 300409
It is impossible to prove a negative... but as far as I know the answer is no, sorry.
The representation of TraitObject
is unstable, notably because in the future Rust might be able to tack on multiple virtual pointers to a single data pointer (representing &(Display + Eq)
for example).
In the mean time, I usually use low-level memory tricks to read the virtual pointer and data pointer then build the TraitObject
myself; guarded by a call to mem::size_of
to ensure that &T
has the right size for 2 *mut ()
because ?Sized
means Sized
or not (and not !Sized
).
Upvotes: 3
Reputation: 432159
I believe the answer is "no":
There is no way to refer to all trait objects generically
(emphasis mine)
Upvotes: 1