You cannot write this struct without unsafe code, and Pin
cannot reduce the amount of unsafe code you need. Here's how you can build the struct without Pin
:
struct S {
buf: *mut [u8],
slice: Option<*const [u8]>,
}
impl Drop for S {
fn drop(&mut self) {
let b = unsafe { Box::from_raw(self.buf) };
drop(b);
}
}
impl S {
pub fn new() -> Self {
let buf = vec![0u8, 1, 2, 3].into_boxed_slice();
let buf_ptr = Box::into_raw(buf);
let slice = Some(buf_ptr as *const [u8]);
S {
buf: buf_ptr,
slice,
}
}
fn buf(&self) -> &[u8] {
unsafe { &*self.buf }
}
fn slice(&self) -> Option<&[u8]> {
unsafe { self.slice.map(|ptr| &*ptr) }
}
}
fn main() {
let s = S::new();
assert_eq!(s.slice().unwrap(), s.buf());
}
You may want to read this post of mine, which explains where Pin
is useful, namely when two pieces of unsafe code need to communicate guarantees through unknown non-unsafe user code. When everything happens in a single module, Pin
does not help you at all, and module privacy can provide all the things you need to write correct (but wildly unsafe) self-referential structs.