1use std::{convert, num::NonZero, os::fd};
2
3use dope_core::{
4 driver::{
5 life,
6 life::{creation, domain, recovery},
7 settings, storage,
8 },
9 random,
10};
11use o3::buffer;
12
13use crate::process::failure::bus;
14
15pub mod boot;
16pub mod create;
17pub mod drain;
18pub mod drive;
19pub mod raw;
20pub mod root;
21pub mod session;
22#[doc(hidden)]
23pub mod work;
24pub trait Op<S: storage::Plan, Q>: Sized {
26 type Output;
27
28 fn run<'scope, 'life, 'p, 'd>(
29 self,
30 scope: session::Scope<'scope, 'life, 'p, 'd, S, Q>,
31 ) -> Self::Output
32 where
33 'd: 'p,
34 'p: 'life,
35 'd: 'life,
36 'life: 'scope,
37 Self: 'd,
38 S: 'd,
39 Q: 'd;
40}
41
42#[repr(transparent)]
44pub struct Scoped<F>(F);
45
46impl<F> Scoped<F> {
47 pub const fn new<S: storage::Plan, Q, R>(run: F) -> Self
48 where
49 F: for<'scope, 'life, 'p, 'd> FnOnce(session::Scope<'scope, 'life, 'p, 'd, S, Q>) -> R,
50 {
51 Self(run)
52 }
53
54 pub fn into_inner(self) -> F {
55 self.0
56 }
57}
58
59impl<S, Q, F, R> Op<S, Q> for Scoped<F>
60where
61 S: storage::Plan,
62 F: for<'scope, 'life, 'p, 'd> FnOnce(session::Scope<'scope, 'life, 'p, 'd, S, Q>) -> R,
63{
64 type Output = R;
65
66 fn run<'scope, 'life, 'p, 'd>(
67 self,
68 scope: session::Scope<'scope, 'life, 'p, 'd, S, Q>,
69 ) -> Self::Output
70 where
71 'd: 'p,
72 'p: 'life,
73 'd: 'life,
74 'life: 'scope,
75 Self: 'd,
76 S: 'd,
77 Q: 'd,
78 {
79 (self.0)(scope)
80 }
81}
82
83struct Entry<O>(O);
84
85impl<S, Q, O> life::Operation<S, Q> for Entry<O>
86where
87 S: storage::Plan,
88 O: Op<S, Q>,
89{
90 type Output = O::Output;
91
92 fn run<'life, 'p, 'd>(
93 self,
94 scope: life::Scope<'life, 'd>,
95 store: storage::Loan<'life, 'p, 'd, S>,
96 source: &'life Q,
97 ) -> Self::Output
98 where
99 'd: 'p,
100 'p: 'life,
101 'd: 'life,
102 Self: 'd,
103 S: 'd,
104 Q: 'd,
105 {
106 let mut core = session::Core::new(scope, source);
107 let scope = session::Scope::new(store, &mut core);
108 Op::run(self.0, scope)
109 }
110}
111
112pub trait Startup: Sized {
115 fn installed(&self) -> Result<(), InstallError>;
117}
118
119impl Startup for () {
120 fn installed(&self) -> Result<(), InstallError> {
121 Ok(())
122 }
123}
124
125#[derive(Clone, Copy, Debug, Eq, PartialEq)]
126pub enum InstallError {
127 Claim(settings::errors::Claim),
128 Coordinators { count: NonZero<usize>, limit: usize },
129 CoordinatorCountOverflow,
130 Process(bus::Fault),
131}
132
133impl From<settings::errors::Claim> for InstallError {
134 fn from(error: settings::errors::Claim) -> Self {
135 Self::Claim(error)
136 }
137}
138
139impl From<bus::Fault> for InstallError {
140 fn from(error: bus::Fault) -> Self {
141 Self::Process(error)
142 }
143}
144
145pub struct Executor<S = (), Q = ()> {
146 storage: S,
147 generation: domain::Generation<Q>,
148 teardown: domain::Teardown,
149}
150
151impl Executor<(), ()> {
152 pub fn new(
153 attempt: &mut creation::Attempt,
154 cfg: settings::Config,
155 ) -> Result<Self, create::Error<'_>> {
156 let driver = attempt.try_driver(cfg)?;
157 Ok(Self {
158 storage: (),
159 generation: domain::Generation::new(driver),
160 teardown: domain::Teardown::default(),
161 })
162 }
163
164 pub(crate) fn with_seed(
165 attempt: &mut creation::Attempt,
166 cfg: settings::Config,
167 seed: random::Seed,
168 ) -> Result<Self, create::Error<'_>> {
169 let driver = attempt.try_seed(cfg, seed)?;
170 Ok(Self {
171 storage: (),
172 generation: domain::Generation::new(driver),
173 teardown: domain::Teardown::default(),
174 })
175 }
176}
177
178impl<S, Q> Executor<S, Q> {
179 pub fn with_storage<T>(self, value: T) -> Executor<storage::Value<T>, Q> {
180 self.with_plan(storage::Value::new(value))
181 }
182
183 pub fn with_plan<T: storage::Plan>(self, plan: T) -> Executor<T, Q> {
184 Executor {
185 storage: plan,
186 generation: self.generation,
187 teardown: self.teardown,
188 }
189 }
190}
191
192pub trait Build: Sized {
193 type Shutdown: Startup;
194
195 fn try_build(
196 self,
197 attempt: &mut creation::Attempt,
198 config: settings::Config,
199 ) -> Result<Executor<(), Self::Shutdown>, create::Error<'_>>;
200}
201
202impl Build for () {
203 type Shutdown = ();
204
205 fn try_build(
206 self,
207 attempt: &mut creation::Attempt,
208 config: settings::Config,
209 ) -> Result<Executor<(), Self::Shutdown>, create::Error<'_>> {
210 Executor::new(attempt, config)
211 }
212}
213
214impl<S> Executor<S, ()> {
215 pub fn shutdown<Q: fd::AsFd>(self, source: Q) -> Result<Executor<S, Q>, domain::Register> {
217 let Self {
218 storage: store,
219 generation: epoch,
220 teardown,
221 } = self;
222 Ok(Executor {
223 storage: store,
224 generation: epoch.fd(source)?,
225 teardown,
226 })
227 }
228}
229
230type ExecResult<'owner, S, O, Q> = Result<
231 <O as Op<S, Q>>::Output,
232 domain::Error<
233 'owner,
234 domain::Rejected<<S as storage::Build>::Error, O>,
235 <O as Op<S, Q>>::Output,
236 Q,
237 >,
238>;
239type CreateResult<'owner, S, F, R, Q> =
240 Result<R, domain::Error<'owner, domain::Rejected<<S as storage::Create>::Error, F>, R, Q>>;
241
242pub struct Execution<'owner, S, Q> {
244 storage: S,
245 domain: domain::Session<'owner, Q>,
246}
247
248impl<S, Q> Executor<S, Q> {
249 pub fn run<R>(self, run: impl for<'owner> FnOnce(Execution<'owner, S, Q>) -> R) -> R {
250 let Self {
251 storage,
252 generation: epoch,
253 mut teardown,
254 } = self;
255 let session = epoch.start(&mut teardown);
256 run(Execution {
257 storage,
258 domain: session,
259 })
260 }
261}
262
263impl<'owner, S: storage::Build, Q: Startup> Execution<'owner, S, Q> {
264 pub fn try_enter<O>(self, op: O, report: impl recovery::Observe) -> ExecResult<'owner, S, O, Q>
265 where
266 O: Op<S, Q>,
267 {
268 let Self {
269 storage: store,
270 domain,
271 } = self;
272 domain
273 .try_enter(store, Entry(op), report)
274 .map_err(|error| error.map_storage(|rejected| rejected.map_op(|entry| entry.0)))
275 }
276}
277
278impl<'owner, S: storage::Create, Q: Startup> Execution<'owner, S, Q> {
279 pub fn try_create<F, R>(
280 self,
281 op: F,
282 report: impl recovery::Observe,
283 ) -> CreateResult<'owner, S, F, R, Q>
284 where
285 F: for<'scope, 'life, 'p, 'd> FnOnce(session::Scope<'scope, 'life, 'p, 'd, S, Q>) -> R,
286 {
287 self.try_scope(Scoped(op), report)
288 .map_err(|error| error.map_storage(|rejected| rejected.map_op(|entry| entry.0)))
289 }
290
291 pub(crate) fn try_scope<O>(
292 self,
293 op: O,
294 report: impl recovery::Observe,
295 ) -> CreateResult<'owner, S, O, O::Output, Q>
296 where
297 O: Op<S, Q>,
298 {
299 let Self {
300 storage: store,
301 domain,
302 } = self;
303 domain
304 .try_create(store, Entry(op), report)
305 .map_err(|error| error.map_storage(|rejected| rejected.map_op(|entry| entry.0)))
306 }
307}
308
309impl<'owner, S, Q> Execution<'owner, S, Q>
310where
311 S: storage::Direct,
312 Q: Startup,
313{
314 pub fn enter<O>(
315 self,
316 op: O,
317 report: impl recovery::Observe,
318 ) -> Result<O::Output, domain::Error<'owner, convert::Infallible, O::Output, Q>>
319 where
320 O: Op<S, Q>,
321 {
322 let Self {
323 storage: store,
324 domain,
325 } = self;
326 domain.enter(store, Entry(op), report)
327 }
328
329 pub fn enter_with<R>(
330 self,
331 op: impl for<'scope, 'life, 'p, 'd> FnOnce(session::Scope<'scope, 'life, 'p, 'd, S, Q>) -> R,
332 report: impl recovery::Observe,
333 ) -> Result<R, domain::Error<'owner, convert::Infallible, R, Q>> {
334 self.enter(Scoped(op), report)
335 }
336}
337
338impl<'owner, A: buffer::raw::Arenas, Q: Startup> Execution<'owner, storage::Scope<A>, Q> {
339 pub fn scope<R>(
341 self,
342 op: impl for<'scope, 'life, 'p, 'd> FnOnce(
343 session::Scope<'scope, 'life, 'p, 'd, storage::Scope<A>, Q>,
344 ) -> R,
345 report: impl recovery::Observe,
346 ) -> Result<R, domain::Error<'owner, convert::Infallible, R, Q>> {
347 let Self {
348 storage: store,
349 domain,
350 } = self;
351 domain.scope(store, Entry(Scoped(op)), report)
352 }
353}