1use std::{io, marker, pin, process, time};
2
3use dope_core::driver::{self, lifecycle};
4use o3::cell::brand;
5
6use crate::{client, executor, random, run, shutdown};
7
8const APP_SHUTDOWN_DRAIN: time::Duration = time::Duration::from_secs(2);
9
10pub struct Session<'scope, 'd: 'scope, S = (), Q = ()> {
11 storage: pin::Pin<&'d S>,
12 core: &'scope mut Core<'d, Q>,
13 lifecycle: &'scope Q,
14}
15
16pub(super) struct Core<'d, Q> {
17 scope: lifecycle::Scope<'d>,
18 seed: random::Seed,
19 retained_events: crate::Events<'d>,
20 _shutdown: marker::PhantomData<fn(Q) -> Q>,
21}
22
23pub struct Application<'app, 'd: 'app, D, Q = ()> {
24 core: &'app mut Core<'d, Q>,
25 installed: crate::Installed<'app, 'd, D>,
26}
27
28struct AppScope<'app, 'd: 'app, D, Q>
29where
30 D: executor::Application<'d>,
31{
32 core: &'app mut Core<'d, Q>,
33 installed: crate::Installed<'app, 'd, D>,
34}
35
36impl<'app, 'd: 'app, D, Q> AppScope<'app, 'd, D, Q>
37where
38 D: executor::Application<'d>,
39{
40 fn shutdown(&mut self) -> executor::raw::Pending<'app, 'd, D> {
41 let installed = self.installed;
42 let core = &mut *self.core;
43 let completions = &mut core.retained_events;
44 core.scope.with_turn(|token, mut driver, turn| {
45 run::Run::new(&mut driver, installed, token, turn, completions).shutdown()
46 })
47 }
48
49 fn drain(&mut self, pending: &executor::raw::Pending<'app, 'd, D>) -> io::Result<()> {
50 let installed = self.installed;
51 let core = &mut *self.core;
52 let completions = &mut core.retained_events;
53 core.scope.with_turn(|token, mut driver, turn| {
54 run::Run::new(&mut driver, installed, token, turn, completions)
55 .drain_for(APP_SHUTDOWN_DRAIN, pending)
56 })
57 }
58
59 fn finalize(&mut self, pending: executor::raw::Pending<'app, 'd, D>) {
60 let core = &mut *self.core;
61 drop(core.retained_events.take());
62 let (token, finalization) = match core.scope.final_quiescence() {
63 Ok(finalization) => finalization,
64 Err(_) => process::abort(),
65 };
66 let finish = pending.finish(finalization);
67 self.installed.finish(token, finish);
68 }
69
70 fn finish(&mut self) -> io::Result<()> {
71 let pending = self.shutdown();
72 if self.drain(&pending).is_err() {
73 process::abort();
74 }
75 self.finalize(pending);
76 Ok(())
77 }
78}
79
80impl<Q> Drop for Core<'_, Q> {
81 fn drop(&mut self) {
82 drop(self.retained_events.take());
83 if self.scope.final_quiescence().is_err() {
84 process::abort();
85 }
86 }
87}
88
89impl<'scope, 'd: 'scope, S, Q> Session<'scope, 'd, S, Q> {
90 pub(super) fn new(
91 storage: pin::Pin<&'d S>,
92 core: &'scope mut Core<'d, Q>,
93 lifecycle: &'scope Q,
94 ) -> Self {
95 Self {
96 storage,
97 core,
98 lifecycle,
99 }
100 }
101
102 pub fn storage(&self) -> &'d S
105 where
106 S: 'd,
107 {
108 self.storage.get_ref()
109 }
110
111 pub fn driver_access(&mut self) -> driver::Context<'_, 'd> {
155 self.core.scope.context()
156 }
157
158 pub fn hash_state(&mut self, domain: random::Domain) -> random::HashState<'d> {
171 let seed = self.core.seed;
172 seed.bind(self.core.scope.token(), domain)
173 }
174
175 fn token(&mut self) -> &mut brand::Token<'d> {
176 self.core.scope.token()
177 }
178
179 pub fn with_app<D, R>(
183 &mut self,
184 app: D,
185 f: impl for<'app> FnOnce(Application<'app, 'd, D, Q>) -> R,
186 ) -> io::Result<R>
187 where
188 D: executor::Application<'d>,
189 Q: executor::Startup,
190 {
191 let (output, finalized) = {
192 let cell = pin::pin!(brand::Value::new(app));
193 debug_assert!(self.core.retained_events.is_none());
194 let installed = crate::Installed::install(cell.as_ref(), self.token());
195 let mut scope = AppScope {
196 core: &mut *self.core,
197 installed,
198 };
199 self.lifecycle.installed();
200 let output = f(Application {
201 core: &mut *scope.core,
202 installed: scope.installed.reborrow(),
203 });
204 let finalized = scope.finish();
205 (output, finalized)
206 };
207 let reaped = self.core.scope.reap_finalized();
208 if reaped.is_err() {
209 process::abort();
210 }
211 finalized?;
212 Ok(output)
213 }
214
215 pub fn with_provider<O, P, C>(
218 &mut self,
219 owner: O,
220 select: impl for<'borrow> FnOnce(pin::Pin<&'borrow O>) -> pin::Pin<&'borrow P>,
221 composition: C,
222 ) -> C::Output
223 where
224 P: client::Provider<'d>,
225 C: client::Composition<'scope, 'd, S, Q, O, P>,
226 {
227 let mut owner = pin::pin!(owner);
228 let client = P::provide(select(owner.as_ref()), client::Scope::new());
229 let root = client::Anchor::new(owner.as_mut());
230 C::compose(composition, client, root, self)
231 }
232}
233
234impl<'app, 'd: 'app, D, Q> Application<'app, 'd, D, Q>
235where
236 D: executor::Application<'d>,
237{
238 pub fn drive<R>(&mut self, root: R) -> io::Result<R::Output>
239 where
240 R: executor::Root<'d>,
241 {
242 let installed = self.installed;
243 let core = &mut *self.core;
244 let completions = &mut core.retained_events;
245 core.scope.with_turn(|token, mut driver, turn| {
246 run::Run::new(&mut driver, installed, token, turn, completions).block_on(root)
247 })
248 }
249
250 pub fn client<P>(
252 &mut self,
253 select: impl for<'borrow> FnOnce(pin::Pin<&'borrow D>) -> pin::Pin<&'borrow P>,
254 ) -> P::Client<'app>
255 where
256 'd: 'app,
257 P: client::Provider<'d>,
258 {
259 let provider = select(self.installed.borrow_pin(self.core.scope.token()));
260 P::provide(provider, client::Scope::new())
261 }
262
263 pub fn run(&mut self) -> io::Result<shutdown::Requested<Q>> {
264 let installed = self.installed;
265 let core = &mut *self.core;
266 let completions = &mut core.retained_events;
267 core.scope.with_turn(|token, mut driver, turn| {
268 run::Run::new(&mut driver, installed, token, turn, completions).run()
269 })?;
270 Ok(shutdown::Requested::new())
271 }
272}
273
274impl<'d, Q> Core<'d, Q> {
275 pub(super) fn new(scope: lifecycle::Scope<'d>, seed: random::Seed) -> Self {
276 Self {
277 scope,
278 seed,
279 retained_events: None,
280 _shutdown: marker::PhantomData,
281 }
282 }
283}