I have some Vec<u8>
with every u8
a surely ascii, but I get scared to transmute Vec<Vec<u8>>
to Vec<String>
, because I know #[repr(Rust)]
may mess up the original order of Vec<T>
(really?), or if there are any other constraints in transmute
that I could have violated?
More specifically, is there a formal documentation showing when will #[repr(rust)]
reorder the data field? I know Vec<T>
occupies exactly 3 * usize
bytes without any hole, but still not sure about it.
If you just do my_vec_of_vecs.into_iter().map(|v| unsafe { String::from_utf8_unchecked(v) }).collect::<Vec<_>>()
the compiler will hopefully optimize it down to nothing, and you don't have to worry about transmute
.
Since there are no guarantees about the order of fields in #[repr(rust)]
structs, there's nothing guaranteeing that Vec<T>
and Vec<U>
have the same field order even if T
and U
have the same layout. However, you could get around this by using Vec::from_raw_parts
instead of transmute
to convert between them:
pub unsafe fn convert(mut v: Vec<Vec<u8>>) -> Vec<String> {
Vec::from_raw_parts(
v.as_mut_ptr().cast(),
v.len(),
v.capacity(),
)
}
(Strictly speaking, I don't think there's any documented guarantee that String
has the same layout as Vec<u8>
. However, there are guarantees about String representation and Vec representation. Combined with the existence of String::as_mut_vec
, these guarantees imply that String
must have the same layout as Vec<u8>
.)
Thanks! But I find that your convert
makes a dangling pointer.
I think it should be like the following?
pub unsafe fn convert(v: Vec<Vec<u8>>) -> Vec<String> {
let mut wrapper = ManuallyDrop::new(v);
Vec::from_raw_parts(
wrapper.as_mut_ptr().cast(),
wrapper.len(),
wrapper.capacity(),
)
}
Yes, good catch.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.