1use std::{mem, pin};
3
4use dope_core::{
5 driver,
6 driver::{
7 life::domain::{Closing, Error, Rejected},
8 settings,
9 settings::{claim, errors},
10 storage,
11 },
12};
13
14use crate::{
15 executor::{self, create, drive, session},
16 random::{self, HashState},
17};
18
19pub mod app;
20mod domain;
21pub mod error;
22pub mod lending;
23pub mod ops;
24mod prepared;
25pub mod recipe;
26mod worker;
27
28pub use domain::Domain;
29pub use prepared::Prepared;
30pub use worker::Worker;
31
32#[repr(transparent)]
36pub struct Boot<'stage, 'scope, 'life: 'scope, 'p: 'life, 'd: 'p, S: storage::Plan + 'd, Q> {
37 session: &'stage session::Scope<'scope, 'life, 'p, 'd, S, Q>,
38}
39
40impl<'stage, 'scope, 'life: 'scope, 'p: 'life, 'd: 'p, S: storage::Plan + 'd, Q>
41 Boot<'stage, 'scope, 'life, 'p, 'd, S, Q>
42{
43 fn new(session: &'stage session::Scope<'scope, 'life, 'p, 'd, S, Q>) -> Self {
44 Self { session }
45 }
46
47 pub fn pinned(&self) -> pin::Pin<&'life S::Output<'p, 'd>> {
49 self.session.pinned()
50 }
51
52 pub fn storage(&self) -> &'life S::Output<'p, 'd> {
54 self.session.storage()
55 }
56}
57
58pub struct Stage<'stage, 'scope, 'life: 'scope, 'p: 'life, 'd: 'p, S: storage::Plan + 'd, Q> {
63 session: &'stage mut session::Scope<'scope, 'life, 'p, 'd, S, Q>,
64}
65
66impl<'stage, 'scope, 'life: 'scope, 'p: 'life, 'd: 'p, S: storage::Plan + 'd, Q>
67 Stage<'stage, 'scope, 'life, 'p, 'd, S, Q>
68{
69 fn new(session: &'stage mut session::Scope<'scope, 'life, 'p, 'd, S, Q>) -> Self {
70 Self { session }
71 }
72
73 pub fn storage(&self) -> &'life S::Output<'p, 'd> {
75 self.session.storage()
76 }
77
78 pub fn hash_state(&mut self, domain: random::Domain) -> HashState<'d> {
81 self.session.hash_state(domain)
82 }
83
84 pub fn driver(&mut self) -> driver::Context<'_, 'd> {
86 self.session.driver()
87 }
88}
89
90pub trait Installer<S: storage::Plan>: Sized {
92 type App<'life, 'p, 'd>: executor::raw::App<'d>
93 where
94 'd: 'p,
95 'p: 'life,
96 'd: 'life,
97 Self: 'd,
98 S: 'd;
99 type Error;
100
101 fn install<'scope, 'life, 'p, 'd, Q>(
102 self,
103 stage: &mut Stage<'_, 'scope, 'life, 'p, 'd, S, Q>,
104 ) -> Result<Self::App<'life, 'p, 'd>, Self::Error>
105 where
106 'd: 'p,
107 'p: 'life,
108 'd: 'life,
109 'life: 'scope,
110 Self: 'd,
111 S: 'd,
112 Q: executor::Startup;
113}
114
115pub enum EnterError<'owner, S, O, T, Q = ()> {
117 Runtime(Rejected<create::Error<'owner>, O>),
118 Storage(Rejected<S, O>),
119 Close(Closing<'owner, Rejected<S, O>, T, Q>),
120}
121
122impl<'owner, S, O, T, Q> EnterError<'owner, S, O, T, Q> {
123 pub fn output(&self) -> Option<&T> {
125 match self {
126 Self::Runtime(..) | Self::Storage(..) => None,
127 Self::Close(state) => state.result().as_ref().ok(),
128 }
129 }
130
131 pub fn cause(&self) -> error::Cause<'_, S> {
133 match self {
134 Self::Runtime(error) => error::Cause::Runtime(error.cause.kind()),
135 Self::Storage(error) => error::Cause::Storage(&error.cause),
136 Self::Close(state) => error::Cause::closing(state),
137 }
138 }
139
140 pub fn kind(&self) -> error::Kind<'_, S, &T> {
141 match self {
142 Self::Runtime(error) => error::Kind::Runtime(error.cause.kind()),
143 Self::Storage(error) => error::Kind::Storage(&error.cause),
144 Self::Close(state) => error::Kind::closing(state),
145 }
146 }
147}
148
149#[derive(Debug)]
150pub enum InstallError<E> {
151 Drive(drive::Error),
152 Install(E),
153}
154
155#[derive(Debug)]
156pub enum Failure<'report, I, T> {
157 Run(session::Error<'report, Result<T, drive::Error>>),
158 Install(I),
159}
160
161impl<I, T> Failure<'_, I, T> {
162 pub fn cause(&self) -> error::Failure<'_, I> {
164 match self {
165 Self::Run(error) => error::Failure::Run {
166 cause: error.cause(),
167 output: match error.output() {
168 Some(Err(error)) => Some(error),
169 Some(Ok(_)) | None => None,
170 },
171 },
172 Self::Install(error) => error::Failure::Install(error),
173 }
174 }
175}
176
177pub enum RunError<'owner, S, I, O, T, Q = ()> {
178 Create(Rejected<create::Error<'owner>, O>),
179 Storage(Rejected<S, O>),
180 Failure(Failure<'owner, I, T>),
181 Close(ClosingRun<'owner, S, I, O, T, Q>),
182}
183
184impl<'owner, S, I, O, T, Q> RunError<'owner, S, I, O, T, Q> {
185 pub fn cause(&self) -> error::Run<'_, S, I> {
187 match self {
188 Self::Create(error) => error::Run::Runtime(error.cause.kind()),
189 Self::Storage(error) => error::Run::Storage(&error.cause),
190 Self::Failure(error) => error::Run::Failure(error.cause()),
191 Self::Close(state) => error::Run::Close {
192 result: match state.result() {
193 Ok(Ok(_)) => Ok(Ok(())),
194 Ok(Err(error)) => Ok(Err(error.cause())),
195 Err(error) => Err(&error.cause),
196 },
197 failure: state.failure(),
198 },
199 }
200 }
201
202 pub fn kind(&self) -> RunKind<'_, 'owner, S, I, T> {
203 match self {
204 Self::Create(error) => error::Kind::Runtime(error.cause.kind()),
205 Self::Storage(error) => error::Kind::Storage(&error.cause),
206 Self::Failure(error) => error::Kind::Run(error),
207 Self::Close(state) => error::Kind::closing(state),
208 }
209 }
210}
211
212impl<'owner, S, O, T, Q> From<Error<'owner, Rejected<S, O>, T, Q>>
213 for EnterError<'owner, S, O, T, Q>
214{
215 fn from(error: Error<'owner, Rejected<S, O>, T, Q>) -> Self {
216 match error {
217 Error::Storage(source) => Self::Storage(source),
218 Error::Close(state) => Self::Close(state),
219 }
220 }
221}
222
223impl<'owner, S, I, O, T, Q> From<EnterError<'owner, S, O, Result<T, Failure<'owner, I, T>>, Q>>
224 for RunError<'owner, S, I, O, T, Q>
225{
226 fn from(error: EnterError<'owner, S, O, Result<T, Failure<'owner, I, T>>, Q>) -> Self {
227 match error {
228 EnterError::Runtime(source) => Self::Create(source),
229 EnterError::Storage(source) => Self::Storage(source),
230 EnterError::Close(state) => Self::Close(state),
231 }
232 }
233}
234
235const _: () = {
236 assert!(
237 mem::size_of::<Boot<'static, 'static, 'static, 'static, 'static, (), ()>>()
238 == mem::size_of::<usize>()
239 );
240 assert!(
241 mem::align_of::<Boot<'static, 'static, 'static, 'static, 'static, (), ()>>()
242 == mem::align_of::<usize>()
243 );
244 assert!(
245 mem::size_of::<Stage<'static, 'static, 'static, 'static, 'static, (), ()>>()
246 == mem::size_of::<&mut session::Scope<'static, 'static, 'static, 'static, (), ()>>()
247 );
248};
249
250#[must_use = "a topology plan must be resolved before it can enter a driver"]
255#[repr(transparent)]
256pub struct Plan<S, I>((S, I));
257
258impl<S, I> Plan<S, I> {
259 pub const fn new(storage: S, install: I) -> Self {
260 Self((storage, install))
261 }
262
263 pub fn into_parts(self) -> (S, I) {
265 self.0
266 }
267
268 pub fn for_profile<P>(self) -> Result<Prepared<S, I>, errors::Claim>
269 where
270 P: settings::Profile,
271 S: storage::Plan + settings::Resource,
272 I: settings::Resource,
273 {
274 let (storage, install) = self.0;
275 let needs = claim::Needs::from_tree(&(&storage, &install))?;
276 let layout = needs.resolve::<P>()?;
277 Ok(Prepared::new(layout, storage, install))
278 }
279
280 pub fn with_config(self, baseline: settings::Config) -> Result<Prepared<S, I>, errors::Claim>
281 where
282 S: storage::Plan + settings::Resource,
283 I: settings::Resource,
284 {
285 let (storage, install) = self.0;
286 let needs = claim::Needs::from_tree(&(&storage, &install))?;
287 let layout = needs.apply_to(baseline)?;
288 Ok(Prepared::new(layout, storage, install))
289 }
290
291 pub fn for_receive<P>(self) -> Result<Prepared<S, I>, errors::Claim>
292 where
293 P: settings::Profile,
294 S: storage::Plan + settings::Resource,
295 I: settings::Resource,
296 {
297 let (storage, install) = self.0;
298 let needs = claim::Needs::from_tree(&(&storage, &install))?;
299 let layout = needs.exact::<P>()?;
300 Ok(Prepared::new(layout, storage, install))
301 }
302
303 pub fn for_install<P>(self) -> Result<Prepared<S, I>, errors::Claim>
304 where
305 P: settings::Profile,
306 S: storage::Claimless,
307 I: settings::Resource,
308 {
309 let (storage, install) = self.0;
310 let needs = claim::Needs::from_tree(&install)?;
311 let layout = needs.resolve::<P>()?;
312 Ok(Prepared::new(layout, storage, install))
313 }
314
315 pub fn with_install(self, baseline: settings::Config) -> Result<Prepared<S, I>, errors::Claim>
316 where
317 S: storage::Claimless,
318 I: settings::Resource,
319 {
320 let (storage, install) = self.0;
321 let needs = claim::Needs::from_tree(&install)?;
322 let layout = needs.apply_to(baseline)?;
323 Ok(Prepared::new(layout, storage, install))
324 }
325}
326
327const _: () = {
328 assert!(mem::size_of::<Plan<usize, u8>>() == mem::size_of::<(usize, u8)>());
329 assert!(mem::align_of::<Plan<usize, u8>>() == mem::align_of::<(usize, u8)>());
330 assert!(mem::needs_drop::<Plan<String, ()>>() == mem::needs_drop::<String>());
331};
332
333type ClosingRun<'owner, S, I, O, T, Q> =
334 Closing<'owner, Rejected<S, O>, Result<T, Failure<'owner, I, T>>, Q>;
335type RunKind<'a, 'owner, S, I, T> =
336 error::Kind<'a, S, &'a Result<T, Failure<'owner, I, T>>, Failure<'owner, I, T>>;