dope_runtime/executor/session/
access.rs1use 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
14pub 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(super) 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(super) 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 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{
83 pub(super) const fn new(
84 core: &'app mut session::Core<'life, 'd, Q>,
85 view: executor::raw::View<'app, 'd, D, executor::raw::Live, Plan>,
86 ) -> Self {
87 Self { core, view }
88 }
89
90 pub(super) fn drive<R, C>(
91 self,
92 source: C,
93 root: R,
94 tick: impl Fn(C) -> Result<Sample, drive::Error>,
95 ) -> Result<R::Output, drive::Error>
96 where
97 R: root::Root<'d>,
98 C: clock::Time,
99 {
100 self.with(|state| block::Block::new(state, source)?.run(root, tick))
101 }
102
103 pub(super) fn drive_fixed<R, C>(
104 self,
105 source: C,
106 root: R,
107 tick: impl Fn(C) -> Result<Sample, drive::Error>,
108 ) -> Result<session::Fixed<'d, R::Output>, drive::Error>
109 where
110 R: root::Root<'d>,
111 C: clock::Time,
112 {
113 self.with(|state| block::Block::new(state, source)?.run_fixed(root, tick))
114 }
115
116 pub(super) fn run(self) -> Result<(), drive::Error> {
117 self.with(|state| serve::run(state, clock::wall(), drive::tick))
118 }
119
120 pub(super) fn run_for(self, timeout: time::Duration) -> Result<(), drive::Error> {
121 let source = clock::Bound::until(clock::wall(), timeout)?;
122 self.with(|state| serve::run(state, source, drive::timeout))
123 }
124
125 pub(super) fn drive_until<R>(self, root: R) -> Result<ControlFlow<R::Output>, drive::Error>
126 where
127 R: root::Root<'d>,
128 {
129 self.with(|state| block::Block::new(state, clock::wall())?.run_until(root, drive::tick))
130 }
131
132 pub(super) fn run_drain(mut self, timeout: Positive) -> Result<drain::Outcome, drive::Error>
133 where
134 D: executor::raw::Drain<'d>,
135 {
136 self.reborrow().run()?;
137 self.drain(timeout)
138 }
139
140 pub(super) fn drive_drain<R>(
141 mut self,
142 timeout: Positive,
143 root: R,
144 ) -> Result<ControlFlow<R::Output, drain::Outcome>, drive::Error>
145 where
146 D: executor::raw::Drain<'d>,
147 R: root::Root<'d>,
148 {
149 match self.reborrow().drive_until(root)? {
150 ControlFlow::Break(output) => Ok(ControlFlow::Break(output)),
151 ControlFlow::Continue(()) => self.drain(timeout).map(ControlFlow::Continue),
152 }
153 }
154
155 fn drain(self, timeout: Positive) -> Result<drain::Outcome, drive::Error>
156 where
157 D: executor::raw::Drain<'d>,
158 {
159 let source = clock::Bound::until(clock::wall(), timeout.get())?;
160 self.with(|state| drain::Run::new(state, source).run())
161 }
162
163 fn with<T>(
164 self,
165 run: impl FnOnce(scope::Scope<'_, '_, 'app, 'd, D, executor::raw::Live>) -> T,
166 ) -> T {
167 let view = self.view;
168 let core = &mut *self.core;
169 let pending = &mut core.pending;
170 core.scope.with_turn(|token, mut driver, turn| {
171 run(scope::Scope::new(&mut driver, view, token, turn, pending))
172 })
173 }
174}