I want to store a pointer of any type, but I don't know what ? can be replaced with. Neither *const () nor *const [()] is allowed here due to the existence of trait object. And I don't know how to judge whether a pointer is fat or thin, so I dare not cast *const () or *const [()] to *const T forcedly. Thus, I created this topic.
Creating a struct or enum is acceptable. Thanks.
#![allow(unused)]
use std::any::{Any, TypeId};
struct AnyPointer {
ptr: *const ?, // What type can `?` be replaced with
tid: TypeId,
}
impl AnyPointer {
fn from_ptr<T: ?Sized>(ptr: *const T) -> AnyPointer {
AnyPointer {
ptr: ptr as _,
tid: TypeId::of::<T>(),
}
}
fn try_cast<T: ?Sized>(&self) -> Option<*const T> {
if TypeId::of::<T>() != self.tid {
return None;
}
Some(self.ptr as _)
}
}
You might be looking for the nightly pointer::to_raw_parts() method which lets you decompose some *const T pointer into its data (a *const ()) and its metadata (e.g. a pointer to a trait object's vtable). This would make your AnyPointer type a bit more complex though, because you'll need to figure out how to store the metadata without making AnyPointer generic over the T type.
However, is there any reason why we need to allow trait objects in the first place? If you drop the ?Sized requirement then a *const T will always be a plain pointer, which is perfectly fine to cast to *const ().
A while back, I wrote an article where we try to do something similar to your AnyPointer - erase a value's type at runtime and try to use its methods or downcast it back to the original T. It doesn't directly answer your question, but maybe it'll give you some inspiration or tricks you can borrow.
Sorry, my library is planning to available in stable rust, so to_raw_parts cannot be adopted, and pointer of trait object needed to be supported, so T cannot be required to be sized. I'm not an English speaker, reading a long article written in English is a bit difficult for me now. I'll try to read it later.
I found the length of fat pointers is always the same, and so are thin pointers. So I think I can do this:
There's no guarantees on the layout of wide pointers, or that the layout is the same between different types. Rust may also some day allow wide pointers of arbitrary size / custom DST metadata.