1use std::{ffi::CString, hint::unreachable_unchecked};
2
3use compio_buf::{IntoInner, IoBuf, IoBufMut, IoVectoredBuf, IoVectoredBufMut};
4use socket2::SockAddr;
5
6use super::*;
7pub use crate::sys::unix_op::*;
8
9macro_rules! op {
10 (<$($ty:ident: $trait:ident),* $(,)?> $name:ident( $($arg:ident: $arg_t:ty),* $(,)? )) => {
11 ::paste::paste!{
12 enum [< $name Inner >] <$($ty: $trait),*> {
13 Uninit($($arg_t),*),
14 Poll(poll::$name<$($ty),*>),
15 IoUring(iour::$name<$($ty),*>),
16 }
17
18 impl<$($ty: $trait),*> [< $name Inner >]<$($ty),*> {
19 fn poll(&mut self) -> &mut poll::$name<$($ty),*> {
20 match self {
21 Self::Uninit(..) => {
22 unsafe {
23 let Self::Uninit($($arg),*) = std::ptr::read(self) else {
24 unreachable_unchecked()
25 };
26 std::ptr::write(self, Self::Poll(poll::$name::new($($arg),*)));
27 }
28 self.poll()
29 },
30 Self::Poll(op) => op,
31 Self::IoUring(_) => unreachable!("Current driver is not `polling`"),
32 }
33 }
34
35 fn iour(&mut self) -> &mut iour::$name<$($ty),*> {
36 match self {
37 Self::Uninit(..) => {
38 unsafe {
39 let Self::Uninit($($arg),*) = std::ptr::read(self) else {
40 unreachable_unchecked()
41 };
42 std::ptr::write(self, Self::IoUring(iour::$name::new($($arg),*)));
43 }
44 self.iour()
45 },
46 Self::IoUring(op) => op,
47 Self::Poll(_) => unreachable!("Current driver is not `io-uring`"),
48 }
49 }
50 }
51
52 #[doc = concat!("A fused `", stringify!($name), "` operation")]
53 pub struct $name <$($ty: $trait),*> {
54 inner: [< $name Inner >] <$($ty),*>
55 }
56
57 impl<$($ty: $trait),*> IntoInner for $name <$($ty),*> {
58 type Inner = <poll::$name<$($ty),*> as IntoInner>::Inner;
59
60 fn into_inner(mut self) -> Self::Inner {
61 match self.inner {
62 [< $name Inner >]::Uninit(..) => {
63 self.inner.poll();
64 self.into_inner()
65 },
66 [< $name Inner >]::Poll(op) => op.into_inner(),
67 [< $name Inner >]::IoUring(op) => op.into_inner(),
68 }
69 }
70 }
71
72 impl<$($ty: $trait),*> $name <$($ty),*> {
73 #[doc = concat!("Create a new `", stringify!($name), "`.")]
74 pub fn new($($arg: $arg_t),*) -> Self {
75 Self { inner: [< $name Inner >]::Uninit($($arg),*) }
76 }
77 }
78 }
79
80 unsafe impl<$($ty: $trait),*> poll::OpCode for $name<$($ty),*> {
81 fn pre_submit(self: std::pin::Pin<&mut Self>) -> std::io::Result<crate::Decision> {
82 unsafe { self.map_unchecked_mut(|x| x.inner.poll() ) }.pre_submit()
83 }
84
85 fn op_type(self: std::pin::Pin<&mut Self>) -> Option<OpType> {
86 unsafe { self.map_unchecked_mut(|x| x.inner.poll() ) }.op_type()
87 }
88
89 fn operate(
90 self: std::pin::Pin<&mut Self>,
91 ) -> std::task::Poll<std::io::Result<usize>> {
92 unsafe { self.map_unchecked_mut(|x| x.inner.poll() ) }.operate()
93 }
94 }
95
96 unsafe impl<$($ty: $trait),*> iour::OpCode for $name<$($ty),*> {
97 fn create_entry(self: std::pin::Pin<&mut Self>) -> OpEntry {
98 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ) }.create_entry()
99 }
100
101 fn create_entry_fallback(self: std::pin::Pin<&mut Self>) -> OpEntry {
102 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ) }.create_entry_fallback()
103 }
104
105 fn call_blocking(self: std::pin::Pin<&mut Self>) -> std::io::Result<usize> {
106 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ) }.call_blocking()
107 }
108
109 unsafe fn set_result(self: std::pin::Pin<&mut Self>, result: &std::io::Result<usize>, extra: &crate::Extra) {
110 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ).set_result(result, extra) }
111 }
112
113 unsafe fn push_multishot(self: std::pin::Pin<&mut Self>, result: std::io::Result<usize>, extra: crate::Extra) {
114 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ).push_multishot(result, extra) }
115 }
116
117 fn pop_multishot(self: std::pin::Pin<&mut Self>) -> Option<BufResult<usize, crate::Extra>> {
118 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ) }.pop_multishot()
119 }
120 }
121 };
122}
123
124#[rustfmt::skip]
125mod iour { pub use crate::sys::iour::{op::*, OpCode}; }
126#[rustfmt::skip]
127mod poll { pub use crate::sys::poll::{op::*, OpCode}; }
128
129op!(<S: AsFd> AcceptMulti(fd: S));
130op!(<T: IoBufMut, S: AsFd> RecvFrom(fd: S, buffer: T, flags: i32));
131op!(<T: IoBuf, S: AsFd> SendTo(fd: S, buffer: T, addr: SockAddr, flags: i32));
132op!(<T: IoVectoredBufMut, S: AsFd> RecvFromVectored(fd: S, buffer: T, flags: i32));
133op!(<T: IoVectoredBuf, S: AsFd> SendToVectored(fd: S, buffer: T, addr: SockAddr, flags: i32));
134op!(<S: AsFd> FileStat(fd: S));
135op!(<S: AsFd> PathStat(dirfd: S, path: CString, follow_symlink: bool));
136op!(<T: IoBuf, S: AsFd> SendZc(fd: S, buffer: T, flags: i32));
137op!(<T: IoVectoredBuf, S: AsFd> SendVectoredZc(fd: S, buffer: T, flags: i32));
138op!(<T: IoBuf, S: AsFd> SendToZc(fd: S, buffer: T, addr: SockAddr, flags: i32));
139op!(<T: IoVectoredBuf, S: AsFd> SendToVectoredZc(fd: S, buffer: T, addr: SockAddr, flags: i32));
140op!(<T: IoVectoredBuf, C: IoBuf, S: AsFd> SendMsgZc(fd: S, buffer: T, control: C, addr: Option<SockAddr>, flags: i32));
141
142macro_rules! mop {
143 (<$($ty:ident: $trait:ident),* $(,)?> $name:ident( $($arg:ident: $arg_t:ty),* $(,)? ) with $pool:ident) => {
144 mop!{ < $($ty: $trait),* > $name ( $( $arg: $arg_t ),* ) with $pool, buffer: crate::BorrowedBuffer<'a> }
145 };
146 (<$($ty:ident: $trait:ident),* $(,)?> $name:ident( $($arg:ident: $arg_t:ty),* $(,)? ) with $pool:ident, buffer: $buffer:ty) => {
147 ::paste::paste!{
148 enum [< $name Inner >] <$($ty: $trait),*> {
149 Poll(crate::op::managed::$name<$($ty),*>),
150 IoUring(iour::$name<$($ty),*>),
151 }
152
153 impl<$($ty: $trait),*> [< $name Inner >]<$($ty),*> {
154 fn poll(&mut self) -> &mut crate::op::managed::$name<$($ty),*> {
155 match self {
156 Self::Poll(op) => op,
157 Self::IoUring(_) => unreachable!("Current driver is not `io-uring`"),
158 }
159 }
160
161 fn iour(&mut self) -> &mut iour::$name<$($ty),*> {
162 match self {
163 Self::IoUring(op) => op,
164 Self::Poll(_) => unreachable!("Current driver is not `polling`"),
165 }
166 }
167 }
168
169 #[doc = concat!("A fused `", stringify!($name), "` operation")]
170 pub struct $name <$($ty: $trait),*> {
171 inner: [< $name Inner >] <$($ty),*>
172 }
173
174 impl<$($ty: $trait),*> $name <$($ty),*> {
175 #[doc = concat!("Create a new `", stringify!($name), "`.")]
176 pub fn new($($arg: $arg_t),*) -> std::io::Result<Self> {
177 Ok(if $pool.is_io_uring() {
178 Self {
179 inner: [< $name Inner >]::IoUring(iour::$name::new($($arg),*)?),
180 }
181 } else {
182 Self {
183 inner: [< $name Inner >]::Poll(crate::op::managed::$name::new($($arg),*)?),
184 }
185 })
186 }
187 }
188
189 impl<$($ty: $trait),*> crate::TakeBuffer for $name<$($ty),*> {
190 type BufferPool = crate::BufferPool;
191 type Buffer<'a> = $buffer;
192
193 fn take_buffer(
194 self,
195 buffer_pool: &Self::BufferPool,
196 result: io::Result<usize>,
197 buffer_id: u16,
198 ) -> io::Result<Self::Buffer<'_>> {
199 match self.inner {
200 [< $name Inner >]::Poll(inner) => {
201 Ok(inner.take_buffer(buffer_pool, result, buffer_id)?)
202 }
203 [< $name Inner >]::IoUring(inner) => {
204 Ok(inner.take_buffer(buffer_pool, result, buffer_id)?)
205 }
206 }
207 }
208 }
209 }
210
211 unsafe impl<$($ty: $trait),*> poll::OpCode for $name<$($ty),*> {
212 fn pre_submit(self: std::pin::Pin<&mut Self>) -> std::io::Result<crate::Decision> {
213 unsafe { self.map_unchecked_mut(|x| x.inner.poll() ) }.pre_submit()
214 }
215
216 fn op_type(self: std::pin::Pin<&mut Self>) -> Option<OpType> {
217 unsafe { self.map_unchecked_mut(|x| x.inner.poll() ) }.op_type()
218 }
219
220 fn operate(
221 self: std::pin::Pin<&mut Self>,
222 ) -> std::task::Poll<std::io::Result<usize>> {
223 unsafe { self.map_unchecked_mut(|x| x.inner.poll() ) }.operate()
224 }
225 }
226
227 unsafe impl<$($ty: $trait),*> iour::OpCode for $name<$($ty),*> {
228 fn create_entry(self: std::pin::Pin<&mut Self>) -> OpEntry {
229 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ) }.create_entry()
230 }
231
232 fn create_entry_fallback(self: std::pin::Pin<&mut Self>) -> OpEntry {
233 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ) }.create_entry_fallback()
234 }
235
236 fn call_blocking(self: std::pin::Pin<&mut Self>) -> std::io::Result<usize> {
237 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ) }.call_blocking()
238 }
239
240 unsafe fn set_result(self: std::pin::Pin<&mut Self>, result: &std::io::Result<usize>, extra: &crate::Extra) {
241 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ).set_result(result, extra) }
242 }
243
244 unsafe fn push_multishot(self: std::pin::Pin<&mut Self>, result: std::io::Result<usize>, extra: crate::Extra) {
245 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ).push_multishot(result, extra) }
246 }
247
248 fn pop_multishot(self: std::pin::Pin<&mut Self>) -> Option<BufResult<usize, crate::Extra>> {
249 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ) }.pop_multishot()
250 }
251 }
252 };
253}
254
255mop!(<S: AsFd> ReadManagedAt(fd: S, offset: u64, pool: &BufferPool, len: usize) with pool);
256mop!(<S: AsFd> ReadManaged(fd: S, pool: &BufferPool, len: usize) with pool);
257mop!(<S: AsFd> RecvManaged(fd: S, pool: &BufferPool, len: usize, flags: i32) with pool);
258mop!(<S: AsFd> RecvFromManaged(fd: S, pool: &BufferPool, len: usize, flags: i32) with pool, buffer: (crate::BorrowedBuffer<'a>, Option<SockAddr>));
259mop!(<S: AsFd> ReadMultiAt(fd: S, offset: u64, pool: &BufferPool, len: usize) with pool);
260mop!(<S: AsFd> ReadMulti(fd: S, pool: &BufferPool, len: usize) with pool);
261mop!(<S: AsFd> RecvMulti(fd: S, pool: &BufferPool, len: usize, flags: i32) with pool);