1use std::{io, os::fd, pin, task};
2
3use dope_core::driver::{
4 self, lifecycle, retained,
5 schedule::{self, ready},
6 settings, storage,
7};
8
9use crate::{random, shutdown};
10
11mod application;
12#[doc(hidden)]
13pub mod raw;
14pub mod session;
15mod startup;
16
17pub use application::Application;
18pub use startup::Startup;
19
20pub struct RootContext<'poll, 'd: 'poll, R> {
31 root: pin::Pin<&'poll mut R>,
32 wake: ready::Target<'d>,
33 work: schedule::Application<'poll, 'd>,
34 driver: retained::Context<'poll, 'poll, 'd>,
35}
36
37impl<'poll, 'd: 'poll, R> RootContext<'poll, 'd, R> {
38 pub(crate) fn new(
39 root: pin::Pin<&'poll mut R>,
40 wake: ready::Target<'d>,
41 work: schedule::Application<'poll, 'd>,
42 driver: retained::Context<'poll, 'poll, 'd>,
43 ) -> Self {
44 Self {
45 root,
46 wake,
47 work,
48 driver,
49 }
50 }
51
52 pub fn into_parts(
53 self,
54 ) -> (
55 pin::Pin<&'poll mut R>,
56 ready::Target<'d>,
57 schedule::Application<'poll, 'd>,
58 retained::Context<'poll, 'poll, 'd>,
59 ) {
60 (self.root, self.wake, self.work, self.driver)
61 }
62}
63
64pub trait Root<'d>: Sized {
68 type Output;
69 fn poll(context: RootContext<'_, 'd, Self>) -> task::Poll<Self::Output>;
70}
71
72pub struct Executor<S = (), Q = ()> {
73 storage: S,
74 domain: lifecycle::Domain<Q>,
75 seed: random::Seed,
76}
77
78impl Executor<(), ()> {
79 pub fn new(cfg: settings::Config) -> io::Result<Self> {
80 Self::with_seed(cfg, random::Seed::random()?)
81 }
82
83 pub(crate) fn with_seed(cfg: settings::Config, seed: random::Seed) -> io::Result<Self> {
84 let driver = driver::Driver::new(cfg)?;
85 Ok(Self {
86 storage: (),
87 domain: lifecycle::Domain::new(driver),
88 seed,
89 })
90 }
91}
92
93impl<S, Q> Executor<S, Q> {
94 pub fn with_storage<T: 'static>(self, value: T) -> Executor<storage::Value<T>, Q> {
95 Executor {
96 storage: storage::Value::new(value),
97 domain: self.domain,
98 seed: self.seed,
99 }
100 }
101
102 pub fn with_factory<T: storage::Factory>(self, storage: T) -> Executor<T, Q> {
103 Executor {
104 storage,
105 domain: self.domain,
106 seed: self.seed,
107 }
108 }
109}
110
111pub trait Factory: Sized {
112 type Shutdown: Startup;
113
114 fn executor(self, config: settings::Config) -> io::Result<Executor<(), Self::Shutdown>>;
115}
116
117impl<S> Executor<S, ()> {
118 pub fn with_shutdown(
120 self,
121 source: shutdown::Source,
122 ) -> io::Result<Executor<S, shutdown::Source>> {
123 self.with_source(source, |source| fd::AsFd::as_fd(&source.event))
124 }
125
126 pub(crate) fn with_source<Q>(
127 self,
128 source: Q,
129 select: impl for<'a> FnOnce(&'a Q) -> fd::BorrowedFd<'a>,
130 ) -> io::Result<Executor<S, Q>> {
131 let Self {
132 storage,
133 domain,
134 seed,
135 } = self;
136 let domain = domain.fd(source, select)?;
137 Ok(Executor {
138 storage,
139 domain,
140 seed,
141 })
142 }
143}
144
145impl<S: storage::Factory, Q: Startup> Executor<S, Q> {
146 pub fn try_enter<R>(
147 self,
148 f: impl for<'scope, 'd> FnOnce(session::Session<'scope, 'd, S::Output<'d>, Q>) -> R,
149 ) -> Result<R, S::Error> {
150 let Self {
151 storage,
152 domain,
153 seed,
154 } = self;
155 let owner = crate::Owner::acquire().into_inner();
156 domain.enter(owner, storage, move |scope, storage, source| {
157 let mut core = session::Core::new(scope, seed);
158 f(session::Session::new(storage, &mut core, source))
159 })
160 }
161}
162
163impl<S, Q> Executor<S, Q>
164where
165 S: storage::Factory,
166 S::Error: storage::Never,
167 Q: Startup,
168{
169 pub fn enter<R>(
170 self,
171 f: impl for<'scope, 'd> FnOnce(session::Session<'scope, 'd, S::Output<'d>, Q>) -> R,
172 ) -> R {
173 match self.try_enter(f) {
174 Ok(output) => output,
175 Err(error) => storage::Never::never(error),
176 }
177 }
178}