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
use std::num::NonZeroUsize;
use crate::{
SimCx, SimCxl,
event::Event,
executor::{spawn_task_on_node, start_node, stop_node},
simulator::for_all_simulators,
};
/// A unique identifier for a node within a simulation.
#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NodeId(pub(crate) NonZeroUsize);
impl NodeId {
pub const INIT: Self = NodeId::from_index(0);
/// Create a new node that tasks can be run on.
///
/// Can only be called from within a simulation.
pub fn create_node() -> NodeId {
SimCx::with(|cx| {
let id = cx.with_cx(|cxl| {
let id = cxl.executor.push_new_node();
cxl.event_handler.handle_event(Event::NodeSpawned(id));
id
});
cx.node_scope(id, || {
for_all_simulators(cx, true, |s| {
s.create_node();
});
});
id
})
}
#[cfg(feature = "emit-tracing")]
pub(crate) fn tv(&self) -> impl tracing::Value {
self.0.get()
}
/// Spawn a task on this node and detach it.
pub fn spawn<F: Future + 'static>(self, future: F) {
spawn_task_on_node(self, future).detach();
}
/// Returns the id of the node this task is running on.
///
/// Can only be called from within a simulation.
pub fn current() -> Self {
SimCx::with(|cx| cx.current_node())
}
/// Invoke Simulator::stop on all simulators and stop all tasks on this node.
///
/// Attempting to spawn tasks on a stopped node will panic.
/// Attempting to stop a node that is already stopped does nothing.
pub fn stop(self) {
stop_node(self, false);
}
/// Invoke Simulator::start on all simulators and allow spawning of new tasks on the node.
///
/// This reverses the effects of [Self::stop].
/// Attempting to start a node that is already running does nothing.
/// New nodes start out in the running state.
///
/// Attempting to start a node after it has been stopped as the result of the entire simulation stopping will panic.
pub fn start(self) {
start_node(self);
}
/// Iterate over all nodes in the current simulation.
///
/// If new nodes are added while this iterator exists, panics may occur or they may or may not be returned.
pub fn all() -> impl Iterator<Item = NodeId> {
(0..SimCxl::with(|cx| cx.executor.node_count())).map(NodeId::from_index)
}
pub(crate) const fn from_index(index: usize) -> Self {
NodeId(NonZeroUsize::new(index + 1).unwrap())
}
pub(crate) const fn to_index(self) -> usize {
self.0.get() - 1
}
}