pub use futures::executor::block_on; pub use futures::executor::LocalPool; pub use futures::task::LocalSpawnExt; use futures::Future; use std::cell::RefCell; use std::rc::Rc; use std::sync::Arc; use std::sync::Mutex; pub trait TestPool { fn spawn + 'static>(&self, future: F); #[allow(dead_code)] fn block_on + 'static>(&mut self, future: F) -> T; } impl TestPool for LocalPool { fn spawn(&self, future: F) where F: Future + 'static, { self.spawner().spawn_local(future).unwrap(); } fn block_on(&mut self, future: F) -> T where F: Future + 'static, { self.run_until(future) } } /// A mutable slot so asynchronous single-threaded tests can assert /// progress. #[derive(Clone, Debug)] pub struct StateVar(Rc>); #[allow(dead_code)] impl StateVar { pub fn new(init: T) -> Self { Self(Rc::new(RefCell::new(init))) } pub fn set(&self, value: T) { *self.0.borrow_mut() = value; } pub fn borrow(&self) -> std::cell::Ref<'_, T> { self.0.borrow() } pub fn borrow_mut(&self) -> std::cell::RefMut<'_, T> { self.0.borrow_mut() } } #[allow(dead_code)] impl StateVar { pub fn get(&self) -> T { self.0.borrow().clone() } } #[allow(dead_code)] impl StateVar { pub fn default() -> Self { Self::new(Default::default()) } } /// A mutable, atomic slot so asynchronous tests can assert progress. #[derive(Clone, Debug)] // Could use crossbeam::AtomicCell pub struct AtomicVar(Arc>); #[allow(dead_code)] impl AtomicVar { pub fn new(init: T) -> Self { Self(Arc::new(Mutex::new(init))) } pub fn set(&self, value: T) { *self.0.lock().unwrap() = value; } } #[allow(dead_code)] impl AtomicVar { pub fn get(&self) -> T { self.0.lock().unwrap().clone() } }