fn btree__val<T>(a: btree) -> T {
match a {
btree::node1(node1) => unsafe {
std::mem::transmute_copy(&Rc_unwrap_or_clone(node1.val))
}
btree::node2(ref node2) => unsafe {
std::mem::transmute_copy(&Rc_unwrap_or_clone(node2.val)) //node2.val may not have the same type as node1.val
}
_ => unreachable!(),
}
}
I discovered that transmute_copy does copy the data even if there is no need to do that. So, I tried to use transmute instead :
fn btree__val<T:Sized>(a: btree) -> T {
match a {
btree::node1(node1) => unsafe {
std::mem::transmute(Rc_unwrap_or_clone(node1.val)) // example of change
}
btree::node2(ref node2) => unsafe {
std::mem::transmute_copy(&Rc_unwrap_or_clone(node2.val))
}
_ => unreachable!(),
}
}
but I get the following error:
cannot transmute between types of different sizes, or dependently-sized types
source type: `f32` (32 bits)
target type: `T` (this type does not have a fixed size)
that's strange because the size of T is actually known at compile time ! (and in that case we are always transmuting to the same type)
Do you know what causes the error ?
I know it looks like issue 43408; but I don't understand if a solution was found.
It's a generic type parameter. Each generic will have a fixed size (as T: Sized), but each one can have different sizes from one another, and from f32. Nothing is preventing you from calling btree__val::<[u8; 1000000]>(a).
You haven't shared any of the surrounding context, but that transmute is unsound. (Nothing is stopping me from calling btree__val::<&mut String> either, say.)
and I know for sure that T will be the right size.
I know this is unsound, but that's in a broader context of generated code (that I try to optimize), and the transmute is superfluous : it will always be type T to type T, I just put it because I need a generic type.
Additionally, you should generally be using either Cell<f32> (you want to modify the number), Pin<Rc<f32>> (you care about the unique address), or Arc<AtomicF32> (you want to concurrently modify the number) instead of Rc<f32>.
Edit 2: Also, this does not appear to be a btree?
This is a binary tree node, not a B-Tree which would have something more like children: [Option<Rc<btree>>; 6]. Check the standard library's BTreeMap.
Ok thanks, I think I can create different accessors depending on the return type. Yes btree is not a binary tree or a Rust BTree, it's just an example.
I was going off of the types you'd mentioned so far.
However, if you're transmuting from something with padding bytes to something without, you have UB.
More generally, much of the point of bytemuck is being able to do such things without UB, and -- via their derive macros -- even without any of your own unsafe. So if you have to do more than slap #[derive(NoUninit)] (or Pod or whatever) on your data types, such as removing padding bytes, that's a sign that you're probably doing something UB.