Skip to content

Instantly share code, notes, and snippets.

@Sgeo
Last active February 28, 2016 19:33
Show Gist options
  • Save Sgeo/87e24d8cd798abc8deb4 to your computer and use it in GitHub Desktop.
Save Sgeo/87e24d8cd798abc8deb4 to your computer and use it in GitHub Desktop.
use std::rc::{Rc, Weak};
use std::cell::RefCell;
pub struct Scope<'t, T: 't> {
filled: bool,
hole: &'t mut T
}
impl<'t, T: 't> Scope<'t, T> {
unsafe fn new(mut_ref: &'t mut T) -> (T, Self) {
use std::ptr;
(ptr::read(mut_ref), Scope { filled: false, hole: mut_ref })
}
}
pub struct Hole<'t, T: 't> {
scope: Weak<RefCell<Scope<'t, T>>>,
}
impl<'t, T> Drop for Scope<'t, T> {
fn drop(&mut self) {
if !self.filled {
panic!("Unfilled hole!");
}
}
}
impl<'t, T: 't> Hole<'t, T> {
fn new(scope: Weak<RefCell<Scope<'t, T>>>) -> Self {
Hole { scope: scope }
}
fn fill(self, t: T) {
use std::ptr;
let scope_option_rc = self.scope.upgrade();
let scope_rc = scope_option_rc.expect("A Hole's Scope was destructed. Should be impossible?");
let mut scope_mut = scope_rc.borrow_mut();
unsafe {
use std::ops::DerefMut;
ptr::write(scope_mut.deref_mut().hole, t);
}
scope_mut.filled = true;
}
}
unsafe fn create_scope_hole_t<'t, T: 't>(mut_ref: &'t mut T) -> (Rc<RefCell<Scope<'t, T>>>, Hole<'t, T>, T) {
let (t, scope) = Scope::new(mut_ref);
let scope_ref = Rc::new(RefCell::new(scope));
let hole = Hole::new(Rc::downgrade(&scope_ref));
(scope_ref, hole, t)
}
macro_rules! take_mut {
($into:pat, $hole:pat = $mut_ref:expr) => {
let (_scope, $hole, $into) = unsafe { create_scope_hole_t($mut_ref) };
}
}
fn main() {
#[derive(Debug)]
struct Foo;
#[derive(Debug)]
struct Bar {
a: Foo,
b: Foo
}
let mut bar = Bar { a: Foo, b: Foo };
{
take_mut!(a, a_hole = &mut bar.a);
take_mut!(b, b_hole = &mut bar.b);
a_hole.fill(Foo);
b_hole.fill(Foo);
}
println!("{:?}", &bar);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment