1use std::cell::RefCell;
2use std::fmt::Debug;
3use std::sync::{Arc, Mutex};
4use std::mem;
5
6#[derive(Debug)]
7pub struct AutoPopStack<T: Debug> {
8 pub stack: Arc<Mutex<RefCell<Vec<T>>>>,
9}
10
11impl<T: Debug> Clone for AutoPopStack<T> {
12 fn clone(&self) -> Self {
13 AutoPopStack { stack: self.stack.clone() }
14 }
15}
16
17impl<T: Debug> Default for AutoPopStack<T> {
18 fn default() -> Self {
19 Self { stack: Default::default() }
20 }
21}
22
23impl<T: Debug> AutoPopStack<T> {
24 pub fn new() -> Self {
25 Self::default()
26 }
27 pub fn push<Id>(&mut self, id: Id, entry: T) -> AutoPopStackEntry<T, Id> where Id: PartialEq<T> + Debug + Copy {
28 self.stack.lock().unwrap().borrow_mut().push(entry);
29 AutoPopStackEntry::new(id, self.clone())
30 }
31 pub fn peek_mut<U>(&mut self, f: impl FnOnce(Option<&mut T>) -> U) -> U {
32 f(self.stack.lock().unwrap().borrow_mut().last_mut())
33 }
34}
35
36impl<T: Debug + Clone> AutoPopStack<T> {
37 pub fn peek(&self) -> Option<T> {
38 self.stack.lock().unwrap().borrow().last().cloned()
39 }
40}
41
42#[must_use]
48pub struct AutoPopStackEntry<T: Debug, Id=T> where Id: PartialEq<T> + Debug + Copy {
49 id: Id,
50 pub stack: AutoPopStack<T>,
51}
52
53impl<T: Debug, Id: PartialEq<T> + Debug + Copy> AutoPopStackEntry<T, Id> {
54 fn new(id: Id, stack: AutoPopStack<T>) -> Self {
55 Self { id, stack }
56 }
57
58 pub fn id(&self) -> Id { self.id }
59 pub fn make_permanent(self) { mem::forget(self); }
60}
61
62impl<T: Debug, Id: PartialEq<T> + Debug + Copy> Drop for AutoPopStackEntry<T, Id> {
63 fn drop(&mut self) {
64 let top = self.stack.stack.lock().unwrap().borrow_mut().pop();
65 debug_assert_eq!(
66 self.id,
67 top.expect("internal compiler error: tried to pop from empty stack"),
68 "internal compiler error: popped incorrect value"
69 );
70 }
71}