Skip to main content

dope_runtime/executor/session/
access.rs

1use std::{ops::ControlFlow, pin, time};
2
3use dope_core::driver::schedule::clock::Sample;
4use drive::{block, clock, serve, turn};
5use o3::base::{cell::region, time::Positive};
6use turn::scope;
7
8use crate::{
9    client,
10    executor::{self, drain, drive, root, session},
11    topology::lending,
12};
13
14/// Borrowed capabilities shared by every live application view.
15pub struct Access<
16    'app,
17    'life: 'app,
18    'd: 'life,
19    D,
20    Q = (),
21    Plan = <D as executor::raw::Layout<'d>>::ParkPlan,
22> {
23    pub(crate) core: &'app mut session::Core<'life, 'd, Q>,
24    view: executor::raw::View<'app, 'd, D, executor::raw::Live, Plan>,
25}
26
27impl<'app, 'life: 'app, 'd: 'life, D, Q, Plan> Access<'app, 'life, 'd, D, Q, Plan> {
28    pub(crate) fn reborrow(&mut self) -> Access<'_, 'life, 'd, D, Q, Plan> {
29        Access {
30            core: &mut *self.core,
31            view: self.view,
32        }
33    }
34
35    pub fn state_token(&mut self) -> &mut region::Token<region::Identity<'d, 1>> {
36        &mut self.core.scope.context().into_regions().1
37    }
38
39    /// Issues the client of the complete installed root.
40    pub fn root_client(&mut self) -> <D::Provider as client::Provider<'d>>::Client<'app>
41    where
42        D: lending::Root<'d>,
43        D::Provider: 'app,
44    {
45        self.client(|client| client)
46    }
47
48    pub fn client<P>(
49        &mut self,
50        select: impl for<'borrow> FnOnce(pin::Pin<&'borrow D>) -> pin::Pin<&'borrow P>,
51    ) -> <P::Provider as client::Provider<'d>>::Client<'app>
52    where
53        P: lending::Root<'d>,
54        P::Provider: 'app,
55    {
56        let root = select(self.view.app(self.core.scope.token()));
57        let provider = lending::Root::provider(root);
58        client::Provider::provide(client::Context::new(provider))
59    }
60
61    pub fn client_with<P, C>(
62        &mut self,
63        select: impl for<'borrow> FnOnce(pin::Pin<&'borrow D>) -> pin::Pin<&'borrow P>,
64        issue: impl for<'borrow> FnOnce(client::Context<'borrow, 'app, 'd, P>) -> C,
65    ) -> C {
66        let provider = select(self.view.app(self.core.scope.token()));
67        issue(client::Context::new(provider))
68    }
69
70    pub fn inspect<P, C>(
71        &mut self,
72        select: impl for<'borrow> FnOnce(pin::Pin<&'borrow D>) -> pin::Pin<&'borrow P>,
73        inspect: impl for<'borrow> FnOnce(pin::Pin<&'borrow P>) -> C,
74    ) -> C {
75        inspect(select(self.view.app(self.core.scope.token())))
76    }
77}
78
79impl<'app, 'life: 'app, 'd: 'life, D, Q, Plan> Access<'app, 'life, 'd, D, Q, Plan>
80where
81    D: executor::raw::App<'d, ParkPlan = Plan>,
82    Q: executor::Startup,
83{
84    pub(super) const fn new(
85        core: &'app mut session::Core<'life, 'd, Q>,
86        view: executor::raw::View<'app, 'd, D, executor::raw::Live, Plan>,
87    ) -> Self {
88        Self { core, view }
89    }
90
91    pub(super) fn drive<R, C>(
92        self,
93        source: C,
94        root: R,
95        tick: impl Fn(C) -> Result<Sample, drive::Error>,
96    ) -> Result<R::Output, drive::Error>
97    where
98        R: root::Root<'d>,
99        C: clock::Time,
100    {
101        let shutdown = turn::shutdown(self.core.lifecycle);
102        self.drive_with(source, root, tick, shutdown)
103    }
104
105    pub(crate) fn drive_with<R, C>(
106        self,
107        source: C,
108        root: R,
109        tick: impl Fn(C) -> Result<Sample, drive::Error>,
110        shutdown: impl FnMut() -> turn::Status,
111    ) -> Result<R::Output, drive::Error>
112    where
113        R: root::Root<'d>,
114        C: clock::Time,
115    {
116        self.with(|state| {
117            block::Block::new(state.driver_ref(), state, source)?.run(root, tick, shutdown)
118        })
119    }
120
121    pub(super) fn drive_fixed<R, C>(
122        self,
123        source: C,
124        root: R,
125        tick: impl Fn(C) -> Result<Sample, drive::Error>,
126    ) -> Result<session::Fixed<'d, R::Output>, drive::Error>
127    where
128        R: root::Root<'d>,
129        C: clock::Time,
130    {
131        let shutdown = turn::shutdown(self.core.lifecycle);
132        self.with(|state| {
133            block::Block::new(state.driver_ref(), state, source)?.run_fixed(root, tick, shutdown)
134        })
135    }
136
137    pub(super) fn run(self) -> Result<(), drive::Error> {
138        let shutdown = turn::shutdown(self.core.lifecycle);
139        self.with(|state| serve::run(state, clock::wall(), drive::tick, shutdown))
140    }
141
142    pub(super) fn run_for(self, timeout: time::Duration) -> Result<(), drive::Error> {
143        let source = clock::Bound::until(clock::wall(), timeout)?;
144        let shutdown = turn::shutdown(self.core.lifecycle);
145        self.with(|state| serve::run(state, source, drive::timeout, shutdown))
146    }
147
148    pub(super) fn drive_until<R>(self, root: R) -> Result<ControlFlow<R::Output>, drive::Error>
149    where
150        R: root::Root<'d>,
151    {
152        let shutdown = turn::shutdown(self.core.lifecycle);
153        self.with(|state| {
154            block::Block::new(state.driver_ref(), state, clock::wall())?.run_until(
155                root,
156                drive::tick,
157                shutdown,
158            )
159        })
160    }
161
162    pub(super) fn run_drain(mut self, timeout: Positive) -> Result<drain::Outcome, drive::Error>
163    where
164        D: executor::raw::Drain<'d>,
165    {
166        self.reborrow().run()?;
167        self.drain(timeout)
168    }
169
170    pub(super) fn drive_drain<R>(
171        mut self,
172        timeout: Positive,
173        root: R,
174    ) -> Result<ControlFlow<R::Output, drain::Outcome>, drive::Error>
175    where
176        D: executor::raw::Drain<'d>,
177        R: root::Root<'d>,
178    {
179        match self.reborrow().drive_until(root)? {
180            ControlFlow::Break(output) => Ok(ControlFlow::Break(output)),
181            ControlFlow::Continue(()) => self.drain(timeout).map(ControlFlow::Continue),
182        }
183    }
184
185    fn drain(self, timeout: Positive) -> Result<drain::Outcome, drive::Error>
186    where
187        D: executor::raw::Drain<'d>,
188    {
189        let source = clock::Bound::until(clock::wall(), timeout.get())?;
190        let shutdown = turn::shutdown(self.core.lifecycle);
191        self.with(|state| drain::run(state, source, shutdown))
192    }
193
194    fn with<T>(
195        self,
196        run: impl FnOnce(scope::Scope<'_, '_, 'app, 'd, D, executor::raw::Live>) -> T,
197    ) -> T {
198        let view = self.view;
199        let core = &mut *self.core;
200        let pending = &mut core.pending;
201        let (token, mut driver, turn) = core.scope.split();
202        run(scope::Scope::new(&mut driver, view, token, turn, pending))
203    }
204}