#![allow(clippy::new_without_default)]
#[cfg(feature = "unstable")]
use std::mem;
#[cfg(feature = "unstable")]
use std::os::unix::io::RawFd;
use crate::squeue::Entry;
use crate::sys;
pub mod types {
use std::os::unix::io::RawFd;
use bitflags::bitflags;
use crate::sys;
pub use sys::__kernel_timespec as Timespec;
pub use sys::__kernel_rwf_t as RwFlags;
#[derive(Debug, Clone, Copy)]
pub enum Target {
Fd(RawFd),
Fixed(u32)
}
impl From<RawFd> for Target {
#[inline]
fn from(fd: RawFd) -> Self {
Target::Fd(fd)
}
}
bitflags!{
pub struct TimeoutFlags: u32 {
const ABS = sys::IORING_TIMEOUT_ABS;
}
}
bitflags!{
pub struct FsyncFlags: u32 {
const DATASYNC = sys::IORING_FSYNC_DATASYNC;
}
}
#[cfg(feature = "unstable")]
#[derive(Default, Debug, Clone, Copy)]
#[repr(transparent)]
pub struct OpenHow(sys::open_how);
#[cfg(feature = "unstable")]
impl OpenHow {
pub const fn new() -> Self {
OpenHow(sys::open_how {
flags: 0,
mode: 0,
resolve: 0
})
}
pub const fn flags(mut self, flags: u64) -> Self {
self.0.flags = flags;
self
}
pub const fn mode(mut self, mode: u64) -> Self {
self.0.mode = mode;
self
}
}
}
macro_rules! assign_fd {
( $sqe:ident . fd = $opfd:expr ) => {
match $opfd {
types::Target::Fd(fd) => $sqe.fd = fd,
types::Target::Fixed(i) => {
$sqe.fd = i as _;
$sqe.flags |= crate::squeue::Flags::FIXED_FILE.bits();
}
}
}
}
macro_rules! opcode {
(
$( #[$outer:meta] )*
pub struct $name:ident {
$( #[$new_meta:meta] )*
$( $field:ident : $tname:ty ),* $(,)?
;;
$(
$( #[$opt_meta:meta] )*
$opt_field:ident : $opt_tname:ty = $default:expr
),* $(,)?
}
pub const CODE = $opcode:expr;
pub fn build($self:ident) -> Entry $build_block:block
) => {
$( #[$outer] )*
pub struct $name {
$( $field : $tname, )*
$( $opt_field : $opt_tname, )*
}
impl $name {
$( #[$new_meta] )*
pub const fn new( $( $field : $tname ),* ) -> Self {
$name {
$( $field , )*
$( $opt_field: $default, )*
}
}
pub const CODE: u8 = $opcode as _;
$(
$( #[$opt_meta] )*
pub const fn $opt_field(mut self, $opt_field: $opt_tname) -> Self {
self.$opt_field = $opt_field;
self
}
)*
pub fn build($self) -> Entry $build_block
}
}
}
#[inline(always)]
fn sqe_zeroed() -> sys::io_uring_sqe {
unsafe { std::mem::zeroed() }
}
opcode!(
#[derive(Debug)]
pub struct Nop { ;; }
pub const CODE = sys::IORING_OP_NOP;
pub fn build(self) -> Entry {
let Nop {} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
Entry(sqe)
}
);
opcode!(
#[derive(Debug)]
pub struct Readv {
fd: types::Target,
iovec: *mut libc::iovec,
len: u32,
;;
ioprio: u16 = 0,
offset: libc::off_t = 0,
rw_flags: types::RwFlags = 0
}
pub const CODE = sys::IORING_OP_READV;
pub fn build(self) -> Entry {
let Readv {
fd,
iovec, len, offset,
ioprio, rw_flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.ioprio = ioprio;
sqe.addr = iovec as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset as _;
sqe.__bindgen_anon_2.rw_flags = rw_flags;
Entry(sqe)
}
);
opcode!(
#[derive(Debug)]
pub struct Writev {
fd: types::Target,
iovec: *const libc::iovec,
len: u32,
;;
ioprio: u16 = 0,
offset: libc::off_t = 0,
rw_flags: types::RwFlags = 0
}
pub const CODE = sys::IORING_OP_WRITEV;
pub fn build(self) -> Entry {
let Writev {
fd,
iovec, len, offset,
ioprio, rw_flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.ioprio = ioprio;
sqe.addr = iovec as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset as _;
sqe.__bindgen_anon_2.rw_flags = rw_flags;
Entry(sqe)
}
);
opcode!(
#[derive(Debug)]
pub struct Fsync {
fd: types::Target,
;;
flags: types::FsyncFlags = types::FsyncFlags::empty()
}
pub const CODE = sys::IORING_OP_FSYNC;
pub fn build(self) -> Entry {
let Fsync { fd, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.__bindgen_anon_2.fsync_flags = flags.bits();
Entry(sqe)
}
);
opcode!(
#[derive(Debug)]
pub struct ReadFixed {
fd: types::Target,
buf: *mut u8,
len: u32,
buf_index: u16,
;;
offset: libc::off_t = 0,
ioprio: u16 = 0,
rw_flags: types::RwFlags = 0
}
pub const CODE = sys::IORING_OP_READ_FIXED;
pub fn build(self) -> Entry {
let ReadFixed {
fd,
buf, len, offset,
buf_index,
ioprio, rw_flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.ioprio = ioprio;
sqe.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset as _;
sqe.__bindgen_anon_2.rw_flags = rw_flags;
sqe.__bindgen_anon_3.__bindgen_anon_1.buf_index = buf_index;
Entry(sqe)
}
);
opcode!(
#[derive(Debug)]
pub struct WriteFixed {
fd: types::Target,
buf: *const u8,
len: u32,
buf_index: u16,
;;
ioprio: u16 = 0,
offset: libc::off_t = 0,
rw_flags: types::RwFlags = 0
}
pub const CODE = sys::IORING_OP_WRITE_FIXED;
pub fn build(self) -> Entry {
let WriteFixed {
fd,
buf, len, offset,
buf_index,
ioprio, rw_flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.ioprio = ioprio;
sqe.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset as _;
sqe.__bindgen_anon_2.rw_flags = rw_flags;
sqe.__bindgen_anon_3.__bindgen_anon_1.buf_index = buf_index;
Entry(sqe)
}
);
opcode!(
#[derive(Debug)]
pub struct PollAdd {
fd: types::Target,
flags: libc::c_short,
;;
}
pub const CODE = sys::IORING_OP_POLL_ADD;
pub fn build(self) -> Entry {
let PollAdd { fd, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.__bindgen_anon_2.poll_events = flags as _;
Entry(sqe)
}
);
opcode!(
#[derive(Debug)]
pub struct PollRemove {
user_data: u64
;;
}
pub const CODE = sys::IORING_OP_POLL_REMOVE;
pub fn build(self) -> Entry {
let PollRemove { user_data } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.addr = user_data as _;
Entry(sqe)
}
);
opcode!(
#[derive(Debug)]
pub struct SyncFileRange {
fd: types::Target,
len: u32,
;;
offset: libc::off64_t = 0,
flags: u32 = 0
}
pub const CODE = sys::IORING_OP_SYNC_FILE_RANGE;
pub fn build(self) -> Entry {
let SyncFileRange {
fd,
len, offset,
flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.len = len as _;
sqe.__bindgen_anon_1.off = offset as _;
sqe.__bindgen_anon_2.sync_range_flags = flags;
Entry(sqe)
}
);
opcode!(
#[derive(Debug)]
pub struct SendMsg {
fd: types::Target,
msg: *const libc::msghdr,
;;
ioprio: u16 = 0,
flags: u32 = 0
}
pub const CODE = sys::IORING_OP_SENDMSG;
pub fn build(self) -> Entry {
let SendMsg { fd, msg, ioprio, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.ioprio = ioprio;
sqe.addr = msg as _;
sqe.len = 1;
sqe.__bindgen_anon_2.msg_flags = flags;
Entry(sqe)
}
);
opcode!(
#[derive(Debug)]
pub struct RecvMsg {
fd: types::Target,
msg: *mut libc::msghdr,
;;
ioprio: u16 = 0,
flags: u32 = 0
}
pub const CODE = sys::IORING_OP_RECVMSG;
pub fn build(self) -> Entry {
let RecvMsg { fd, msg, ioprio, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.ioprio = ioprio;
sqe.addr = msg as _;
sqe.len = 1;
sqe.__bindgen_anon_2.msg_flags = flags;
Entry(sqe)
}
);
opcode!(
#[derive(Debug)]
pub struct Timeout {
timespec: *const types::Timespec,
;;
count: u32 = 0,
flags: types::TimeoutFlags = types::TimeoutFlags::empty()
}
pub const CODE = sys::IORING_OP_TIMEOUT;
pub fn build(self) -> Entry {
let Timeout { timespec, count, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.addr = timespec as _;
sqe.len = 1;
sqe.__bindgen_anon_1.off = count as _;
sqe.__bindgen_anon_2.timeout_flags = flags.bits();
Entry(sqe)
}
);
opcode!(
pub struct TimeoutRemove {
user_data: u64,
;;
flags: types::TimeoutFlags = types::TimeoutFlags::empty()
}
pub const CODE = sys::IORING_OP_TIMEOUT_REMOVE;
pub fn build(self) -> Entry {
let TimeoutRemove { user_data, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.addr = user_data as _;
sqe.__bindgen_anon_2.timeout_flags = flags.bits();
Entry(sqe)
}
);
opcode!(
pub struct Accept {
fd: types::Target,
addr: *mut libc::sockaddr,
addrlen: *mut libc::socklen_t
;;
flags: u32 = 0
}
pub const CODE = sys::IORING_OP_ACCEPT;
pub fn build(self) -> Entry {
let Accept { fd, addr, addrlen, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.addr = addr as _;
sqe.__bindgen_anon_1.addr2 = addrlen as _;
sqe.__bindgen_anon_2.accept_flags = flags;
Entry(sqe)
}
);
opcode!(
pub struct AsyncCancel {
user_data: u64,
;;
}
pub const CODE = sys::IORING_OP_ASYNC_CANCEL;
pub fn build(self) -> Entry {
let AsyncCancel { user_data } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.addr = user_data as _;
Entry(sqe)
}
);
opcode!(
pub struct LinkTimeout {
timespec: *const types::Timespec,
;;
flags: types::TimeoutFlags = types::TimeoutFlags::empty()
}
pub const CODE = sys::IORING_OP_LINK_TIMEOUT;
pub fn build(self) -> Entry {
let LinkTimeout { timespec, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.addr = timespec as _;
sqe.len = 1;
sqe.__bindgen_anon_2.timeout_flags = flags.bits();
Entry(sqe)
}
);
opcode!(
pub struct Connect {
fd: types::Target,
addr: *const libc::sockaddr,
addrlen: libc::socklen_t
;;
}
pub const CODE = sys::IORING_OP_CONNECT;
pub fn build(self) -> Entry {
let Connect { fd, addr, addrlen } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.addr = addr as _;
sqe.__bindgen_anon_1.off = addrlen as _;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct Fallocate {
fd: types::Target,
len: u32,
;;
offset: libc::off_t = 0,
mode: i32 = 0
}
pub const CODE = sys::IORING_OP_FALLOCATE;
pub fn build(self) -> Entry {
let Fallocate { fd, len, offset, mode } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.addr = len as _;
sqe.len = mode as _;
sqe.__bindgen_anon_1.off = offset as _;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct Openat {
dirfd: types::Target,
pathname: *const libc::c_char,
;;
flags: i32 = 0,
mode: libc::mode_t = 0
}
pub const CODE = sys::IORING_OP_OPENAT;
pub fn build(self) -> Entry {
let Openat { dirfd, pathname, flags, mode } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = dirfd);
sqe.addr = pathname as _;
sqe.len = mode;
sqe.__bindgen_anon_2.open_flags = flags as _;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct Close {
fd: types::Target,
;;
}
pub const CODE = sys::IORING_OP_CLOSE;
pub fn build(self) -> Entry {
let Close { fd } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct FilesUpdate {
fds: *const RawFd,
len: u32,
;;
offset: i32 = 0
}
pub const CODE = sys::IORING_OP_FILES_UPDATE;
pub fn build(self) -> Entry {
let FilesUpdate { fds, len, offset } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.addr = fds as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset as _;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct Statx {
dirfd: types::Target,
pathname: *const libc::c_char,
statxbuf: *mut libc::statx,
;;
flags: i32 = 0,
mask: u32 = 0
}
pub const CODE = sys::IORING_OP_STATX;
pub fn build(self) -> Entry {
let Statx {
dirfd, pathname, statxbuf,
flags, mask
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = dirfd);
sqe.addr = pathname as _;
sqe.len = mask;
sqe.__bindgen_anon_1.off = statxbuf as _;
sqe.__bindgen_anon_2.statx_flags = flags as _;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct Read {
fd: types::Target,
buf: *mut u8,
len: u32,
;;
offset: libc::off_t = 0,
ioprio: u16 = 0,
rw_flags: types::RwFlags = 0
}
pub const CODE = sys::IORING_OP_READ;
pub fn build(self) -> Entry {
let Read {
fd,
buf, len, offset,
ioprio, rw_flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.ioprio = ioprio;
sqe.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset as _;
sqe.__bindgen_anon_2.rw_flags = rw_flags;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct Write {
fd: types::Target,
buf: *const u8,
len: u32,
;;
offset: libc::off_t = 0,
ioprio: u16 = 0,
rw_flags: types::RwFlags = 0
}
pub const CODE = sys::IORING_OP_WRITE;
pub fn build(self) -> Entry {
let Write {
fd,
buf, len, offset,
ioprio, rw_flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.ioprio = ioprio;
sqe.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset as _;
sqe.__bindgen_anon_2.rw_flags = rw_flags;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct Fadvise {
fd: types::Target,
len: libc::off_t,
advice: i32,
;;
offset: libc::off_t = 0,
}
pub const CODE = sys::IORING_OP_FADVISE;
pub fn build(self) -> Entry {
let Fadvise { fd, len, advice, offset } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.len = len as _;
sqe.__bindgen_anon_1.off = offset as _;
sqe.__bindgen_anon_2.fadvise_advice = advice as _;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct Madvise {
addr: *const libc::c_void,
len: libc::off_t,
advice: i32
;;
}
pub const CODE = sys::IORING_OP_MADVISE;
pub fn build(self) -> Entry {
let Madvise { addr, len, advice } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.addr = addr as _;
sqe.len = len as _;
sqe.__bindgen_anon_2.fadvise_advice = advice as _;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct Send {
fd: types::Target,
buf: *const u8,
len: u32,
;;
flags: i32 = 0
}
pub const CODE = sys::IORING_OP_SEND;
pub fn build(self) -> Entry {
let Send { fd, buf, len, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_2.msg_flags = flags as _;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct Recv {
fd: types::Target,
buf: *mut u8,
len: u32,
;;
flags: i32 = 0
}
pub const CODE = sys::IORING_OP_RECV;
pub fn build(self) -> Entry {
let Recv { fd, buf, len, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = fd);
sqe.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_2.msg_flags = flags as _;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct Openat2 {
dirfd: types::Target,
pathname: *const libc::c_char,
how: *const types::OpenHow
;;
}
pub const CODE = sys::IORING_OP_OPENAT2;
pub fn build(self) -> Entry {
let Openat2 { dirfd, pathname, how } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = dirfd);
sqe.addr = pathname as _;
sqe.len = mem::size_of::<sys::open_how>() as _;
sqe.__bindgen_anon_1.off = how as _;
Entry(sqe)
}
);
#[cfg(feature = "unstable")]
opcode!(
pub struct EpollCtl {
epfd: types::Target,
fd: RawFd,
op: i32,
ev: *const libc::epoll_event
;;
}
pub const CODE = sys::IORING_OP_EPOLL_CTL;
pub fn build(self) -> Entry {
let EpollCtl { epfd, fd, op, ev } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
assign_fd!(sqe.fd = epfd);
sqe.addr = ev as _;
sqe.len = op as _;
sqe.__bindgen_anon_1.off = fd as _;
Entry(sqe)
}
);