Skip to content

Instantly share code, notes, and snippets.

@stepancheg
Created April 24, 2019 02:18
Show Gist options
  • Save stepancheg/5b38dc6d2dd08afe05ff6cd84a3179f7 to your computer and use it in GitHub Desktop.
Save stepancheg/5b38dc6d2dd08afe05ff6cd84a3179f7 to your computer and use it in GitHub Desktop.
use std::mem;
use std::pin::Pin;
use std::ops::DerefMut;
/// Self-referential struct
struct SelfRef<A, B>
where B: ?Sized, A: DerefMut, A::Target: Unpin,
{
/// Holds a pointer of type A
owner: Pin<A>,
/// A subview of that pointer is stored here
reference: *mut B,
}
impl<A, B> SelfRef<A, B>
where B: ?Sized, A: DerefMut, A::Target: Unpin,
{
/// Construct a new self-referential struct and update a reference
fn new<F>(mut owner: Pin<A>, init: F) -> SelfRef<A, B>
where F: for<'a> FnOnce(&'a mut A::Target) -> &'a mut B
{
SelfRef {
reference: init(owner.deref_mut()) as *mut B,
owner,
}
}
fn update_reference<F>(&mut self, f: F)
where F: for<'a> FnOnce(&'a mut A::Target) -> &'a mut B
{
// TODO: not panic safe
self.reference = f(self.owner.deref_mut()) as *mut B;
}
fn get_reference(&mut self) -> &mut B {
unsafe { mem::transmute(self.reference) }
}
}
fn main() {
{
// Self-referential struct holds a box of vec and a mutable slice to that vec
let mut p: SelfRef<Box<Vec<u32>>, [u32]> = SelfRef::new(Box::pin(Vec::<u32>::new()), |v| &mut v[..]);
assert_eq!(0, p.get_reference().len());
// Can update a pointer, but must also update a reference
p.update_reference(|v| { v.extend(10..20); &mut v[..] });
p.update_reference(|v| &mut v[3..]);
assert_eq!(13, p.get_reference()[0]);
}
{
let mut vec = Vec::new();
// Self-referential struct holds a &mut vec and a mutable subslice from that vec
let mut p: SelfRef<&mut Vec<u32>, [u32]> = SelfRef::new(Pin::new(&mut vec), |v| &mut v[..]);
assert_eq!(0, p.get_reference().len());
// Can update a pointer, but must also update a reference
p.update_reference(|v| { v.extend(10..20); &mut v[..] });
p.update_reference(|v| &mut v[3..]);
assert_eq!(13, p.get_reference()[0]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment