we want to turn this:
opaque! {
struct Foo<'a> {
x: Option<&'a Cell<Foo<'a>>>,
y: usize,
}
impl<'a> Drop for Foo<'a> {
fn drop_cell(this: Pin<&'a Cell<Foo<'a>>>) {
let bar = cell_project!(Foo<'_>, this.x);
let inner = bar.get().unwrap();
println!("{:p}", this.get_ref());
println!("{:p}", inner);
println!("{}", cell_project!(Foo<'_>, inner.y).get());
cell_project!(Foo<'_>, inner.y).set(3);
}
}
}
into all this:
struct Foo<'a> {
x: Option<&'a Cell<Foo<'a>>>,
y: usize,
}
#[repr(transparent)]
struct FooOpaque {
// unsafe field: not actually 'static
inner: Foo<'static>,
_pinned: PhantomPinned,
}
impl FooOpaque {
fn new(foo: impl for<'a> FnOnce(&'a ()) -> Foo<'a>) -> Self {
#[allow(unreachable_code)]
fn _prevent_problematic_drop(f: impl for<'x> Fn(&'x ()) -> Foo<'x>) {
let _arg = ();
let _foo: Foo<'_> = f(&_arg);
let _cell = Cell::new(_foo);
#[inline(never)]
fn _f<'a>(_x: &'a Cell<Foo<'a>>) {}
_f(&_cell);
}
Self {
inner: unsafe { std::mem::transmute(foo(&())) },
_pinned: PhantomPinned,
}
}
fn operate_in<F, R>(pinned_cell: Pin<&Cell<Self>>, f: F) -> R
where F: for<'a> FnOnce(Pin<&'a Cell<Foo<'a>>>) -> R {
f(unsafe {
pinned_cell.map_unchecked(|cell_ref| {
std::mem::transmute(cell_project!(FooOpaque, cell_ref.inner))
})
})
}
}
impl Drop for FooOpaque {
fn drop(&mut self) {
unsafe {
// assume it was pinned.
Self::operate_in(std::mem::transmute(self), |cell_ref| {
fn drop_cell(this: Pin<&'a Cell<Foo<'a>>>) {
let bar = cell_project!(Foo<'_>, this.x);
let inner = bar.get().unwrap();
println!("{:p}", this.get_ref());
println!("{:p}", inner);
println!("{}", cell_project!(Foo<'_>, inner.y).get());
cell_project!(Foo<'_>, inner.y).set(3);
}
drop_cell(cell_ref)
});
}
}
}
but we'd like to do it without a proc macro. is this possible without a proc macro?