pure_stage/simulation/
blocked.rs1use std::fmt;
16
17use crate::{Effect, Instant, Name};
18
19#[derive(Debug, PartialEq)]
21pub enum Blocked {
22 Idle,
24 Sleeping { next_wakeup: Instant },
26 Deadlock(Vec<SendBlock>),
28 Breakpoint(Name, Effect),
30 Busy { external_effects: usize, stages: Vec<Name> },
34 Terminated(Name),
36}
37
38#[derive(Debug, PartialEq)]
39pub struct SendBlock {
40 pub from: Name,
41 pub to: Name,
42 pub is_call: bool,
43}
44
45impl Blocked {
46 #[track_caller]
48 pub fn assert_idle(&self) {
49 match self {
50 Blocked::Idle => {}
51 _ => panic!("expected idle, got {:?}", self),
52 }
53 }
54
55 #[track_caller]
57 pub fn assert_sleeping(&self) -> Instant {
58 match self {
59 Blocked::Sleeping { next_wakeup } => *next_wakeup,
60 _ => panic!("expected sleeping, got {:?}", self),
61 }
62 }
63
64 #[track_caller]
66 pub fn assert_sleeping_until(&self, until: Instant) {
67 match self {
68 Blocked::Sleeping { next_wakeup } => {
69 assert_eq!(*next_wakeup, until);
70 }
71 _ => panic!("expected sleeping until {:?}, got {:?}", until, self),
72 }
73 }
74
75 #[track_caller]
77 pub fn assert_deadlock(&self, names: impl IntoIterator<Item = impl AsRef<str> + fmt::Debug>) {
78 let names = names.into_iter().collect::<Vec<_>>();
79 match self {
80 Blocked::Deadlock(deadlock)
81 if deadlock.iter().all(|send| names.iter().any(|n| name_match(&send.from, n.as_ref()))) => {}
82 _ => panic!("expected deadlock by {:?}, got {:?}", names, self),
83 }
84 }
85
86 #[track_caller]
88 pub fn assert_busy(&self, names: impl IntoIterator<Item = impl AsRef<str> + fmt::Debug>) -> &Self {
89 let names = names.into_iter().collect::<Vec<_>>();
90 match self {
91 Blocked::Busy { stages, .. } if names.iter().all(|n| stages.iter().any(|s| name_match(s, n.as_ref()))) => {}
92 _ => panic!("expected busy by {:?}, got {:?}", names, self),
93 }
94 self
95 }
96
97 #[track_caller]
98 pub fn assert_external_effects(&self, effects: usize) {
99 let Self::Busy { external_effects, .. } = self else {
100 panic!("expected busy state but got {:?}", self);
101 };
102 assert_eq!(*external_effects, effects);
103 }
104
105 #[track_caller]
107 pub fn assert_breakpoint(self, name: impl AsRef<str>) -> Effect {
108 match self {
109 Blocked::Breakpoint(n, eff) if name_match(&n, name.as_ref()) => eff,
110 _ => panic!("expected breakpoint `{}`, got {:?}", name.as_ref(), self),
111 }
112 }
113
114 #[track_caller]
116 pub fn assert_terminated(self, name: impl AsRef<str>) {
117 match self {
118 Blocked::Terminated(n) if name_match(&n, name.as_ref()) => {}
119 _ => panic!("expected terminated `{}`, got {:?}", name.as_ref(), self),
120 }
121 }
122}
123
124fn name_match(name: &Name, given: &str) -> bool {
125 let name = name.as_str();
126 if name == given {
127 return true;
128 }
129 if name.starts_with(given) && name.get(given.len()..).expect("`given` was valid UTF-8").starts_with('-') {
130 return name[given.len() + 1..].parse::<u64>().is_ok();
131 }
132 false
133}