Say you have a slice of Boxes. Practically speaking, in terms of memory layout, a Box is a pointer or a fat pointer. A ref is the same thing.
So if you take that initial slice, and convert it to a list of refs (because that's what a function wants), from a memory content perspective, you end up with the same thing.
That is:
use libc;
fn main() {
let array = [Box::new(42u32), Box::new(21)];
let array2: Vec<&u32> = array.iter().map(|x| &**x).collect();
println!("{}", unsafe { libc::memcmp(array.as_ptr() as _, array2.as_ptr() as _, 8) });
}
prints 0 (no difference).
That intermediate Vec is, however, rather a waste of time and space. So, you'd theorize that you can probably transmute to get what you want... and it actually works:
fn main() {
let array = [Box::new(42u32), Box::new(21)];
let array: &[&u32] = unsafe { std::mem::transmute(&array[..]) };
println!("{:?}", array);
}
miri is even happy about it. But here's the question: is it a shortcoming of miri or is it legitimately not UB?
Going even further, is it still valid for fat pointers?
fn main() {
let array = [String::from("hello").into_boxed_str(), String::from("world").into_boxed_str()];
let array: &[&str] = unsafe { std::mem::transmute(&array[..]) };
println!("{:?}", array);
}
Again, miri is happy about it. But is it legitimate?
Edit: and if it's definitely not UB, should the standard library provide it as a supported thing? I've had to do the "collect refs in a temporary Vec" thing too many times.