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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use futures::future::{BoxFuture};
use std::thread::*;
///
/// A handle of a process running in a scene
///
/// (A process is just a future, a scene is essentially run as a set of concurrent futures that can be modified as needed)
///
#[derive(Copy, Clone, PartialEq, Eq)]
pub (crate) struct ProcessHandle(pub (super) usize);
///
/// The state of the future that's running a process in a scene
///
pub (crate) enum SceneProcessFuture {
/// The future is not running and is waiting to start
Waiting(BoxFuture<'static, ()>),
/// The future is running on the specified thread
Running(ThreadId),
}
///
/// Data associated with a process in a scene
///
pub (crate) struct SceneProcess {
/// The future for this process (can be None while it's being polled by another thread)
pub (super) future: SceneProcessFuture,
/// Set to true if this process has been woken up
pub (super) is_awake: bool,
/// The threads that should be unparked when the future in this process becomes idle
pub (super) unpark_when_waiting: Vec<Thread>,
}
impl SceneProcessFuture {
///
/// True if the future is waiting to run
///
#[inline]
pub fn is_waiting(&self) -> bool {
matches!(self, SceneProcessFuture::Waiting(_))
}
///
/// True if this future is already running on this thread
///
#[inline]
pub fn is_running_on_this_thread(&self) -> bool {
use std::thread;
match self {
SceneProcessFuture::Running(thread_id) => *thread_id == thread::current().id(),
_ => false,
}
}
///
/// If this process is waiting, marks it as running on the current thread and returns the waiting future
///
/// If the process is not waiting, this will return None
///
#[inline]
pub fn take(&mut self) -> Option<BoxFuture<'static, ()>> {
use std::mem;
use std::thread;
match self {
SceneProcessFuture::Waiting(_) => {
// Swap out the result
let mut result = SceneProcessFuture::Running(thread::current().id());
mem::swap(&mut result, self);
// Convert to an option
if let SceneProcessFuture::Waiting(future) = result { Some(future) } else { unreachable!() }
},
_ => None,
}
}
}
impl Drop for SceneProcess {
fn drop(&mut self) {
// Wake anything that's waiting for this process when it's stopped
self.unpark_when_waiting.drain(..)
.for_each(|thread| thread.unpark());
}
}