#![allow(clippy::cast_sign_loss, clippy::checked_conversions)]
use crate::types::{
AcceptFlags, FallocateMode, FileMode, FsyncFlags, IoUringSqe, IoVec, MsgFlags, MsgHdr, Opcode,
OpenFlags, PollMask, RenameFlags, ShutdownHow, SocketFlags, SqeFlags, StatxFlags, StatxMask,
TimeoutFlags, Timespec, UnlinkFlags,
};
pub struct Sqe(pub(crate) IoUringSqe);
const ZEROED: IoUringSqe = unsafe { core::mem::zeroed() };
impl Sqe {
#[must_use]
pub fn nop() -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Nop.into();
Self(sqe)
}
#[must_use]
pub fn close(fd: i32) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Close.into();
sqe.fd = fd;
Self(sqe)
}
#[must_use]
pub fn timeout_remove(target_user_data: u64) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::TimeoutRemove.into();
sqe.addr = target_user_data;
Self(sqe)
}
#[must_use]
pub fn cancel(target_user_data: u64) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::AsyncCancel.into();
sqe.addr = target_user_data;
Self(sqe)
}
#[must_use]
pub fn fsync(fd: i32, flags: FsyncFlags) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Fsync.into();
sqe.fd = fd;
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub fn fdatasync(fd: i32) -> Self {
Self::fsync(fd, FsyncFlags::DATASYNC)
}
#[must_use]
pub fn poll_add(fd: i32, mask: PollMask) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::PollAdd.into();
sqe.fd = fd;
sqe.op_flags = mask.bits();
Self(sqe)
}
#[must_use]
pub fn poll_remove(target_user_data: u64) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::PollRemove.into();
sqe.addr = target_user_data;
Self(sqe)
}
#[must_use]
pub fn fallocate(fd: i32, mode: FallocateMode, offset: u64, len: u64) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Fallocate.into();
sqe.fd = fd;
sqe.off = offset;
sqe.addr = len; sqe.len = mode.bits(); Self(sqe)
}
#[must_use]
pub fn socket(domain: i32, sock_type: i32, protocol: i32, flags: SocketFlags) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Socket.into();
sqe.fd = domain;
sqe.off = sock_type as u64;
sqe.len = protocol as u32;
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub fn shutdown(fd: i32, how: ShutdownHow) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Shutdown.into();
sqe.fd = fd;
sqe.len = how.into();
Self(sqe)
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn read(fd: i32, buf: &mut [u8], offset: u64) -> Self {
debug_assert!(buf.len() <= u32::MAX as usize);
unsafe { Self::read_ptr(fd, buf.as_mut_ptr(), buf.len() as u32, offset) }
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn write(fd: i32, buf: &[u8], offset: u64) -> Self {
debug_assert!(buf.len() <= u32::MAX as usize);
unsafe { Self::write_ptr(fd, buf.as_ptr(), buf.len() as u32, offset) }
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn readv(fd: i32, iovecs: &[IoVec], offset: u64) -> Self {
debug_assert!(iovecs.len() <= u32::MAX as usize);
unsafe { Self::readv_ptr(fd, iovecs.as_ptr(), iovecs.len() as u32, offset) }
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn writev(fd: i32, iovecs: &[IoVec], offset: u64) -> Self {
debug_assert!(iovecs.len() <= u32::MAX as usize);
unsafe { Self::writev_ptr(fd, iovecs.as_ptr(), iovecs.len() as u32, offset) }
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn send(fd: i32, buf: &[u8], flags: MsgFlags) -> Self {
debug_assert!(buf.len() <= u32::MAX as usize);
unsafe { Self::send_ptr(fd, buf.as_ptr(), buf.len() as u32, flags) }
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn recv(fd: i32, buf: &mut [u8], flags: MsgFlags) -> Self {
debug_assert!(buf.len() <= u32::MAX as usize);
unsafe { Self::recv_ptr(fd, buf.as_mut_ptr(), buf.len() as u32, flags) }
}
#[must_use]
pub fn openat(dfd: i32, path: &core::ffi::CStr, flags: OpenFlags, mode: FileMode) -> Self {
unsafe { Self::openat_ptr(dfd, path.as_ptr().cast(), flags, mode) }
}
#[must_use]
pub fn statx(
dfd: i32,
path: &core::ffi::CStr,
flags: StatxFlags,
mask: StatxMask,
statx_buf: &mut crate::types::Statx,
) -> Self {
unsafe {
Self::statx_ptr(
dfd,
path.as_ptr().cast(),
flags,
mask,
core::ptr::from_mut(statx_buf),
)
}
}
#[must_use]
pub fn renameat(
old_dfd: i32,
old_path: &core::ffi::CStr,
new_dfd: i32,
new_path: &core::ffi::CStr,
flags: RenameFlags,
) -> Self {
unsafe {
Self::renameat_ptr(
old_dfd,
old_path.as_ptr().cast(),
new_dfd,
new_path.as_ptr().cast(),
flags,
)
}
}
#[must_use]
pub fn unlinkat(dfd: i32, path: &core::ffi::CStr, flags: UnlinkFlags) -> Self {
unsafe { Self::unlinkat_ptr(dfd, path.as_ptr().cast(), flags) }
}
#[must_use]
pub fn mkdirat(dfd: i32, path: &core::ffi::CStr, mode: FileMode) -> Self {
unsafe { Self::mkdirat_ptr(dfd, path.as_ptr().cast(), mode) }
}
#[must_use]
pub fn timeout(ts: &Timespec, count: u32, flags: TimeoutFlags) -> Self {
unsafe { Self::timeout_ptr(core::ptr::from_ref(ts), count, flags) }
}
#[must_use]
pub fn link_timeout(ts: &Timespec, flags: TimeoutFlags) -> Self {
unsafe { Self::link_timeout_ptr(core::ptr::from_ref(ts), flags) }
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn connect(fd: i32, addr: &[u8]) -> Self {
unsafe { Self::connect_ptr(fd, addr.as_ptr(), addr.len() as u32) }
}
#[must_use]
pub fn accept(fd: i32, flags: AcceptFlags) -> Self {
unsafe { Self::accept_ptr(fd, core::ptr::null_mut(), core::ptr::null_mut(), flags) }
}
#[must_use]
pub fn sendmsg(fd: i32, msg: &MsgHdr, flags: MsgFlags) -> Self {
unsafe { Self::sendmsg_ptr(fd, core::ptr::from_ref(msg), flags) }
}
#[must_use]
pub fn recvmsg(fd: i32, msg: &mut MsgHdr, flags: MsgFlags) -> Self {
unsafe { Self::recvmsg_ptr(fd, core::ptr::from_mut(msg), flags) }
}
#[must_use]
pub unsafe fn read_ptr(fd: i32, buf: *mut u8, len: u32, offset: u64) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Read.into();
sqe.fd = fd;
sqe.addr = buf as u64;
sqe.len = len;
sqe.off = offset;
Self(sqe)
}
#[must_use]
pub unsafe fn write_ptr(fd: i32, buf: *const u8, len: u32, offset: u64) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Write.into();
sqe.fd = fd;
sqe.addr = buf as u64;
sqe.len = len;
sqe.off = offset;
Self(sqe)
}
#[must_use]
pub unsafe fn readv_ptr(fd: i32, iovecs: *const IoVec, nr_vecs: u32, offset: u64) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Readv.into();
sqe.fd = fd;
sqe.addr = iovecs as u64;
sqe.len = nr_vecs;
sqe.off = offset;
Self(sqe)
}
#[must_use]
pub unsafe fn writev_ptr(fd: i32, iovecs: *const IoVec, nr_vecs: u32, offset: u64) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Writev.into();
sqe.fd = fd;
sqe.addr = iovecs as u64;
sqe.len = nr_vecs;
sqe.off = offset;
Self(sqe)
}
#[must_use]
pub unsafe fn openat_ptr(dfd: i32, path: *const u8, flags: OpenFlags, mode: FileMode) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Openat.into();
sqe.fd = dfd;
sqe.addr = path as u64;
sqe.len = mode.bits();
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub unsafe fn read_fixed(fd: i32, buf: *mut u8, len: u32, offset: u64, buf_index: u16) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::ReadFixed.into();
sqe.fd = fd;
sqe.addr = buf as u64;
sqe.len = len;
sqe.off = offset;
sqe.buf_index = buf_index;
Self(sqe)
}
#[must_use]
pub unsafe fn write_fixed(
fd: i32,
buf: *const u8,
len: u32,
offset: u64,
buf_index: u16,
) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::WriteFixed.into();
sqe.fd = fd;
sqe.addr = buf as u64;
sqe.len = len;
sqe.off = offset;
sqe.buf_index = buf_index;
Self(sqe)
}
#[must_use]
pub unsafe fn timeout_ptr(ts: *const Timespec, count: u32, flags: TimeoutFlags) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Timeout.into();
sqe.addr = ts as u64;
sqe.len = 1;
sqe.off = u64::from(count);
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub unsafe fn link_timeout_ptr(ts: *const Timespec, flags: TimeoutFlags) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::LinkTimeout.into();
sqe.addr = ts as u64;
sqe.len = 1;
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub unsafe fn statx_ptr(
dfd: i32,
path: *const u8,
flags: StatxFlags,
mask: StatxMask,
statx_buf: *mut crate::types::Statx,
) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Statx.into();
sqe.fd = dfd;
sqe.off = statx_buf as u64;
sqe.addr = path as u64;
sqe.len = mask.bits();
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub unsafe fn renameat_ptr(
old_dfd: i32,
old_path: *const u8,
new_dfd: i32,
new_path: *const u8,
flags: RenameFlags,
) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Renameat.into();
sqe.fd = old_dfd;
sqe.addr = old_path as u64;
sqe.len = new_dfd as u32;
sqe.off = new_path as u64;
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub unsafe fn unlinkat_ptr(dfd: i32, path: *const u8, flags: UnlinkFlags) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Unlinkat.into();
sqe.fd = dfd;
sqe.addr = path as u64;
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub unsafe fn accept_ptr(
fd: i32,
addr: *mut u8,
addrlen: *mut u32,
flags: AcceptFlags,
) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Accept.into();
sqe.fd = fd;
sqe.addr = addr as u64;
sqe.off = addrlen as u64;
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub unsafe fn connect_ptr(fd: i32, addr: *const u8, addrlen: u32) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Connect.into();
sqe.fd = fd;
sqe.addr = addr as u64;
sqe.off = u64::from(addrlen);
Self(sqe)
}
#[must_use]
pub unsafe fn send_ptr(fd: i32, buf: *const u8, len: u32, flags: MsgFlags) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Send.into();
sqe.fd = fd;
sqe.addr = buf as u64;
sqe.len = len;
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub unsafe fn recv_ptr(fd: i32, buf: *mut u8, len: u32, flags: MsgFlags) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Recv.into();
sqe.fd = fd;
sqe.addr = buf as u64;
sqe.len = len;
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub unsafe fn sendmsg_ptr(fd: i32, msg: *const MsgHdr, flags: MsgFlags) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::SendMsg.into();
sqe.fd = fd;
sqe.addr = msg as u64;
sqe.len = 1;
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub unsafe fn recvmsg_ptr(fd: i32, msg: *mut MsgHdr, flags: MsgFlags) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::RecvMsg.into();
sqe.fd = fd;
sqe.addr = msg as u64;
sqe.len = 1;
sqe.op_flags = flags.bits();
Self(sqe)
}
#[must_use]
pub unsafe fn mkdirat_ptr(dfd: i32, path: *const u8, mode: FileMode) -> Self {
let mut sqe = ZEROED;
sqe.opcode = Opcode::Mkdirat.into();
sqe.fd = dfd;
sqe.addr = path as u64;
sqe.len = mode.bits();
Self(sqe)
}
#[must_use]
pub const fn user_data(mut self, data: u64) -> Self {
self.0.user_data = data;
self
}
#[must_use]
pub const fn flags(mut self, flags: SqeFlags) -> Self {
self.0.flags |= flags.bits();
self
}
#[must_use]
pub const fn link(mut self) -> Self {
self.0.flags |= SqeFlags::IO_LINK.bits();
self
}
#[must_use]
pub const fn hardlink(mut self) -> Self {
self.0.flags |= SqeFlags::IO_HARDLINK.bits();
self
}
#[must_use]
pub const fn fixed_file(mut self) -> Self {
self.0.flags |= SqeFlags::FIXED_FILE.bits();
self
}
#[must_use]
pub const fn drain(mut self) -> Self {
self.0.flags |= SqeFlags::IO_DRAIN.bits();
self
}
#[must_use]
pub const fn buffer_select(mut self, group_id: u16) -> Self {
self.0.flags |= SqeFlags::BUFFER_SELECT.bits();
self.0.buf_index = group_id;
self
}
}