When one needs to "forget" a type of the pointer it's can be safely cast to some other pointer. Usually
*const () or
*const u8 is used. Or
NonNull if null pointer are out of question and niche is nice to have.
Later pointer can be cast back to original type and then safely dereferenced.
Typical use case for this is to perform downcasts at runtime when
TypeId is available externally so no
dyn Any is required.
This still works for pointers to slices and DST structs with slice field. Except that now the pointer have to be cast to arbitrary slice pointer like
And now this doesn't work for
dyn Trait and generic
T: ?Sized. Cast between
*const dyn Trait and
*const dyn OtherTrait is not allowed. Same as cast between
*const dyn Trait and
The reason behind this is (as I understand it) that the layout of metadata can be different.
So I guess that transmuting those pointers may be UB.
Now I have a problem. I try to make a function signature for function that takes thin pointer to value and TypeId and returns pointer to type with that TypeId or None. The TypeId can be of inner type or of dyn trait.
What are my options?
This is a question about using Rust, not about evolving the language, so is a better fit for the users forum.
To go from
(*mut (), TypeId) to
*mut impl ?Sized, the best option is to actually just hold onto
*mut dyn Any; it's the same size (and perhaps smaller, once
TypeId is strengthened against collisions), and will automatically avoid soundness issues.
If splitting into two parts is necessary (e.g. to cross FFI), you want to look at the
ptr_metadata APIs to split
*mut dyn Any into
(*mut (), DynMetadata<dyn Any>).
I do not believe you can soundly directly downcast from
dyn Any to
dyn Trait, no matter the language features. You need to know the concrete type in order to select the correct
dyn Trait vtable, and the
dyn Any vtable does not and cannot contain this information.
In my use case I don't carry
At some point I have a
NonNull<T> that points to an array of
T and turn it to type-erased
NonNull<u8> to store in heterogeneous data structure.
At later point I again have
T, look for a correct
NonNull<u8> and cast it. Then I can iterate over
Now I want to add a layer of abstraction.
During setup a few functions with signature
fn(&T) -> &U where U: ?Sized can be registered.
And wrapped to
fn(NonNull<u8>) -> ??? to store them heterogeneously.
Now receiver would only know about
U: ?Sized, has pairs of
fn(NonNull<u8>) -> ??? and knowledge that that pointer can be used with that function and that function output was
NonNull<U> cast into
The problem is, what
??? type should be?
I tried transmuting
NonNull<[u8]> and back and it worked, but I guess it's UB if
U is dyn trait.
Also works with any dummy dyn trait object type. And probably UB again if
U is slice.
Currently I rewrote the thing to cast function pointer instead of its output. i.e. I transmute
fn(NonNull<u8>) -> NonNull<U> to
fn(NonNull<u8>) to store it and then back to
fn(NonNull<u8>) -> NonNull<U> to call it.
I wonder if any of the methods I tried could theoretically be not only safe and sound, but defined such.
This is an important detail. In this case you necessarily have
T: Sized (to construct a
[T]), and can cast between
*mut () and
*mut T freely.
It doesn't. I don't know what you transmuted; probably
fn(…) -> …, which does work. Transmuting between function pointer types is AIUI guaranteed to be sound.
What you probably want is an opaque function pointer type, though. std doesn't have one, but it's possible to polyfill, kinda.
Well, it "works" like this.
But I figured it is either UB or may become UB in future.
I switched to function pointer cast instead. Should be future-proof.