1use std::{marker, os::fd};
2
3use dope_core::{
4 Errno,
5 driver::{life::creation, settings},
6};
7use o3::base::marker::ThreadBound;
8
9use crate::{
10 executor::{self, create},
11 process::{
12 failure::bus,
13 lifecycle::{self, Main},
14 },
15};
16
17pub use crate::process::Shutdown as ReadySource;
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum CreateError {
21 Pair(bus::Create),
22 Duplicate(Errno),
23}
24
25#[derive(Debug)]
26pub struct FireError {
27 pub trigger: Trigger,
28 pub cause: Errno,
29}
30
31#[must_use]
32pub struct Pair {
33 source: Source,
34 trigger: Trigger,
35}
36
37#[must_use]
38pub struct Source {
39 pub(crate) event: (fd::OwnedFd, Main),
40}
41
42impl fd::AsFd for Source {
43 fn as_fd(&self) -> fd::BorrowedFd<'_> {
44 fd::AsFd::as_fd(&self.event.0)
45 }
46}
47
48#[must_use]
49#[derive(Debug)]
50pub struct Trigger(Main);
51
52type Invariant<Q> = marker::PhantomData<(fn(Q) -> Q, ThreadBound)>;
53
54#[must_use]
55pub struct Requested<Q = Source>(Invariant<Q>);
56
57impl Pair {
58 pub fn new() -> Result<Self, CreateError> {
59 let (main, event) = lifecycle::pair().map_err(CreateError::Pair)?;
60 let guard = main.duplicate().map_err(CreateError::Duplicate)?;
61 Ok(Self {
62 source: Source {
63 event: (event, guard),
64 },
65 trigger: Trigger(main),
66 })
67 }
68
69 pub fn split(self) -> (Source, Trigger) {
70 (self.source, self.trigger)
71 }
72
73 pub fn run<R>(self, execute: impl FnOnce(Source) -> R) -> R {
74 execute(self.source)
75 }
76}
77
78impl executor::Build for Source {
79 type Shutdown = Source;
80
81 fn try_build(
82 self,
83 attempt: &mut creation::Attempt,
84 config: settings::Config,
85 ) -> Result<executor::Executor<(), Self::Shutdown>, create::Error<'_>> {
86 executor::Executor::new(attempt, config)?
87 .shutdown(self)
88 .map_err(create::Error::from)
89 }
90}
91
92impl<'run> executor::Build for ReadySource<'run> {
93 type Shutdown = Self;
94
95 fn try_build(
96 self,
97 attempt: &mut creation::Attempt,
98 config: settings::Config,
99 ) -> Result<executor::Executor<(), Self::Shutdown>, create::Error<'_>> {
100 executor::Executor::new(attempt, config)?
101 .shutdown(self)
102 .map_err(create::Error::from)
103 }
104}
105
106impl executor::Startup for Source {
107 fn installed(&self) -> Result<(), executor::InstallError> {
108 Ok(())
109 }
110}
111
112impl Trigger {
113 pub fn fire(self) -> Result<(), FireError> {
114 match self.0.request() {
115 Ok(()) => Ok(()),
116 Err(cause) => Err(FireError {
117 trigger: self,
118 cause,
119 }),
120 }
121 }
122}
123
124impl<Q> Requested<Q> {
125 pub(crate) const fn new() -> Self {
126 Self(marker::PhantomData)
127 }
128}
129
130const _: () = assert!(std::mem::size_of::<Requested>() == 0);