use core::ffi::{c_void, CStr};
use rustix::fd::{AsRawFd, BorrowedFd, RawFd};
use rustix::fs::{Mode, OFlags};
use rustix::io::ReadWriteFlags;
use rustix::io_uring::IoringOp::*;
use rustix::io_uring::{
addr3_or_cmd_union, addr_or_splice_off_in_union, buf_union, io_uring_ptr,
io_uring_user_data, ioprio_union, iovec, len_union, off_or_addr2_union,
op_flags_union, splice_fd_in_or_file_index_or_addr_len_union,
IoringCqeFlags, IoringOp, IoringSqeFlags,
};
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
pub struct Cqe {
pub user_data: io_uring_user_data,
pub res: i32,
pub flags: IoringCqeFlags,
}
#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct Sqe {
pub opcode: IoringOp,
pub flags: IoringSqeFlags,
pub ioprio: ioprio_union,
pub fd: RawFd,
pub off_or_addr2: off_or_addr2_union,
pub addr_or_splice_off_in: addr_or_splice_off_in_union,
pub len: len_union,
pub op_flags: op_flags_union,
pub user_data: io_uring_user_data,
pub buf: buf_union,
pub personality: u16,
pub splice_fd_in_or_file_index_or_addr_len:
splice_fd_in_or_file_index_or_addr_len_union,
pub addr3_or_cmd: addr3_or_cmd_union,
}
impl Sqe {
pub fn addr(&self) -> io_uring_ptr {
unsafe { self.addr_or_splice_off_in.addr }
}
pub fn off(&self) -> u64 {
unsafe { self.off_or_addr2.off }
}
pub fn prep_nop(&mut self, user_data: u64) {
self.opcode = Nop;
self.user_data = user_data.into();
}
pub fn prep_fsync(
&mut self,
user_data: u64,
fd: BorrowedFd,
flags: ReadWriteFlags,
) {
self.opcode = Fsync;
self.fd = fd.as_raw_fd();
self.op_flags.rw_flags = flags;
self.user_data.u64_ = user_data;
}
pub fn set_len(&mut self, len: usize) {
self.len.len =
len.try_into().expect("io_uring requires lengths to fit in a u32");
}
pub fn set_buf<T>(&mut self, ptr: *const T, len: usize, offset: u64) {
self.addr_or_splice_off_in.addr = io_uring_ptr::new(ptr as *mut c_void);
self.set_len(len);
self.off_or_addr2.off = offset;
}
pub fn prep_read(
&mut self,
user_data: u64,
fd: BorrowedFd,
buf: &mut [u8],
offset: u64,
) {
self.opcode = Read;
self.fd = fd.as_raw_fd();
self.set_buf(buf.as_ptr(), buf.len(), offset);
self.user_data.u64_ = user_data;
}
pub fn prep_readv(
&mut self,
user_data: u64,
fd: BorrowedFd,
iovecs: &[iovec],
offset: u64,
) {
self.opcode = Readv;
self.fd = fd.as_raw_fd();
self.set_buf(iovecs.as_ptr(), iovecs.len(), offset);
self.user_data.u64_ = user_data;
}
pub fn prep_readv_fixed(
&mut self,
user_data: u64,
file_index: usize,
iovecs: &[iovec],
offset: u64,
) {
self.opcode = Readv;
self.fd = file_index
.try_into()
.expect("fixed file index must fit into a u32");
self.set_buf(iovecs.as_ptr(), iovecs.len(), offset);
self.flags.set(IoringSqeFlags::FIXED_FILE, true);
self.user_data.u64_ = user_data;
}
pub fn prep_write(
&mut self,
user_data: u64,
fd: BorrowedFd,
buf: &[u8],
offset: u64,
) {
self.opcode = Write;
self.fd = fd.as_raw_fd();
self.set_buf(buf.as_ptr(), buf.len(), offset);
self.user_data.u64_ = user_data;
}
pub fn prep_writev(
&mut self,
user_data: u64,
fd: BorrowedFd,
iovecs: &[iovec],
offset: u64,
) {
self.opcode = Writev;
self.fd = fd.as_raw_fd();
self.set_buf(iovecs.as_ptr(), iovecs.len(), offset);
self.user_data.u64_ = user_data;
}
pub fn prep_splice(
&mut self,
user_data: u64,
fd_in: BorrowedFd,
off_in: u64,
fd_out: BorrowedFd,
off_out: u64,
len: usize,
) {
self.opcode = Splice;
self.fd = fd_out.as_raw_fd();
self.set_len(len);
self.off_or_addr2.off = off_out;
self.addr_or_splice_off_in.splice_off_in = off_in;
self.splice_fd_in_or_file_index_or_addr_len.splice_fd_in =
fd_in.as_raw_fd();
self.user_data.u64_ = user_data;
}
pub fn prep_write_fixed(
&mut self,
user_data: u64,
fd: BorrowedFd,
buffer: &iovec,
offset: u64,
buffer_index: u16,
) {
self.opcode = WriteFixed;
self.fd = fd.as_raw_fd();
self.set_buf(buffer.iov_base, buffer.iov_len, offset);
self.buf.buf_index = buffer_index;
self.user_data.u64_ = user_data;
}
pub fn prep_read_fixed(
&mut self,
user_data: u64,
fd: BorrowedFd,
buffer: &mut iovec,
offset: u64,
buffer_index: u16,
) {
self.opcode = ReadFixed;
self.fd = fd.as_raw_fd();
self.set_buf(buffer.iov_base, buffer.iov_len, offset);
self.buf.buf_index = buffer_index;
self.user_data.u64_ = user_data;
}
pub fn prep_openat(
&mut self,
user_data: u64,
fd: BorrowedFd,
path: &CStr,
flags: OFlags,
mode: Mode,
) {
self.opcode = Openat;
self.fd = fd.as_raw_fd();
self.set_buf(path.as_ptr(), mode.as_raw_mode() as usize, 0);
self.op_flags.open_flags = flags;
self.user_data.u64_ = user_data;
}
}