• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::cell::Cell;
2 use std::fmt;
3 
4 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 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result20     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21         f.debug_struct("EnterError").finish()
22     }
23 }
24 
25 impl fmt::Display for EnterError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result26     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 tasks, 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.
enter() -> Result<Enter, EnterError>55 pub fn enter() -> Result<Enter, EnterError> {
56     ENTERED.with(|c| {
57         if c.get() {
58             Err(EnterError { _priv: () })
59         } else {
60             c.set(true);
61 
62             Ok(Enter { _priv: () })
63         }
64     })
65 }
66 
67 impl fmt::Debug for Enter {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result68     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69         f.debug_struct("Enter").finish()
70     }
71 }
72 
73 impl Drop for Enter {
drop(&mut self)74     fn drop(&mut self) {
75         ENTERED.with(|c| {
76             assert!(c.get());
77             c.set(false);
78         });
79     }
80 }
81