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::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(ref mut op) => op,
31 Self::IoUring(_) => unreachable!("Current driver is not `io-uring`"),
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(ref mut op) => op,
47 Self::Poll(_) => unreachable!("Current driver is not `polling`"),
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 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 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 };
102}
103
104#[rustfmt::skip]
105mod iour { pub use crate::sys::iour::{op::*, OpCode}; }
106#[rustfmt::skip]
107mod poll { pub use crate::sys::poll::{op::*, OpCode}; }
108
109op!(<T: IoBufMut, S: AsFd> RecvFrom(fd: S, buffer: T));
110op!(<T: IoBuf, S: AsFd> SendTo(fd: S, buffer: T, addr: SockAddr));
111op!(<T: IoVectoredBufMut, S: AsFd> RecvFromVectored(fd: S, buffer: T));
112op!(<T: IoVectoredBuf, S: AsFd> SendToVectored(fd: S, buffer: T, addr: SockAddr));
113op!(<S: AsFd> FileStat(fd: S));
114op!(<> PathStat(path: CString, follow_symlink: bool));
115
116macro_rules! mop {
117 (<$($ty:ident: $trait:ident),* $(,)?> $name:ident( $($arg:ident: $arg_t:ty),* $(,)? ) with $pool:ident) => {
118 ::paste::paste!{
119 enum [< $name Inner >] <$($ty: $trait),*> {
120 Poll(crate::op::managed::$name<$($ty),*>),
121 IoUring(iour::$name<$($ty),*>),
122 }
123
124 impl<$($ty: $trait),*> [< $name Inner >]<$($ty),*> {
125 fn poll(&mut self) -> &mut crate::op::managed::$name<$($ty),*> {
126 match self {
127 Self::Poll(ref mut op) => op,
128 Self::IoUring(_) => unreachable!("Current driver is not `io-uring`"),
129 }
130 }
131
132 fn iour(&mut self) -> &mut iour::$name<$($ty),*> {
133 match self {
134 Self::IoUring(ref mut op) => op,
135 Self::Poll(_) => unreachable!("Current driver is not `polling`"),
136 }
137 }
138 }
139
140 #[doc = concat!("A fused `", stringify!($name), "` operation")]
141 pub struct $name <$($ty: $trait),*> {
142 inner: [< $name Inner >] <$($ty),*>
143 }
144
145 impl<$($ty: $trait),*> $name <$($ty),*> {
146 #[doc = concat!("Create a new `", stringify!($name), "`.")]
147 pub fn new($($arg: $arg_t),*) -> std::io::Result<Self> {
148 Ok(if $pool.is_io_uring() {
149 Self {
150 inner: [< $name Inner >]::IoUring(iour::$name::new($($arg),*)?),
151 }
152 } else {
153 Self {
154 inner: [< $name Inner >]::Poll(crate::op::managed::$name::new($($arg),*)?),
155 }
156 })
157 }
158 }
159
160 impl<$($ty: $trait),*> crate::TakeBuffer for $name<$($ty),*> {
161 type BufferPool = crate::BufferPool;
162 type Buffer<'a> = crate::BorrowedBuffer<'a>;
163
164 fn take_buffer(
165 self,
166 buffer_pool: &Self::BufferPool,
167 result: io::Result<usize>,
168 flags: u32,
169 ) -> io::Result<Self::Buffer<'_>> {
170 match self.inner {
171 [< $name Inner >]::Poll(inner) => {
172 Ok(inner.take_buffer(buffer_pool, result, flags)?)
173 }
174 [< $name Inner >]::IoUring(inner) => {
175 Ok(inner.take_buffer(buffer_pool, result, flags)?)
176 }
177 }
178 }
179 }
180 }
181
182 impl<$($ty: $trait),*> poll::OpCode for $name<$($ty),*> {
183 fn pre_submit(self: std::pin::Pin<&mut Self>) -> std::io::Result<crate::Decision> {
184 unsafe { self.map_unchecked_mut(|x| x.inner.poll() ) }.pre_submit()
185 }
186
187 fn op_type(self: std::pin::Pin<&mut Self>) -> Option<OpType> {
188 unsafe { self.map_unchecked_mut(|x| x.inner.poll() ) }.op_type()
189 }
190
191 fn operate(
192 self: std::pin::Pin<&mut Self>,
193 ) -> std::task::Poll<std::io::Result<usize>> {
194 unsafe { self.map_unchecked_mut(|x| x.inner.poll() ) }.operate()
195 }
196 }
197
198 impl<$($ty: $trait),*> iour::OpCode for $name<$($ty),*> {
199 fn create_entry(self: std::pin::Pin<&mut Self>) -> OpEntry {
200 unsafe { self.map_unchecked_mut(|x| x.inner.iour() ) }.create_entry()
201 }
202 }
203 };
204}
205
206mop!(<S: AsFd> ReadManagedAt(fd: S, offset: u64, pool: &BufferPool, len: usize) with pool);
207mop!(<S: AsFd> RecvManaged(fd: S, pool: &BufferPool, len: usize) with pool);