Skip to main content

dope_core/io/socket/
pending.rs

1use std::{marker, mem};
2
3use dope_sys::{
4    engine,
5    io::socket::option::tuning::{Error, device},
6};
7use o3::depot::arena::slab::Vacancy;
8
9use crate::{
10    Engine, Errno, driver,
11    driver::{
12        result,
13        retained::{flight, flight::cancel},
14        route::{indices, kind},
15    },
16    io::{
17        event::net::{connect, tuning},
18        fd::handles,
19        socket::option,
20    },
21};
22
23#[doc(hidden)]
24pub struct Live;
25
26#[doc(hidden)]
27pub struct Cancelled;
28
29/// Exact cause of a socket submission rejection.
30#[derive(Debug)]
31pub enum Cause {
32    Submit(result::SubmitError),
33    Option(Errno),
34}
35
36#[must_use = "a rejected establishment retains its exact descriptor and cause"]
37pub struct Rejection<'d> {
38    fd: handles::Descriptor<'d>,
39    cause: Cause,
40}
41
42#[must_use = "cancellation either transfers the item to the kernel or returns it for retry"]
43pub enum Cancellation<'d> {
44    Submitted(Tuning<'d, Cancelled>),
45    Retry {
46        item: Tuning<'d>,
47        error: result::SubmitError,
48    },
49}
50
51#[doc(hidden)]
52#[must_use = "a pending establishment owns its descriptor and completion authority"]
53#[repr(C)]
54pub struct Tuning<'d, State = Live> {
55    fd: handles::Descriptor<'d>,
56    flight: flight::Flight<'d, kind::Tuning>,
57    permit: <Engine as engine::Cancel<indices::SlotIndex>>::Permit,
58    state: marker::PhantomData<State>,
59}
60
61#[doc(hidden)]
62#[must_use = "a pending establishment owns its descriptor and completion authority"]
63#[repr(C)]
64pub struct Connection<'d, State = Live> {
65    fd: handles::Descriptor<'d>,
66    flight: flight::Flight<'d, kind::Connect>,
67    state: marker::PhantomData<State>,
68}
69
70#[must_use = "a completion mismatch retains both pending and completion authority"]
71pub struct Mismatch<T, C> {
72    item: T,
73    done: C,
74}
75
76impl<T, C> Mismatch<T, C> {
77    pub fn into_parts(self) -> (T, C) {
78        (self.item, self.done)
79    }
80}
81
82impl<'d, State> Tuning<'d, State> {
83    #[doc(hidden)]
84    pub const fn fd(&self) -> &handles::Descriptor<'d> {
85        &self.fd
86    }
87}
88
89impl<'d> Tuning<'d> {
90    pub(crate) fn from_native<P>(
91        finish: device::Finish<handles::Descriptor<'d>, flight::Reserved<'d, kind::Tuning>, P>,
92    ) -> option::Tuning<'d>
93    where
94        Engine: engine::Cancel<indices::SlotIndex, Permit = P>,
95    {
96        match finish {
97            device::Finish::Applied(fd) => option::Tuning::Applied(fd),
98            device::Finish::Pending(fd, target, permit) => option::Tuning::Pending(Self {
99                fd,
100                flight: target.commit(),
101                permit,
102                state: marker::PhantomData,
103            }),
104        }
105    }
106
107    fn commit<P>(self) -> Tuning<'d, Cancelled>
108    where
109        Engine: engine::Cancel<indices::SlotIndex, Permit = P>,
110    {
111        Tuning {
112            fd: self.fd,
113            flight: self.flight,
114            permit: self.permit,
115            state: marker::PhantomData,
116        }
117    }
118
119    pub fn cancel(self, driver: &mut driver::Context<'_, 'd>) -> Cancellation<'d> {
120        match engine::Cancel::cancel(driver.native().as_mut(), &self.permit, self.fd.index()) {
121            Ok(()) => Cancellation::Submitted(self.commit()),
122            Err(error) => Cancellation::Retry {
123                item: self,
124                error: result::SubmitError::queue(error),
125            },
126        }
127    }
128}
129
130impl<'d, State> Connection<'d, State> {
131    #[doc(hidden)]
132    pub const fn fd(&self) -> &handles::Descriptor<'d> {
133        &self.fd
134    }
135}
136
137impl<'d> Connection<'d> {
138    pub(crate) fn connect(
139        fd: handles::Descriptor<'d>,
140        flight: flight::Flight<'d, kind::Connect>,
141    ) -> Self {
142        Self {
143            fd,
144            flight,
145            state: marker::PhantomData,
146        }
147    }
148
149    pub fn try_cancel(
150        mut self,
151        driver: &mut driver::Context<'_, 'd>,
152    ) -> Result<Connection<'d, Cancelled>, (Self, cancel::Error)> {
153        match driver.native().try_stop_at(&mut self.flight, &self.fd) {
154            Ok(_) => Ok(self.commit()),
155            Err(error) => Err((self, error)),
156        }
157    }
158
159    pub(crate) fn commit(self) -> Connection<'d, Cancelled> {
160        Connection {
161            fd: self.fd,
162            flight: self.flight,
163            state: marker::PhantomData,
164        }
165    }
166}
167
168impl<'d> Rejection<'d> {
169    pub(crate) const fn new(fd: handles::Descriptor<'d>, cause: Cause) -> Self {
170        Self { fd, cause }
171    }
172
173    pub fn into_parts(self) -> (handles::Descriptor<'d>, Cause) {
174        (self.fd, self.cause)
175    }
176}
177
178impl<'d> From<Error<handles::Descriptor<'d>, Vacancy>> for Rejection<'d> {
179    fn from(error: Error<handles::Descriptor<'d>, Vacancy>) -> Self {
180        let (fd, cause) = match error {
181            Error::Full(fd, error) => (fd, Cause::Submit(result::SubmitError::queue(error))),
182            Error::Reserve(fd, error) => (fd, Cause::Submit(result::SubmitError::from(error))),
183        };
184        Self::new(fd, cause)
185    }
186}
187
188impl<'d, State> Tuning<'d, State> {
189    #[doc(hidden)]
190    pub fn complete(
191        self,
192        done: tuning::Completion<'d>,
193    ) -> Result<(handles::Descriptor<'d>, Result<(), Errno>), Mismatch<Self, tuning::Completion<'d>>>
194    {
195        let outcome = match done.resolve(self.flight.target()) {
196            Ok(outcome) => outcome,
197            Err(done) => return Err(Mismatch { item: self, done }),
198        };
199        drop(self.flight);
200        Ok((self.fd, outcome))
201    }
202}
203
204impl<'d, State> Connection<'d, State> {
205    #[doc(hidden)]
206    pub fn complete(
207        self,
208        done: connect::Completion<'d>,
209    ) -> Result<
210        (handles::Descriptor<'d>, Result<(), connect::Error>),
211        Mismatch<Self, connect::Completion<'d>>,
212    > {
213        let outcome = match done.resolve(self.flight.target()) {
214            Ok(outcome) => outcome,
215            Err(done) => return Err(Mismatch { item: self, done }),
216        };
217        drop(self.flight);
218        Ok((self.fd, outcome))
219    }
220}
221
222const _: () = {
223    assert!(mem::size_of::<Live>() == 0);
224    assert!(mem::size_of::<Cancelled>() == 0);
225    assert!(
226        mem::size_of::<Tuning<'_>>()
227            == mem::size_of::<(handles::Descriptor<'_>, flight::Flight<'_>)>()
228    );
229    assert!(
230        mem::align_of::<Tuning<'_>>()
231            == mem::align_of::<(handles::Descriptor<'_>, flight::Flight<'_>)>()
232    );
233    assert!(mem::offset_of!(Tuning<'_>, fd) == 0);
234    assert!(
235        mem::size_of::<Connection<'_>>()
236            == mem::size_of::<(handles::Descriptor<'_>, flight::Flight<'_, kind::Connect>)>()
237    );
238    assert!(mem::offset_of!(Connection<'_>, fd) == 0);
239    assert!(mem::size_of::<Rejection<'_>>() == mem::size_of::<(handles::Descriptor<'_>, Cause)>());
240    assert!(
241        mem::align_of::<Rejection<'_>>() == mem::align_of::<(handles::Descriptor<'_>, Cause)>()
242    );
243    assert!(mem::size_of::<Tuning<'_, Cancelled>>() == mem::size_of::<Tuning<'_>>());
244    assert!(mem::size_of::<Connection<'_, Cancelled>>() == mem::size_of::<Connection<'_>>());
245};
246
247impl<'d> From<device::Failure<handles::Descriptor<'d>, Vacancy>> for Rejection<'d> {
248    fn from(error: device::Failure<handles::Descriptor<'d>, Vacancy>) -> Self {
249        match error {
250            device::Failure::Option(fd, error) => Self::new(fd, Cause::Option(error)),
251            device::Failure::Reserve(error) => error.into(),
252        }
253    }
254}