I want to convert a Vec
to a Vec
where T
is a primitive of some sort and U
is a newtype of T
According to the documentation of std::mem::transmute(), using Vec::from_raw_parts
combined with ManuallyDrop
is the best option, as of Rust 1.38:
let v_from_raw = unsafe {
// Ensure the original vector is not dropped.
let mut v_clone = std::mem::ManuallyDrop::new(v_orig);
Vec::from_raw_parts(v_clone.as_mut_ptr() as *mut U,
v_clone.len(),
v_clone.capacity())
};
The prerequisite for this is that T
and U
have the same size, the same minimum alignment and that all bit patterns that are valid for T
are also valid for U
. If you define T
and U
as in your question, you don't have a guarantee for this.
struct U(T)
defines a tuple struct, and the memory layout of such a struct is completely undefined. However, it is possible to force the memory representations to be identical by using the transparent representation:
#[repr(transparent)]
struct U(T);
Nightly Rust has Vec::into_raw_parts, which reduces the amount of code and places to go wrong:
#![feature(vec_into_raw_parts)]
fn convert_using_into_raw_parts(v: Vec<T>) -> Vec<U> {
let (ptr, len, cap) = v.into_raw_parts();
unsafe { Vec::from_raw_parts(ptr as *mut U, len, cap) }
}
There's also an open RFC Collection Transmute #2756 which proposes adding a Vec::transmute
method.
You cannot change the type of a value in place in safe Rust. There is no guarantee that the two types will have the same size or the same semantics.
This applies to a single value (T
-> U
) as well as aggregate values (Vec<T>
-> Vec<U>
, HashMap<K1, V1>
-> HashMap<K2, V2>
). Note that aggregate values are really just a special case of "single" values.
The best thing to do is to create a new vector:
let buffer2 = buffer.into_iter().map(Foo).collect();
You could also adjust do_something_using_foo
to take in a common generic type that both Foo
and u32
implement:
use std::borrow::{Borrow, BorrowMut};
#[derive(Debug, Clone)]
struct Foo(u32);
impl Borrow<u32> for Foo {
fn borrow(&self) -> &u32 {
&self.0
}
}
impl BorrowMut<u32> for Foo {
fn borrow_mut(&mut self) -> &mut u32 {
&mut self.0
}
}
fn do_something_using_foo<T>(buffer: &mut [T])
where
T: BorrowMut<u32>,
{
}
fn main() {
let mut buffer_u32 = vec![0u32; 100];
let mut buffer_foo = vec![Foo(0); 100];
do_something_using_foo(&mut buffer_u32);
do_something_using_foo(&mut buffer_foo);
}
In unsafe Rust, it is technically possible — you can shoot yourself in the foot as much as you'd like.
You can use something like std::mem::transmute if you know what you are doing.
However, it's undefined behavior to use transmute
with Vec
as the representation of Vec
is not defined. Instead, see Sven Marnach's answer.
See also: