| 1 | use std::cell::Cell; | 
| 2 | use std::fmt; | 
|---|
| 3 |  | 
|---|
| 4 | std::thread_local!(static ENTERED: Cell<bool> = Cell::new(false)); | 
|---|
| 5 |  | 
|---|
| 6 | /// Represents an executor context. | 
|---|
| 7 | /// | 
|---|
| 8 | /// For more details, see [`enter` documentation](enter()). | 
|---|
| 9 | pub struct Enter { | 
|---|
| 10 | _priv: (), | 
|---|
| 11 | } | 
|---|
| 12 |  | 
|---|
| 13 | /// An error returned by `enter` if an execution scope has already been | 
|---|
| 14 | /// entered. | 
|---|
| 15 | pub struct EnterError { | 
|---|
| 16 | _priv: (), | 
|---|
| 17 | } | 
|---|
| 18 |  | 
|---|
| 19 | impl fmt::Debug for EnterError { | 
|---|
| 20 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|---|
| 21 | f.debug_struct(name: "EnterError").finish() | 
|---|
| 22 | } | 
|---|
| 23 | } | 
|---|
| 24 |  | 
|---|
| 25 | impl fmt::Display for EnterError { | 
|---|
| 26 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|---|
| 27 | write!(f, "an execution scope has already been entered") | 
|---|
| 28 | } | 
|---|
| 29 | } | 
|---|
| 30 |  | 
|---|
| 31 | impl std::error::Error for EnterError {} | 
|---|
| 32 |  | 
|---|
| 33 | /// Marks the current thread as being within the dynamic extent of an | 
|---|
| 34 | /// executor. | 
|---|
| 35 | /// | 
|---|
| 36 | /// Executor implementations should call this function before beginning to | 
|---|
| 37 | /// execute a task, and drop the returned [`Enter`](Enter) value after | 
|---|
| 38 | /// completing task execution: | 
|---|
| 39 | /// | 
|---|
| 40 | /// ``` | 
|---|
| 41 | /// use futures::executor::enter; | 
|---|
| 42 | /// | 
|---|
| 43 | /// let enter = enter().expect( "..."); | 
|---|
| 44 | /// /* run task */ | 
|---|
| 45 | /// drop(enter); | 
|---|
| 46 | /// ``` | 
|---|
| 47 | /// | 
|---|
| 48 | /// Doing so ensures that executors aren't | 
|---|
| 49 | /// accidentally invoked in a nested fashion. | 
|---|
| 50 | /// | 
|---|
| 51 | /// # Error | 
|---|
| 52 | /// | 
|---|
| 53 | /// Returns an error if the current thread is already marked, in which case the | 
|---|
| 54 | /// caller should panic with a tailored error message. | 
|---|
| 55 | pub fn enter() -> Result<Enter, EnterError> { | 
|---|
| 56 | ENTERED.with(|c: &Cell| { | 
|---|
| 57 | if c.get() { | 
|---|
| 58 | Err(EnterError { _priv: () }) | 
|---|
| 59 | } else { | 
|---|
| 60 | c.set(val:true); | 
|---|
| 61 |  | 
|---|
| 62 | Ok(Enter { _priv: () }) | 
|---|
| 63 | } | 
|---|
| 64 | }) | 
|---|
| 65 | } | 
|---|
| 66 |  | 
|---|
| 67 | impl fmt::Debug for Enter { | 
|---|
| 68 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|---|
| 69 | f.debug_struct(name: "Enter").finish() | 
|---|
| 70 | } | 
|---|
| 71 | } | 
|---|
| 72 |  | 
|---|
| 73 | impl Drop for Enter { | 
|---|
| 74 | fn drop(&mut self) { | 
|---|
| 75 | ENTERED.with(|c: &Cell| { | 
|---|
| 76 | assert!(c.get()); | 
|---|
| 77 | c.set(val:false); | 
|---|
| 78 | }); | 
|---|
| 79 | } | 
|---|
| 80 | } | 
|---|
| 81 |  | 
|---|