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}