Hi,
Assuming we have 2 simple wrappers on some type (new type pattern):
Full example here: demo
struct W1<T>(T);
struct W2<T>(T);
I assume converting from W1<_> to W2<_> is zero cost?
pub fn w1_to_w2<T>(a: W1<T>) -> W2<T> {
W2(a.0)
}
But my problem is converting Arc<W1<T>> to Arc<W2<T>> because I also want it to be safe and zero-cost, meaning - no extra allocation, no extra copy/clone.
From the documentation of Arc I found the solution (in unsafe RUST) with using of from_raw / into_raw:
pub fn arc_w1_to_arc_w2<T>(a: Arc<W1<T>>) -> Arc<W2<T>>
{
let a_ptr = Arc::into_raw(a);
unsafe {
let a = Arc::from_raw(a_ptr as *const W2<T>);
return a;
}
}
Q1: Is this code above safe?
Do I need to mark these wrappers W1/W2 with some #[repr(C)] to make sure size/allignment is identical for the same T?
[Question about Drop]
I notice that implementing Drop for W1<T> does not block this moving, probably this is some kind of UB, but "MIRI" does not complain?
Modified example demo with Drop
I mean
#[repr(transparent)]
pub struct W1<T>(T);
#[repr(transparent)]
pub struct W2<T>(T);
impl<T> Drop for W1<T> {
fn drop(&mut self) {
println!("Dropping W1");
}
}
Then this code does not show "Dropping W1" when uncommenting lines with b:
fn main() {
let a = Arc::new(W1(123_u16));
let b = clone_arc_w1_to_arc_w2(&a);
assert_eq!(b.0, 123);
assert_eq!(a.0, 123);
drop(b);
println!("ok");
}
pub fn clone_arc_w1_to_arc_w2<T>(a: &Arc<W1<T>>) -> Arc<W2<T>>
{
let a_ptr = Arc::as_ptr(a);
unsafe {
let a = Arc::from_raw(a_ptr as *const W2<T>);
return a;
}
}
Of course this is pure theoretical problem - I do not plan to implement Drop for my wrapper types.