1use std::{mem, ops::ControlFlow, pin, task};
2
3use dope_core::driver::{self, result::poll, route, route::indices, schedule, schedule::ready};
4use drive::{clock, turn};
5use schedule::clock::{Moment, Sample};
6use turn::{modes, routes, scope};
7
8use crate::executor::{self, boot, drive, root};
9
10#[must_use = "fixed-point evidence and its root output must be observed"]
12pub struct Fixed<'d, T> {
13 output: T,
14 now: Moment<'d>,
15}
16
17impl<'d, T> Fixed<'d, T> {
18 pub(crate) const fn new(output: T, now: Moment<'d>) -> Self {
19 Self { output, now }
20 }
21
22 pub const fn output(&self) -> &T {
23 &self.output
24 }
25
26 pub fn into_output(self) -> T {
27 self.output
28 }
29
30 pub const fn now(&self) -> Moment<'d> {
31 self.now
32 }
33}
34
35const _: () = {
36 assert!(mem::size_of::<Fixed<'_, ()>>() == mem::size_of::<Moment<'_>>());
37 assert!(mem::align_of::<Fixed<'_, ()>>() == mem::align_of::<Moment<'_>>());
38};
39
40pub(crate) struct Block<'d, T, C> {
41 state: T,
42 source: C,
43 slot: ready::Slot<'d, routes::Wake>,
44}
45
46enum Attempt<R, O> {
47 Complete(Result<O, drive::Error>),
48 Cancel(R, drive::Error),
49}
50
51enum Outcome<O, P> {
52 Complete(O, P),
53 Shutdown(Option<O>),
54}
55
56impl<O, P> Outcome<O, P> {
57 fn complete(self) -> Result<(O, P), drive::Error> {
58 match self {
59 Self::Complete(output, proof) => Ok((output, proof)),
60 Self::Shutdown(_) => Err(drive::Error::Shutdown),
61 }
62 }
63}
64
65impl<R, O> Attempt<R, O> {
66 fn finish<'d>(self) -> Result<O, drive::Error>
67 where
68 R: boot::Root<'d, Output = O>,
69 {
70 match self {
71 Self::Complete(result) => result,
72 Self::Cancel(root, source) => {
73 R::cancel(root);
74 Err(source)
75 }
76 }
77 }
78}
79
80impl<'run, 'driver, 'd, C> Block<'d, scope::Boot<'run, 'driver, 'd>, C>
81where
82 C: clock::Source,
83{
84 pub(crate) fn run_boot<R>(
85 start: Result<Self, drive::Error>,
86 root: R,
87 shutdown: impl FnMut() -> turn::Status,
88 ) -> Result<R::Output, drive::Error>
89 where
90 R: boot::Root<'d>,
91 {
92 match start {
93 Ok(block) => block.poll_boot(root, shutdown),
94 Err(source) => Attempt::Cancel(root, source),
95 }
96 .finish()
97 }
98
99 fn poll_boot<R>(
100 mut self,
101 mut root: R,
102 mut shutdown: impl FnMut() -> turn::Status,
103 ) -> Attempt<R, R::Output>
104 where
105 R: boot::Root<'d>,
106 {
107 let wake = self.slot.target();
108 let (mut polled, output) = {
109 let mut cause = boot::Cause::Start;
110 loop {
111 let tick = self.source.tick();
112 let ready = match self.state.next_root(&self.slot, tick, &mut shutdown) {
113 Ok(ready) => ready,
114 Err(source) => return Attempt::Cancel(root, source),
115 };
116 let polled = if matches!(cause, boot::Cause::Start) || ready.is_root() {
117 let (polled, output) = ready.poll_boot(root, wake, cause);
118 match output {
119 boot::Poll::Pending(next) => {
120 root = next;
121 polled
122 }
123 boot::Poll::Ready(output) => break (polled, output),
124 }
125 } else {
126 ready.skip()
127 };
128 cause = boot::Cause::Wake;
129 let parked = polled.park();
130 match parked.status() {
131 turn::Status::Active => {}
132 turn::Status::Shutdown => return Attempt::Cancel(root, drive::Error::Shutdown),
133 }
134 let idle = match parked.sync() {
135 Ok(Some(idle)) => idle,
136 Ok(None) => continue,
137 Err(error) => return Attempt::Cancel(root, error.into()),
138 };
139 let progress = idle.progress();
140 if let Err(error) = idle.wait(progress, self.source) {
141 return Attempt::Cancel(root, error.into());
142 }
143 }
144 };
145 Attempt::Complete(loop {
146 let parked = polled.park();
147 match parked.status() {
148 turn::Status::Active => {}
149 turn::Status::Shutdown => break Err(drive::Error::Shutdown),
150 }
151 let idle = match parked.sync() {
152 Ok(idle) => idle,
153 Err(error) => break Err(error.into()),
154 };
155 if let Some(idle) = idle {
156 let progress = idle.progress();
157 if matches!(progress, schedule::Progress::Quiescent) {
158 match idle.sync() {
159 Ok(poll::Commit::Drained) => break Ok(output),
160 Ok(poll::Commit::Pending) => {}
161 Err(error) => break Err(error.into()),
162 }
163 } else if let Err(error) = idle.wait(progress, self.source) {
164 break Err(error.into());
165 }
166 }
167 let tick = self.source.tick();
168 polled = match self.state.next_root(&self.slot, tick, &mut shutdown) {
169 Ok(ready) => ready.skip(),
170 Err(error) => break Err(error),
171 };
172 })
173 }
174}
175
176impl<'d, T, C> Block<'d, T, C> {
177 pub(crate) fn new(
178 driver: driver::Reference<'d>,
179 state: T,
180 source: C,
181 ) -> Result<Self, drive::Error> {
182 let target = driver
183 .targets::<routes::Wake>()
184 .bind(indices::SlotIndex::ZERO, route::Epoch::INITIAL);
185 let slot = driver.ready().make_slot(target.dispatch())?;
186 Ok(Self {
187 state,
188 source,
189 slot,
190 })
191 }
192}
193
194impl<'run, 'driver, 'app, 'd: 'app, D, S, C>
195 Block<'d, scope::Scope<'run, 'driver, 'app, 'd, D, S>, C>
196where
197 D: executor::raw::App<'d>,
198 C: clock::Time,
199{
200 pub(crate) fn run<R>(
201 self,
202 root: R,
203 tick: impl Fn(C) -> Result<Sample, drive::Error>,
204 shutdown: impl FnMut() -> turn::Status,
205 ) -> Result<R::Output, drive::Error>
206 where
207 R: root::Root<'d>,
208 {
209 let (output, ()) = self
210 .drive(root, tick, shutdown, |idle| {
211 Ok(matches!(idle.sync()?, poll::Commit::Drained).then_some(()))
212 })?
213 .complete()?;
214 Ok(output)
215 }
216
217 pub(crate) fn run_until<R>(
218 self,
219 root: R,
220 tick: impl Fn(C) -> Result<Sample, drive::Error>,
221 shutdown: impl FnMut() -> turn::Status,
222 ) -> Result<ControlFlow<R::Output>, drive::Error>
223 where
224 R: root::Root<'d>,
225 {
226 Ok(
227 match self.drive(root, tick, shutdown, |idle| {
228 Ok(matches!(idle.sync()?, poll::Commit::Drained).then_some(()))
229 })? {
230 Outcome::Complete(output, ()) | Outcome::Shutdown(Some(output)) => {
231 ControlFlow::Break(output)
232 }
233 Outcome::Shutdown(None) => ControlFlow::Continue(()),
234 },
235 )
236 }
237
238 pub(crate) fn run_fixed<R>(
239 self,
240 root: R,
241 tick: impl Fn(C) -> Result<Sample, drive::Error>,
242 shutdown: impl FnMut() -> turn::Status,
243 ) -> Result<Fixed<'d, R::Output>, drive::Error>
244 where
245 R: root::Root<'d>,
246 {
247 let (output, now) = self
248 .drive(root, tick, shutdown, |idle| {
249 let fixed = idle.is_fixed();
250 let now = idle.now();
251 let commit = idle.sync()?;
252 Ok((fixed && matches!(commit, poll::Commit::Drained)).then_some(now))
253 })?
254 .complete()?;
255 Ok(Fixed::new(output, now))
256 }
257
258 fn drive<R, P>(
259 mut self,
260 root: R,
261 tick: impl Fn(C) -> Result<Sample, drive::Error>,
262 mut shutdown: impl FnMut() -> turn::Status,
263 complete: impl for<'turn> Fn(
264 turn::Idle<'turn, 'd, modes::App<'turn, 'app, 'd, D, S>>,
265 ) -> Result<Option<P>, drive::Error>,
266 ) -> Result<Outcome<R::Output, P>, drive::Error>
267 where
268 R: root::Root<'d>,
269 {
270 let wake = self.slot.target();
271 let (mut polled, output) = {
272 let mut root = pin::pin!(root);
273 let mut first = true;
274 loop {
275 let tick = tick(self.source)?;
276 let ready = self.state.next_root(&self.slot, tick, &mut shutdown)?;
277 let poll = first || ready.is_root();
278 let (polled, output) = if poll {
279 ready.poll(root.as_mut(), wake)
280 } else {
281 (ready.skip(), task::Poll::Pending)
282 };
283 first = false;
284 match output {
285 task::Poll::Ready(output) => break (polled, output),
286 task::Poll::Pending => {
287 let parked = polled.park();
288 match parked.status() {
289 turn::Status::Active => {}
290 turn::Status::Shutdown => return Ok(Outcome::Shutdown(None)),
291 }
292 if let Some(idle) = parked.sync()? {
293 let progress = idle.progress();
294 idle.wait(progress, self.source)?;
295 }
296 }
297 }
298 }
299 };
300 loop {
301 let parked = polled.park();
302 match parked.status() {
303 turn::Status::Active => {}
304 turn::Status::Shutdown => return Ok(Outcome::Shutdown(Some(output))),
305 }
306 if let Some(idle) = parked.sync()?
307 && let Some(proof) = complete(idle)?
308 {
309 return Ok(Outcome::Complete(output, proof));
310 }
311 let tick = tick(self.source)?;
312 polled = self.state.next_app(tick, &mut shutdown)?.skip();
313 }
314 }
315}