Skip to main content

dope_runtime/executor/session/
app.rs

1use std::{ops, time};
2
3use o3::base::time::Positive;
4
5use crate::{
6    executor::{
7        self, drain,
8        drive::{self, clock},
9        root, session,
10    },
11    shutdown,
12};
13
14/// Live application view scoped to one installed session.
15#[repr(transparent)]
16pub struct App<'app, 'life: 'app, 'd: 'life, D: executor::raw::Layout<'d>, Q = ()> {
17    pub(crate) access: session::access::Access<'app, 'life, 'd, D, Q>,
18}
19
20impl<'app, 'life: 'app, 'd: 'life, D, Q> App<'app, 'life, 'd, D, Q>
21where
22    D: executor::raw::App<'d>,
23    Q: executor::Startup,
24{
25    pub fn drive<R>(&mut self, root: R) -> Result<R::Output, drive::Error>
26    where
27        R: root::Root<'d>,
28    {
29        self.access
30            .reborrow()
31            .drive(clock::wall(), root, drive::tick)
32    }
33
34    pub fn run(self) -> Result<shutdown::Requested<Q>, drive::Error> {
35        self.access.run()?;
36        Ok(shutdown::Requested::new())
37    }
38
39    /// Returns a completed root or the shutdown request after dropping the pending root.
40    /// A root completed in the shutdown turn keeps its output.
41    pub fn drive_until<R>(
42        self,
43        root: R,
44    ) -> Result<ops::ControlFlow<R::Output, shutdown::Requested<Q>>, drive::Error>
45    where
46        R: root::Root<'d>,
47    {
48        Ok(self
49            .access
50            .drive_until(root)?
51            .map_continue(|()| shutdown::Requested::new()))
52    }
53
54    /// Drives one root with a wall-clock deadline, checked between executor turns.
55    /// Each root poll must return to the executor for the deadline to be observed.
56    pub fn drive_for<R>(
57        &mut self,
58        timeout: time::Duration,
59        root: R,
60    ) -> Result<R::Output, drive::Error>
61    where
62        R: root::Root<'d>,
63    {
64        let source = clock::Bound::until(clock::wall(), timeout)?;
65        self.access.reborrow().drive(source, root, drive::timeout)
66    }
67
68    /// Serves until shutdown or the wall-clock deadline, checked between turns.
69    /// Each application transition must return to the executor.
70    pub fn run_for(self, timeout: time::Duration) -> Result<shutdown::Requested<Q>, drive::Error> {
71        self.access.run_for(timeout)?;
72        Ok(shutdown::Requested::new())
73    }
74
75    pub fn run_drain(self, timeout: Positive) -> Result<drain::Report<Q>, drive::Error>
76    where
77        D: executor::raw::Drain<'d>,
78    {
79        let outcome = self.access.run_drain(timeout)?;
80        Ok(drain::Report::new(shutdown::Requested::new(), outcome))
81    }
82
83    /// Returns a completed root, or drains after shutdown once the pending root is dropped.
84    /// A root completed in the shutdown turn keeps its output; the drain timeout starts at shutdown.
85    pub fn drive_drain<R>(
86        self,
87        timeout: Positive,
88        root: R,
89    ) -> Result<ops::ControlFlow<R::Output, drain::Report<Q>>, drive::Error>
90    where
91        D: executor::raw::Drain<'d>,
92        R: root::Root<'d>,
93    {
94        Ok(self
95            .access
96            .drive_drain(timeout, root)?
97            .map_continue(|outcome| drain::Report::new(shutdown::Requested::new(), outcome)))
98    }
99}
100
101impl<'app, 'life: 'app, 'd: 'life, D, Q> ops::Deref for App<'app, 'life, 'd, D, Q>
102where
103    D: executor::raw::Layout<'d>,
104{
105    type Target = session::access::Access<'app, 'life, 'd, D, Q>;
106
107    fn deref(&self) -> &Self::Target {
108        &self.access
109    }
110}
111
112impl<'d, D: executor::raw::Layout<'d>, Q> ops::DerefMut for App<'_, '_, 'd, D, Q> {
113    fn deref_mut(&mut self) -> &mut Self::Target {
114        &mut self.access
115    }
116}