1use std::{mem, pin, time};
2
3use dope_core::driver::{
4 self,
5 schedule::{clock, sequence},
6 storage,
7};
8
9use crate::{
10 executor::{
11 self, boot, drive,
12 session::{self, App, Manual, run},
13 },
14 random, shutdown,
15};
16
17pub struct Scope<'scope, 'life: 'scope, 'p: 'life, 'd: 'p, S: storage::Plan + 'd = (), Q = ()> {
18 storage: pin::Pin<&'life S::Output<'p, 'd>>,
19 pub(crate) core: &'scope mut session::Core<'life, 'd, Q>,
20}
21
22const fn assert_layout<'scope, 'life: 'scope, 'p: 'life, 'd: 'p>() {
23 assert!(mem::size_of::<Scope<'scope, 'life, 'p, 'd>>() == mem::size_of::<usize>() * 2);
24 assert!(mem::align_of::<Scope<'scope, 'life, 'p, 'd>>() == mem::align_of::<usize>());
25}
26
27const _: () = assert_layout();
28
29impl<'scope, 'life: 'scope, 'p: 'life, 'd: 'p, S: storage::Plan + 'd, Q>
30 Scope<'scope, 'life, 'p, 'd, S, Q>
31{
32 pub(in crate::executor) fn new(
33 storage: storage::Loan<'life, 'p, 'd, S>,
34 core: &'scope mut session::Core<'life, 'd, Q>,
35 ) -> Self {
36 Self {
37 storage: storage.pinned(),
38 core,
39 }
40 }
41
42 pub(crate) fn reborrow(&mut self) -> Scope<'_, 'life, 'p, 'd, S, Q> {
43 Scope {
44 storage: self.storage,
45 core: &mut *self.core,
46 }
47 }
48
49 pub fn pinned(&self) -> pin::Pin<&'life S::Output<'p, 'd>> {
51 self.storage
52 }
53
54 pub fn storage(&self) -> &'life S::Output<'p, 'd> {
55 self.storage.get_ref()
56 }
57
58 pub fn driver(&mut self) -> driver::Context<'_, 'd> {
59 self.core.scope.context()
60 }
61
62 pub fn hash_state(&mut self, domain: random::Domain) -> random::HashState<'d> {
63 let driver = self.core.scope.context();
64 random::HashState::for_seed(driver.driver_ref().random_seed(), domain)
65 }
66
67 pub fn try_root<P: random::Purpose>(
68 &mut self,
69 ) -> Result<random::Root<'d, P>, sequence::Exhausted> {
70 let driver = self.core.scope.context();
71 random::Root::try_acquire(&driver)
72 }
73
74 pub(crate) fn finish<'report, D>(
75 self,
76 report: &'report mut session::Completion,
77 app: D,
78 ) -> Result<(), session::Error<'report, ()>>
79 where
80 D: executor::raw::App<'d>,
81 Q: executor::Startup,
82 {
83 self.with_run(app, None, report, |scope, report| scope.finish(report, ()))
84 }
85
86 pub fn with_app<'report, D, R>(
87 &mut self,
88 report: &'report mut session::Completion,
89 app: D,
90 f: impl for<'app> FnOnce(App<'app, 'life, 'd, D, Q>) -> R,
91 ) -> session::Result<'report, R>
92 where
93 D: executor::raw::App<'d>,
94 Q: executor::Startup,
95 {
96 self.reborrow()
97 .with_run(app, None, report, |mut scope, report| {
98 let output = f(scope.app());
99 scope.finish(report, output)
100 })
101 }
102
103 pub fn request<'report, D>(
105 &mut self,
106 report: &'report mut session::Completion,
107 app: D,
108 ) -> session::Result<'report, Result<shutdown::Requested<Q>, drive::Error>>
109 where
110 D: executor::raw::App<'d>,
111 Q: executor::Startup,
112 {
113 self.with_app(report, app, |app| session::App::run(app))
114 }
115
116 pub fn run<'report, D>(
117 &mut self,
118 report: &'report mut session::Completion,
119 app: D,
120 ) -> session::Result<'report, Result<(), drive::Error>>
121 where
122 D: executor::raw::App<'d>,
123 Q: executor::Startup,
124 {
125 self.with_app(report, app, |app| app.run().map(|_| ()))
126 }
127
128 pub fn with_quiesce<'report, D, R>(
131 &mut self,
132 report: &'report mut session::Completion,
133 app: D,
134 timeout: time::Duration,
135 f: impl for<'app> FnOnce(App<'app, 'life, 'd, D, Q>) -> R,
136 ) -> session::Result<'report, R>
137 where
138 D: executor::raw::App<'d>,
139 Q: executor::Startup,
140 {
141 use drive::clock::{Bound, wall};
142
143 self.reborrow()
144 .with_run(app, None, report, |mut scope, report| {
145 let output = f(scope.app());
146 scope.finish_for(report, Bound::for_duration(wall(), timeout), output)
147 })
148 }
149
150 pub fn run_quiesce<'report, D>(
152 &mut self,
153 report: &'report mut session::Completion,
154 app: D,
155 timeout: time::Duration,
156 ) -> session::Result<'report, Result<(), drive::Error>>
157 where
158 D: executor::raw::App<'d>,
159 Q: executor::Startup,
160 {
161 self.with_quiesce(report, app, timeout, |app| app.run().map(|_| ()))
162 }
163
164 pub fn with_at_for<'report, D, R>(
168 &mut self,
169 report: &'report mut session::Completion,
170 app: D,
171 start: clock::Deadline<'d>,
172 timeout: time::Duration,
173 f: impl for<'app> FnOnce(Manual<'app, 'life, 'd, D, Q>) -> R,
174 ) -> session::Result<'report, R>
175 where
176 D: executor::raw::App<'d>,
177 Q: executor::Startup,
178 {
179 use drive::clock::{Bound, at};
180
181 self.reborrow()
182 .with_run(app, Some(start), report, |scope, report| {
183 let output = f(Manual {
184 access: session::Access::new(&mut *scope.core, scope.owner.view()),
185 });
186 let now = scope.core.scope.context().driver_ref().clock().now().into();
187 scope.finish_for(report, Bound::for_duration(at(now), timeout), output)
188 })
189 }
190
191 pub(crate) fn drive<R>(&mut self, root: R) -> Result<R::Output, drive::Error>
192 where
193 R: boot::Root<'d>,
194 Q: executor::Startup,
195 {
196 use drive::{block, clock::wall, turn};
197 use turn::scope;
198
199 let core = &mut *self.core;
200 let admitted = core.scope.try_boot();
201 let pending = &mut core.pending;
202 let (_, mut driver, turn) = core.scope.split();
203 let block = scope::Boot::try_new(&mut driver, turn, pending, admitted)
204 .and_then(|state| block::Block::new(state.driver_ref(), state, wall()));
205 block::Block::run_boot(block, root, turn::shutdown(core.lifecycle))
206 }
207
208 fn with_run<'report, D, R>(
210 self,
211 app: D,
212 start: Option<clock::Deadline<'d>>,
213 report: &'report mut session::Completion,
214 run: impl for<'app> FnOnce(
215 run::Run<'app, 'life, 'd, D, Q>,
216 &'report mut session::Completion,
217 ) -> session::Result<'report, R>,
218 ) -> session::Result<'report, R>
219 where
220 D: executor::raw::App<'d>,
221 Q: executor::Startup,
222 {
223 let start = self.core.admit(start).map_err(session::Error::Drive)?;
224 let cell = pin::pin!(executor::raw::Backing::new(self.core.scope.token(), app));
225 let app = cell.as_ref().pin();
226 let owner = {
227 let (token, driver, mut turn) = self.core.scope.split();
228 turn.sample(start);
229 executor::raw::Owner::install(app, token, driver.driver_ref())
230 };
231 let scope = run::Run {
232 core: &mut *self.core,
233 owner,
234 }
235 .publish()
236 .map_err(|(cause, disarm)| session::Error::Install { cause, disarm })?;
237 run(scope, report)
238 }
239}