I realize this is something of an obscure thing to want to do, but sometimes it's somewhat helpful to be able to store a value in a c library via ffi, and then make a callback to a rust function from c.
In these circumstances I've found situations where I want to have an owned pointer which is stored as a mut * c_void.
You can store a value in C using this method along with forget(), and you can relatively easily resurrect it as a mut * T on the other side, but it's useful to be able to move out of the unsafe pointer and back into 'safe' rust space in this situation.
However, the compiler will always complain about moving the reference out of a & pointer.
Is there a special way around that, to unsafely convert a &T or *T into a ~T?
That may be a little unclear, so here's a tangible example:
extern crate libc;
use libc::c_void;
use std::ops::Drop;
use std::intrinsics::forget;
struct Foo { x: int }
impl Drop for Foo {
fn drop(&mut self) {
println!("We discarded our foo thanks!");
}
}
fn main() {
let mut x = ~Foo { x: 10 };
let mut y = & mut *x as * mut Foo;
println!("Address Y: {:x}", y as uint);
let mut z = y as * mut c_void;
println!("Address Z: {:x}", z as uint);
// Forget x so we don't worry about it
unsafe { forget(x); }
// This would normally happen inside the ffi callback where
// the ffi code discards the void * it was holding and returns it.
unsafe {
let mut res_z = z as * mut Foo;
println!("Ressurected Z: {:x}", z as uint);
let mut res_y = & mut (*res_z);
println!("Ressurected Y: {:x}", y as uint);
let mut res_x:~Foo = ~(*res_y);
}
}
That final line won't compile because:
test.rs:34:28: 34:34 error: cannot move out of dereference of `&mut`-pointer
test.rs:34 let mut res_x:~Foo = ~(*res_y);
If you remove that line the destructor is never invoked; I'm looking for a way to move that memory block back into the 'safe' rust zone and have it collected correctly when the block scope ends.
edit: I suspect swap() is the way to do this, but the exact semantics of doing it right without leaking are still a bit obscure to me. For example in https://gist.github.com/shadowmint/11361488 a ~Foo leaks; the destructor is invoked for the forgotten ~Foo, but instead we leak the local ~Foo created in tmp. :/