Skip to content

Instantly share code, notes, and snippets.

@arielb1
Last active August 29, 2015 14:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arielb1/5eb299a87546ce8829b3 to your computer and use it in GitHub Desktop.
Save arielb1/5eb299a87546ce8829b3 to your computer and use it in GitHub Desktop.
Working Scope implementation
use std::cell::RefCell;
use std::mem;
struct Destructor<'a> {
next: Option<Box<Destructor<'a>>>,
dtor: Box<FnMut() + 'a>
}
struct Scope<'a> {
at_exit: RefCell<Option<Box<Destructor<'a>>>>
}
pub fn with_scope<T, F: for<'a,'b> FnOnce(&'b Scope<'a>) -> T>(f: F) -> T {
let s = Scope { at_exit: RefCell::new(None) };
let result = f(&s);
drop(s);
result
}
impl<'a> Scope<'a> {
fn register(&self, a: Box<FnMut()+'a>) {
let mut inner = self.at_exit.borrow_mut();
let cur = inner.take();
*inner = Some(Box::new(Destructor {
next: cur,
dtor: a
}));
}
}
impl<'a> Drop for Scope<'a> {
fn drop(&mut self) {
// ensure self gets dropped again if a dtor panics
let mut self_copy = mem::replace(self,
Scope { at_exit: RefCell::new(None) });
if self_copy.at_exit.borrow().is_none() {
unsafe { mem::forget(self_copy) }
return; // Avoid infinite recursion
}
// Work around #14875
fn drop_internal<'a>(self_copy: &mut Scope<'a>) {
loop {
let mut dtor_;
let mut iref = self_copy.at_exit.borrow_mut();
if let Some(b) = iref.take() {
let b = *b;
*iref = b.next;
dtor_ = b.dtor;
} else {
return;
}
dtor_();
}
}
drop_internal(&mut self_copy);
}
}
fn main() {
use std::thread;
thread::spawn(|| {
with_scope(|s| {
let z = 0;
s.register(Box::new(|| println!("Dtor: 0")));
1/z;
})
});
thread::spawn(|| { with_scope(|s| {
s.register(Box::new(|| println!("Dtor: 1")));
s.register(Box::new(|| panic!()));
s.register(Box::new(|| println!("Dtor: 2")));
});
});
thread::sleep_ms(1000);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment