dope_uring/driver/request/
mod.rs1mod small_slot;
2mod table;
3
4use std::{
5 io,
6 task::{Context, Poll},
7};
8
9use crate::sys::token::Completion;
10
11use super::Driver;
12use super::current::current_driver_mut;
13pub(crate) use table::Requests;
14
15#[repr(C, packed)]
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub(crate) struct RequestId {
18 index: u16,
19 epoch: u32,
20 _wire_pad: u8,
21}
22
23impl RequestId {
24 pub(crate) const EPOCH_MASK: u32 = 0x00ff_ffff;
25
26 pub(crate) fn new(index: usize, epoch: u32) -> Self {
27 Self {
28 index: u16::try_from(index)
29 .expect("dope invariant violated: request index exceeds u16 range"),
30 epoch: epoch & Self::EPOCH_MASK,
31 _wire_pad: 0,
32 }
33 }
34
35 pub(in crate::driver) fn index(self) -> usize {
36 self.index as usize
37 }
38
39 pub(in crate::driver) fn epoch(self) -> u32 {
40 self.epoch
41 }
42}
43
44enum RequestState<T> {
45 Pending { data: Box<T>, ticket: RequestTicket },
46 Done,
47}
48
49struct RequestTicket {
50 index: RequestId,
51}
52
53impl RequestTicket {
54 fn new(index: RequestId) -> Self {
55 Self { index }
56 }
57
58 fn poll(&self, cx: &mut Context<'_>) -> Poll<Completion> {
59 current_driver_mut().requests.poll(self.index, cx)
60 }
61
62 fn discard<T: 'static>(&self, data: &mut Option<T>) {
63 current_driver_mut().requests.discard(self.index, data);
64 }
65}
66
67pub struct Request<T: 'static> {
68 state: RequestState<T>,
69}
70
71impl<T: 'static> Request<T> {
72 pub(crate) fn submit_boxed(
73 ctx: &mut Driver,
74 data: Box<T>,
75 sqe: crate::Sqe,
76 ) -> Result<Self, (io::Error, Box<T>)> {
77 match ctx.submit_sqe_op(sqe) {
78 Ok(index) => Ok(Self {
79 state: RequestState::Pending {
80 data,
81 ticket: RequestTicket::new(index),
82 },
83 }),
84 Err(e) => Err((e, data)),
85 }
86 }
87}
88
89impl<T: Unpin + 'static> Request<T> {
90 pub(crate) async fn await_submit(submit: Result<Self, (io::Error, T)>) -> (io::Result<u32>, T) {
91 match submit {
92 Ok(req) => {
93 let (res, _, op) = req.await;
94 (res, op)
95 }
96 Err((e, op)) => (Err(e), op),
97 }
98 }
99}
100
101impl<T: Unpin + 'static> std::future::Future for Request<T> {
102 type Output = (io::Result<u32>, u32, T);
103
104 fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
105 let me = self.get_mut();
106 match &me.state {
107 RequestState::Pending { .. } => {}
108 RequestState::Done => panic!("dope invariant violated: polled completed request"),
109 }
110 let RequestState::Pending { ticket, .. } = &me.state else {
111 panic!("dope invariant violated: request poll state mismatch");
112 };
113 match ticket.poll(cx) {
114 Poll::Pending => Poll::Pending,
115 Poll::Ready(meta) => {
116 let RequestState::Pending { data, .. } =
117 std::mem::replace(&mut me.state, RequestState::Done)
118 else {
119 panic!("dope invariant violated: request completion state mismatch");
120 };
121 Poll::Ready((meta.result, meta.flags, *data))
122 }
123 }
124 }
125}
126
127impl<T: 'static> Drop for Request<T> {
128 fn drop(&mut self) {
129 let (ticket, data) = match std::mem::replace(&mut self.state, RequestState::Done) {
130 RequestState::Pending { ticket, data } => (ticket, data),
131 RequestState::Done => return,
132 };
133 let mut data = Some(*data);
134 ticket.discard(&mut data);
135 }
136}