Created
April 24, 2019 02:18
-
-
Save stepancheg/5b38dc6d2dd08afe05ff6cd84a3179f7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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