I was creating a graph structure in C++, and realized that the reinterpret_cast
I was going to use was undefined behavior. I was wandering if the same would also be UB in Rust.
So! I have a Vec<data>
, and I wanted to store indexes externally (so the data can freely be moved in memory without invalidating references. To be more precise, I have multiple vec, each of them storing a different types. To add some safeguards, I added a tag type, to know which vector I want to index. For this, I created a Handle<Tag>
class.
struct Handle<Tag> {
index: usize,
phantom: std::marker::PhantomData<Tag>,
}
Those handles are themselves stored in another container. I’m using char
for the type of the data and Vec
for the collection that store the handles, but in my C++ code, it was more complex.
struct A {
data: Vec<char>, // can be more complicated than just `char`
indexes: Vec<Handle<A>>, // could be stored in a `HashMap` instead
}
// impl Index<Handle<A>> for A
Then I’m transforming the data encapsulated in A
which generate a new struct:
struct B {
data: Vec<char>, // the type may have change after the transformation
indexes: Vec<Handle<B>>,
}
// impl Index<Handle<B>> for B
The order of the elements inside data
is kept during the transformation. This means that transforming A::indexes
into B::indexes
mean creating a new vector that will contains exactly the same values.
fn some_transformation(data: Vec<char>) -> Vec<char> {
data
}
let a = A {
data: vec!['a', 'b', 'c'],
indexes: vec![Handle::new(1), Handle::new(2)]
};
let b = B {
data: some_transformation(a.data),
indexes: a.indexes
.iter()
.map(|handle| Handle::new(handle.index)) // copy the value of the handle
.collect(),
};
assert_eq!(b.data[b.indexes[0].index], 'b');
Is the following optimization valid or totally UB?
let b = B {
data: some_transformation(a.data),
indexes: unsafe {
std::mem::transmute(a.indexes)
},
};