use std::io;
use std::os::fd::RawFd;
use crate::io_uring::op::{CompletionFlags, Op, OpReturn};
use crate::io_uring::{libc, sq};
use crate::pipe::PipeFlag;
use crate::{AsyncFd, SubmissionQueue, fd, syscall};
pub(crate) struct PipeOp;
impl Op for PipeOp {
type Output = [AsyncFd; 2];
type Resources = ([RawFd; 2], fd::Kind);
type Args = PipeFlag;
#[allow(clippy::cast_sign_loss)]
fn fill_submission(
(fds, fd_kind): &mut Self::Resources,
flags: &mut Self::Args,
submission: &mut sq::Submission,
) {
submission.0.opcode = libc::IORING_OP_PIPE as u8;
submission.0.__bindgen_anon_2 = libc::io_uring_sqe__bindgen_ty_2 {
addr: (&raw mut *fds) as u64,
};
submission.0.__bindgen_anon_3 = libc::io_uring_sqe__bindgen_ty_3 {
pipe_flags: (flags.0 | fd_kind.cloexec_flag() as u32),
};
fd_kind.create_flags(submission);
}
#[allow(clippy::cast_possible_wrap)]
fn map_ok(
sq: &SubmissionQueue,
(fds, fd_kind): Self::Resources,
(_, res): OpReturn,
) -> Self::Output {
debug_assert!(res == 0);
unsafe {
[
AsyncFd::from_raw(fds[0], fd_kind, sq.clone()),
AsyncFd::from_raw(fds[1], fd_kind, sq.clone()),
]
}
}
fn fallback(
sq: &SubmissionQueue,
(mut fds, _): Self::Resources,
err: io::Error,
) -> io::Result<Self::Output> {
if let Some(libc::EINVAL) = err.raw_os_error() {
let res = syscall!(pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?;
let resources = (fds, fd::Kind::File);
let op_return = (CompletionFlags::empty(), res.cast_unsigned());
Ok(Self::map_ok(sq, resources, op_return))
} else {
Err(err)
}
}
}