Skip to main content

dope_runtime/topology/
prepared.rs

1use std::convert;
2
3use dope_core::driver::{life::recovery, settings, storage};
4
5use crate::{
6    executor::{self, session},
7    shutdown,
8    topology::{self, ops, recipe},
9};
10
11/// Fully validated, proof-carrying startup input for one worker driver.
12///
13/// Retains the installer with its claims until the exact domain is entered.
14pub struct Prepared<S, I> {
15    domain: topology::Domain<S>,
16    installer: I,
17}
18
19impl<S, I> Prepared<S, I> {
20    pub(super) const fn new(layout: settings::Config, storage: S, setup: I) -> Self {
21        Self {
22            domain: topology::Domain::new(layout, storage),
23            installer: setup,
24        }
25    }
26
27    pub const fn layout(&self) -> settings::Config {
28        self.domain.layout()
29    }
30}
31
32impl<S, I> Prepared<S, I>
33where
34    S: storage::Direct,
35{
36    pub fn enter_local<O, R, Done>(
37        self,
38        op: O,
39        report: impl recovery::Observe,
40        finish: impl for<'owner> FnOnce(
41            Result<R, topology::EnterError<'owner, convert::Infallible, (I, O), R>>,
42        ) -> Done,
43    ) -> Done
44    where
45        O: for<'scope, 'life, 'p, 'd> ops::Operation<
46                'd,
47                topology::Worker<'scope, 'life, 'p, 'd, S, I, ()>,
48                Output = R,
49            >,
50    {
51        self.domain
52            .enter_local((self.installer, op), report, finish)
53    }
54
55    pub fn with_local<F, R, Done>(
56        self,
57        op: F,
58        report: impl recovery::Observe,
59        finish: impl for<'owner> FnOnce(
60            Result<R, topology::EnterError<'owner, convert::Infallible, (I, F), R>>,
61        ) -> Done,
62    ) -> Done
63    where
64        F: for<'scope, 'life, 'p, 'd> FnOnce(
65            topology::Worker<'scope, 'life, 'p, 'd, S, I, ()>,
66        ) -> R,
67    {
68        self.domain
69            .enter_local((self.installer, op), report, finish)
70    }
71
72    pub fn enter<C, O, R, Done>(
73        self,
74        context: C,
75        op: O,
76        report: impl recovery::Observe,
77        finish: impl for<'owner> FnOnce(
78            Result<R, topology::EnterError<'owner, convert::Infallible, (I, O), R, C::Shutdown>>,
79        ) -> Done,
80    ) -> Done
81    where
82        C: executor::Build,
83        O: for<'scope, 'life, 'p, 'd> ops::Operation<
84                'd,
85                topology::Worker<'scope, 'life, 'p, 'd, S, I, C::Shutdown>,
86                Output = R,
87            >,
88    {
89        self.domain
90            .enter(context, (self.installer, op), report, finish)
91    }
92
93    pub fn enter_with<C, F, R, Done>(
94        self,
95        context: C,
96        op: F,
97        report: impl recovery::Observe,
98        finish: impl for<'owner> FnOnce(
99            Result<R, topology::EnterError<'owner, convert::Infallible, (I, F), R, C::Shutdown>>,
100        ) -> Done,
101    ) -> Done
102    where
103        C: executor::Build,
104        F: for<'scope, 'life, 'p, 'd> FnOnce(
105            topology::Worker<'scope, 'life, 'p, 'd, S, I, C::Shutdown>,
106        ) -> R,
107    {
108        self.domain
109            .enter(context, (self.installer, op), report, finish)
110    }
111
112    /// Installs and runs one application, retaining every failure for its handler.
113    pub fn run<'report, C, F>(
114        self,
115        context: C,
116        complete: &'report mut session::Completion,
117        report: impl recovery::Observe,
118        failed: impl for<'owner> FnOnce(
119            topology::RunError<
120                'owner,
121                convert::Infallible,
122                I::Error,
123                (I, ops::Run<'report>),
124                shutdown::Requested<C::Shutdown>,
125                C::Shutdown,
126            >,
127        ) -> Result<shutdown::Requested<C::Shutdown>, F>,
128    ) -> Result<shutdown::Requested<C::Shutdown>, F>
129    where
130        C: executor::Build,
131        I: recipe::Execute<S>,
132    {
133        self.enter(context, ops::Run(complete), report, |result| {
134            let error = match result {
135                Ok(Ok(done)) => return Ok(done),
136                Ok(Err(error)) => topology::RunError::Failure(error),
137                Err(error) => topology::RunError::from(error),
138            };
139            failed(error)
140        })
141    }
142}
143
144impl<S, I> Prepared<S, I>
145where
146    S: storage::Build,
147{
148    pub fn try_local<O, R, Done>(
149        self,
150        op: O,
151        report: impl recovery::Observe,
152        finish: impl for<'owner> FnOnce(
153            Result<R, topology::EnterError<'owner, S::Error, (I, O), R>>,
154        ) -> Done,
155    ) -> Done
156    where
157        O: for<'scope, 'life, 'p, 'd> ops::Operation<
158                'd,
159                topology::Worker<'scope, 'life, 'p, 'd, S, I, ()>,
160                Output = R,
161            >,
162    {
163        self.domain.try_local((self.installer, op), report, finish)
164    }
165
166    pub fn try_scoped<F, R, Done>(
167        self,
168        op: F,
169        report: impl recovery::Observe,
170        finish: impl for<'owner> FnOnce(
171            Result<R, topology::EnterError<'owner, S::Error, (I, F), R>>,
172        ) -> Done,
173    ) -> Done
174    where
175        F: for<'scope, 'life, 'p, 'd> FnOnce(
176            topology::Worker<'scope, 'life, 'p, 'd, S, I, ()>,
177        ) -> R,
178    {
179        self.domain.try_local((self.installer, op), report, finish)
180    }
181
182    pub fn try_enter<C, O, R, Done>(
183        self,
184        context: C,
185        op: O,
186        report: impl recovery::Observe,
187        finish: impl for<'owner> FnOnce(
188            Result<R, topology::EnterError<'owner, S::Error, (I, O), R, C::Shutdown>>,
189        ) -> Done,
190    ) -> Done
191    where
192        C: executor::Build,
193        O: for<'scope, 'life, 'p, 'd> ops::Operation<
194                'd,
195                topology::Worker<'scope, 'life, 'p, 'd, S, I, C::Shutdown>,
196                Output = R,
197            >,
198    {
199        self.domain
200            .try_enter(context, (self.installer, op), report, finish)
201    }
202
203    pub fn try_with<C, F, R, Done>(
204        self,
205        context: C,
206        op: F,
207        report: impl recovery::Observe,
208        finish: impl for<'owner> FnOnce(
209            Result<R, topology::EnterError<'owner, S::Error, (I, F), R, C::Shutdown>>,
210        ) -> Done,
211    ) -> Done
212    where
213        C: executor::Build,
214        F: for<'scope, 'life, 'p, 'd> FnOnce(
215            topology::Worker<'scope, 'life, 'p, 'd, S, I, C::Shutdown>,
216        ) -> R,
217    {
218        self.domain
219            .try_enter(context, (self.installer, op), report, finish)
220    }
221}
222
223impl<S, I> Prepared<S, I>
224where
225    S: storage::Create,
226{
227    pub fn try_create<C, F, R, Done>(
228        self,
229        context: C,
230        op: F,
231        report: impl recovery::Observe,
232        finish: impl for<'owner> FnOnce(
233            Result<R, topology::EnterError<'owner, S::Error, (I, F), R, C::Shutdown>>,
234        ) -> Done,
235    ) -> Done
236    where
237        C: executor::Build,
238        F: for<'scope, 'life, 'p, 'd> FnOnce(
239            topology::Worker<'scope, 'life, 'p, 'd, S, I, C::Shutdown>,
240        ) -> R,
241    {
242        self.domain
243            .try_create(context, (self.installer, op), report, finish)
244    }
245
246    pub fn try_scope<C, O, R, Done>(
247        self,
248        context: C,
249        op: O,
250        report: impl recovery::Observe,
251        finish: impl for<'owner> FnOnce(
252            Result<R, topology::EnterError<'owner, S::Error, (I, O), R, C::Shutdown>>,
253        ) -> Done,
254    ) -> Done
255    where
256        C: executor::Build,
257        O: for<'scope, 'life, 'p, 'd> ops::Operation<
258                'd,
259                topology::Worker<'scope, 'life, 'p, 'd, S, I, C::Shutdown>,
260                Output = R,
261            >,
262    {
263        self.domain
264            .try_create(context, (self.installer, op), report, finish)
265    }
266}