sim_lib_control/
resume.rs1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
3pub struct FrameLimits {
4 pub depth: usize,
6 pub work: usize,
8}
9
10#[derive(Clone, Debug, PartialEq, Eq)]
12pub enum ResumePacket<T, E> {
13 Start,
15 Send(T),
17 Throw(E),
19 Close,
21}
22
23#[derive(Clone, Debug, PartialEq, Eq)]
25pub enum ResumeResult<T, R, E> {
26 Yielded(T),
28 Returned(R),
30 Failed(E),
32}
33
34#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub enum FrameError {
37 NotStarted,
39 AlreadyStarted,
41 AlreadyComplete,
43 DepthExhausted,
45 WorkExhausted,
47}
48
49#[derive(Clone, Copy, Debug, PartialEq, Eq)]
51pub struct StepBudget {
52 depth_left: usize,
53 work_left: usize,
54}
55
56impl StepBudget {
57 pub fn charge_work(&mut self) -> Result<(), FrameError> {
59 self.work_left = self
60 .work_left
61 .checked_sub(1)
62 .ok_or(FrameError::WorkExhausted)?;
63 Ok(())
64 }
65
66 pub fn enter(&mut self) -> Result<(), FrameError> {
68 self.depth_left = self
69 .depth_left
70 .checked_sub(1)
71 .ok_or(FrameError::DepthExhausted)?;
72 Ok(())
73 }
74
75 pub fn leave(&mut self) {
77 self.depth_left = self.depth_left.saturating_add(1);
78 }
79}
80
81pub struct ResumableFrame<D> {
83 driver: D,
84 limits: FrameLimits,
85 started: bool,
86 complete: bool,
87}
88
89impl<D> ResumableFrame<D> {
90 pub fn new(limits: FrameLimits, driver: D) -> Self {
92 Self {
93 driver,
94 limits,
95 started: false,
96 complete: false,
97 }
98 }
99
100 pub fn is_complete(&self) -> bool {
102 self.complete
103 }
104
105 pub fn resume<T, R, E>(
107 &mut self,
108 packet: ResumePacket<T, E>,
109 ) -> Result<ResumeResult<T, R, E>, FrameError>
110 where
111 D: FnMut(ResumePacket<T, E>, &mut StepBudget) -> Result<ResumeResult<T, R, E>, FrameError>,
112 {
113 if self.complete {
114 return Err(FrameError::AlreadyComplete);
115 }
116 match (&packet, self.started) {
117 (ResumePacket::Start, true) => return Err(FrameError::AlreadyStarted),
118 (ResumePacket::Start, false) => self.started = true,
119 (_, false) => return Err(FrameError::NotStarted),
120 (_, true) => {}
121 }
122 let mut budget = StepBudget {
123 depth_left: self.limits.depth,
124 work_left: self.limits.work,
125 };
126 let outcome = (self.driver)(packet, &mut budget)?;
127 self.complete = !matches!(outcome, ResumeResult::Yielded(_));
128 Ok(outcome)
129 }
130}