Skip to main content

dope_runtime/topology/
ops.rs

1use dope_core::driver::storage;
2
3use crate::{
4    executor::{self, session},
5    shutdown,
6    topology::{self, Worker, lending, recipe},
7};
8
9/// Runs once in one exact driver generation, retaining its operation owner.
10pub trait Operation<'d, C>: Sized {
11    type Output;
12
13    fn run(self, context: C) -> Self::Output
14    where
15        Self: 'd;
16}
17
18impl<'d, C, F, R> Operation<'d, C> for F
19where
20    F: FnOnce(C) -> R,
21{
22    type Output = R;
23
24    fn run(self, context: C) -> Self::Output
25    where
26        Self: 'd,
27    {
28        self(context)
29    }
30}
31
32impl<S, I, Q, O, R> executor::Op<S, Q> for (I, O)
33where
34    S: storage::Plan,
35    O: for<'scope, 'life, 'p, 'd> Operation<'d, Worker<'scope, 'life, 'p, 'd, S, I, Q>, Output = R>,
36{
37    type Output = R;
38
39    fn run<'scope, 'life, 'p, 'd>(
40        self,
41        session: session::Scope<'scope, 'life, 'p, 'd, S, Q>,
42    ) -> Self::Output
43    where
44        'd: 'p,
45        'p: 'life,
46        'd: 'life,
47        'life: 'scope,
48        Self: 'd,
49        S: 'd,
50        Q: 'd,
51    {
52        self.1.run(Worker::new(session, self.0))
53    }
54}
55
56/// Maps an operation's output before its driver generation is released.
57pub struct Map<O, F>(pub O, pub F);
58
59impl<'d, C, O, F, R> Operation<'d, C> for Map<O, F>
60where
61    O: Operation<'d, C>,
62    F: FnOnce(O::Output) -> R,
63{
64    type Output = R;
65
66    fn run(self, context: C) -> R
67    where
68        Self: 'd,
69    {
70        (self.1)(self.0.run(context))
71    }
72}
73
74/// Installs the claimed head and lends it to its retained dependent tail.
75pub struct Compose;
76
77impl<'scope, 'life, 'p, 'd, S, I, T, Q> Operation<'d, Worker<'scope, 'life, 'p, 'd, S, (I, T), Q>>
78    for Compose
79where
80    S: storage::Plan,
81    Q: executor::Startup,
82    I: lending::ComposeFrom<S, T, Q>,
83{
84    type Output = Result<I::Output, I::Error>;
85
86    fn run(self, worker: Worker<'scope, 'life, 'p, 'd, S, (I, T), Q>) -> Self::Output
87    where
88        Self: 'd,
89    {
90        worker.lend(|(head, tail), stage| head.compose(tail, stage))
91    }
92}
93
94/// Installs and runs the retained application, preserving its shutdown proof.
95pub struct Run<'report>(pub &'report mut session::Completion);
96
97impl<'report, 'scope, 'life, 'p, 'd, S, I, Q> Operation<'d, Worker<'scope, 'life, 'p, 'd, S, I, Q>>
98    for Run<'report>
99where
100    S: storage::Plan,
101    Q: executor::Startup,
102    I: recipe::Execute<S>,
103{
104    type Output = Result<
105        shutdown::Requested<Q>,
106        topology::Failure<'report, I::Error, shutdown::Requested<Q>>,
107    >;
108
109    fn run(self, worker: Worker<'scope, 'life, 'p, 'd, S, I, Q>) -> Self::Output
110    where
111        Self: 'd,
112    {
113        worker.lend(|source, stage| source.execute(stage, self.0))
114    }
115}