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
use std::prelude::v1::*; use std::cell::Cell; use std::fmt; thread_local!(static ENTERED: Cell<bool> = Cell::new(false)); /// Represents an executor context. /// /// For more details, see [`enter` documentation](enter()). pub struct Enter { _a: () } /// An error returned by `enter` if an execution scope has already been /// entered. #[derive(Debug)] pub struct EnterError { _a: (), } /// Marks the current thread as being within the dynamic extent of an /// executor. /// /// Executor implementations should call this function before beginning to /// execute a tasks, and drop the returned [`Enter`](Enter) value after /// completing task execution: /// /// ``` /// use futures::executor::enter; /// /// let enter = enter().expect("..."); /// /* run task */ /// drop(enter); /// ``` /// /// Doing so ensures that executors aren't /// accidentally invoked in a nested fashion. /// /// # Error /// /// Returns an error if the current thread is already marked, in which case the /// caller should panic with a tailored error message. pub fn enter() -> Result<Enter, EnterError> { ENTERED.with(|c| { if c.get() { Err(EnterError { _a: () }) } else { c.set(true); Ok(Enter { _a: () }) } }) } impl fmt::Debug for Enter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Enter").finish() } } impl Drop for Enter { fn drop(&mut self) { ENTERED.with(|c| { assert!(c.get()); c.set(false); }); } }