futures_executor/
enter.rs

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