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.driver_ref(), 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| {
114 block::Block::new(state.driver_ref(), state, source)?.run_fixed(root, tick)
115 })
116 }
117
118 pub(super) fn run(self) -> Result<(), drive::Error> {
119 self.with(|state| serve::run(state, clock::wall(), drive::tick))
120 }
121
122 pub(super) fn run_for(self, timeout: time::Duration) -> Result<(), drive::Error> {
123 let source = clock::Bound::until(clock::wall(), timeout)?;
124 self.with(|state| serve::run(state, source, drive::timeout))
125 }
126
127 pub(super) fn drive_until<R>(self, root: R) -> Result<ControlFlow<R::Output>, drive::Error>
128 where
129 R: root::Root<'d>,
130 {
131 self.with(|state| {
132 block::Block::new(state.driver_ref(), state, clock::wall())?
133 .run_until(root, drive::tick)
134 })
135 }
136
137 pub(super) fn run_drain(mut self, timeout: Positive) -> Result<drain::Outcome, drive::Error>
138 where
139 D: executor::raw::Drain<'d>,
140 {
141 self.reborrow().run()?;
142 self.drain(timeout)
143 }
144
145 pub(super) fn drive_drain<R>(
146 mut self,
147 timeout: Positive,
148 root: R,
149 ) -> Result<ControlFlow<R::Output, drain::Outcome>, drive::Error>
150 where
151 D: executor::raw::Drain<'d>,
152 R: root::Root<'d>,
153 {
154 match self.reborrow().drive_until(root)? {
155 ControlFlow::Break(output) => Ok(ControlFlow::Break(output)),
156 ControlFlow::Continue(()) => self.drain(timeout).map(ControlFlow::Continue),
157 }
158 }
159
160 fn drain(self, timeout: Positive) -> Result<drain::Outcome, drive::Error>
161 where
162 D: executor::raw::Drain<'d>,
163 {
164 let source = clock::Bound::until(clock::wall(), timeout.get())?;
165 self.with(|state| drain::run(state, source))
166 }
167
168 fn with<T>(
169 self,
170 run: impl FnOnce(scope::Scope<'_, '_, 'app, 'd, D, executor::raw::Live>) -> T,
171 ) -> T {
172 let view = self.view;
173 let core = &mut *self.core;
174 let pending = &mut core.pending;
175 core.scope.with_turn(|token, mut driver, turn| {
176 run(scope::Scope::new(&mut driver, view, token, turn, pending))
177 })
178 }
179}