1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
#![feature(fnbox)]

use std::collections::VecDeque;
use std::cell::UnsafeCell;

pub struct DequeCell<T>(UnsafeCell<VecDeque<T>>);

impl<T> DequeCell<T> {
	pub fn new() -> Self {
		DequeCell(UnsafeCell::new(VecDeque::new()))
	}
	fn inner(&self) -> &mut VecDeque<T> {
		unsafe { &mut *self.0.get() }
	}
	pub fn push_back(&self, t: T) {
		self.inner().push_back(t);
	}
	pub fn push_front(&self, t: T) {
		self.inner().push_front(t);
	}
	pub fn pop_back(&self) -> Option<T> {
		self.inner().pop_back()
	}
	pub fn pop_front(&self) -> Option<T> {
		self.inner().pop_front()
	}
	pub fn len(&self) -> usize {
		self.inner().len()
	}
	pub fn capacity(&self) -> usize {
		self.inner().capacity()
	}
	pub fn reserve(&self, additional: usize) {
		self.inner().reserve(additional);
	}
	pub fn reserve_exact(&self, additional: usize) {
		self.inner().reserve_exact(additional);
	}
	pub fn is_empty(&self) -> bool {
		self.inner().is_empty()
	}
	pub fn clear(&self) {
		self.inner().clear();
	}
	pub fn drain(&self) -> Drain<T> {
		Drain { inner: self }
	}
}

pub struct Drain<'a, T: 'a> {
    inner: &'a DequeCell<T>,
}

impl<'a, T: 'a> Iterator for Drain<'a, T> {
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        self.inner.pop_front()
    }
}


#[cfg(test)]
mod tests {
	use super::DequeCell;
	use std::boxed::FnBox;
	
	struct Context<T> {
		actions: DequeCell<Box<FnBox(&mut Context<T>)>>,
		data: T,
	}
	
	impl<T> Context<T> {
		fn drain(&mut self) {
			while let Some(action) = self.actions.pop_front() {
				action.call_box((self,));
			}
		}
		fn new(data: T) -> Self {
			Context { actions: DequeCell::new(), data: data }
		}
	}
	
	#[test]
	fn interleaved_access() {
		let mut c = Context::new(0);
		
		
		c.actions.push_back(Box::new(|c: &mut Context<i32>| {
			assert!(c.data == 0);
			c.data += 1;
			c.actions.push_back(Box::new(|c: &mut Context<i32>| {
				assert!(c.data == 2);
				c.data += 1;
			}));
		}));
		c.actions.push_back(Box::new(|c: &mut Context<i32>| {
			assert!(c.data == 1);
			c.data += 1;
		}));
			
		c.drain();
		assert!(c.data == 3);
	}
}