I'm trying to write a function to determine whether a Box<T> and *const U point to the same thing, but in a context where T & U: ?Sized (psuedo-code). All I care about is the pointed-to-addresses being equal or not.
Reading online it seems like using std::ptr::eq is a no go, because for fat pointers it checks both the data pointer and vtable pointer for equality, and vtable addresses aren't stable (see https://github.com/rust-lang/rust/issues/69757).
But, all that matters is whether the data addresses match, I don't care about the vtable or the type of the pointer. So I was wondering if anyone could help clear up 2 things for me : v)
Is it always safe to transmute a fat pointer to a (usize, usize), and will they always be in the order of (data, vtable) when dealing with DSTs? (and outside of const contexts).
Is there a better way to perform such a check without transmuting? All of this sounds pretty reasonable in my head but so have lots of other bad ideas! Somewhere along this rabbit hole someone used something special like *const () to thin-ify the pointer and discard it's typing or something, but I can't seem to find where I saw that, and trying to search "const ()" is... difficult...
Anyways! Thanks for any help, and feel free to lambaste any of the insanities my question is predicated on!!
Just do a cast pointer as *const () (or pointer.cast::<()>() should do the same) for both pointers, and compare the resulting pointers. It doesn't need to be a *const () specifically, casting e g. as *const u8 works just as well. Really, for comparing the addresses the type does not matter very much.
(Using transmute the way you described would likely result in undefined behavior, or at least in relying on unstable layout of types, so compilation could become UB or could at least break with future compiler versions.)
Well now I just feel dumb
I thought there was some special syntactical magic around *const (), I didn't realize it was literally just the unit type!
or at least in relying on unstable layout of types
I figured the transmute was the wrong way to go, but was curious about whether the layout of DST pointers was considered 'stable' or just an implementation detail. Good to know it's the former!
Anyways, thanks for the information and recommendation!! I guess I'll go with the *const () even though like you say it shouldn't really matter. Hopefully it'll better signal that the types are completely irrelevant here.
Thanks, I'll always take any additional information I can get!
Buttttt, I'm afraid you already guessed my response
The actual type bound is T: Element + ?Sized, where Element is an internal trait implemented by a handful of structs.
None of these structs are zero-sized, contain slices, or one another (so no leading field concern). So they should skirt the edge concerns you list, but if there's one I've overlooked; like I said, I'll always appreciate information!