macro_rules! bitflags {
(
$(#[$meta:meta])*
$vis:vis struct $Name:ident($inner:ty);
$(
$(#[$cmeta:meta])*
const $FLAG:ident = $value:expr;
)*
) => {
$(#[$meta])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
$vis struct $Name($inner);
impl $Name {
$(
$(#[$cmeta])*
pub const $FLAG: Self = Self($value);
)*
#[must_use]
pub const fn bits(self) -> $inner {
self.0
}
#[must_use]
pub const fn contains(self, flag: Self) -> bool {
(self.0 & flag.0) == flag.0
}
}
impl PartialEq<$inner> for $Name {
fn eq(&self, other: &$inner) -> bool {
self.0 == *other
}
}
impl core::ops::BitOr for $Name {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
}
impl core::ops::BitOrAssign for $Name {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl core::ops::BitAnd for $Name {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
Self(self.0 & rhs.0)
}
}
impl core::ops::BitAndAssign for $Name {
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
}
impl core::ops::Not for $Name {
type Output = Self;
fn not(self) -> Self {
Self(!self.0)
}
}
};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
#[repr(u8)]
pub enum Opcode {
Nop = 0,
Readv = 1,
Writev = 2,
Fsync = 3,
ReadFixed = 4,
WriteFixed = 5,
PollAdd = 6,
PollRemove = 7,
SendMsg = 9,
RecvMsg = 10,
Timeout = 11,
TimeoutRemove = 12,
Accept = 13,
AsyncCancel = 14,
LinkTimeout = 15,
Connect = 16,
Fallocate = 17,
Openat = 18,
Close = 19,
Statx = 21,
Read = 22,
Write = 23,
Send = 26,
Recv = 27,
Shutdown = 34,
Renameat = 35,
Unlinkat = 36,
Mkdirat = 37,
Socket = 45,
}
impl PartialEq<u8> for Opcode {
fn eq(&self, other: &u8) -> bool {
*self as u8 == *other
}
}
impl From<Opcode> for u8 {
fn from(op: Opcode) -> Self {
op as Self
}
}
bitflags! {
pub struct EnterFlags(u32);
const GETEVENTS = 1 << 0;
const SQ_WAKEUP = 1 << 1;
}
bitflags! {
pub struct SetupFlags(u32);
const SQPOLL = 1 << 1;
const SQ_AFF = 1 << 2;
const CQSIZE = 1 << 3;
const CLAMP = 1 << 4;
const ATTACH_WQ = 1 << 5;
const SINGLE_ISSUER = 1 << 12;
}
bitflags! {
pub struct Features(u32);
const SINGLE_MMAP = 1 << 0;
const NODROP = 1 << 1;
const SUBMIT_STABLE = 1 << 2;
const RW_CUR_POS = 1 << 3;
const CUR_PERSONALITY = 1 << 4;
const FAST_POLL = 1 << 5;
const POLL_32BITS = 1 << 6;
const SQPOLL_NONFIXED = 1 << 7;
const EXT_ARG = 1 << 8;
const NATIVE_WORKERS = 1 << 9;
}
impl Features {
pub(crate) const fn from_raw(raw: u32) -> Self {
Self(raw)
}
}
bitflags! {
pub struct SqeFlags(u8);
const FIXED_FILE = 1 << 0;
const IO_DRAIN = 1 << 1;
const IO_LINK = 1 << 2;
const IO_HARDLINK = 1 << 3;
const IO_ASYNC = 1 << 4;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum RegisterOp {
RegisterBuffers = 0,
UnregisterBuffers = 1,
RegisterFiles = 2,
UnregisterFiles = 3,
RegisterFilesUpdate = 6,
}
impl From<RegisterOp> for u32 {
fn from(op: RegisterOp) -> Self {
op as Self
}
}
bitflags! {
pub struct Prot(u32);
const READ = 0x1;
const WRITE = 0x2;
}
bitflags! {
pub struct MapFlags(u32);
const SHARED = 0x01;
const POPULATE = 0x0000_8000;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u64)]
pub enum RingOffset {
SqRing = 0,
CqRing = 0x0800_0000,
Sqes = 0x1000_0000,
}
impl PartialEq<u64> for RingOffset {
fn eq(&self, other: &u64) -> bool {
*self as u64 == *other
}
}
impl From<RingOffset> for u64 {
fn from(off: RingOffset) -> Self {
off as Self
}
}
bitflags! {
pub struct OpenFlags(u32);
const WRONLY = 1;
const RDWR = 2;
const CREAT = 0o100;
const TRUNC = 0o1000;
const TMPFILE = 0o20_200_000;
}
pub const AT_FDCWD: i32 = -100;
bitflags! {
pub struct FileMode(u32);
const OWNER_READ = 0o400;
const OWNER_WRITE = 0o200;
const OWNER_EXEC = 0o100;
const GROUP_READ = 0o040;
const GROUP_WRITE = 0o020;
const GROUP_EXEC = 0o010;
const OTHER_READ = 0o004;
const OTHER_WRITE = 0o002;
const OTHER_EXEC = 0o001;
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct IoSqringOffsets {
pub head: u32,
pub tail: u32,
pub ring_mask: u32,
pub ring_entries: u32,
pub flags: u32,
pub dropped: u32,
pub array: u32,
pub resv1: u32,
pub user_addr: u64,
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct IoCqringOffsets {
pub head: u32,
pub tail: u32,
pub ring_mask: u32,
pub ring_entries: u32,
pub overflow: u32,
pub cqes: u32,
pub flags: u32,
pub resv1: u32,
pub user_addr: u64,
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct IoUringParams {
pub sq_entries: u32,
pub cq_entries: u32,
pub flags: u32,
pub sq_thread_cpu: u32,
pub sq_thread_idle: u32,
pub features: u32,
pub wq_fd: u32,
pub resv: [u32; 3],
pub sq_off: IoSqringOffsets,
pub cq_off: IoCqringOffsets,
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct IoUringSqe {
pub opcode: u8,
pub flags: u8,
pub ioprio: u16,
pub fd: i32,
pub off: u64,
pub addr: u64,
pub len: u32,
pub op_flags: u32,
pub user_data: u64,
pub buf_index: u16,
pub personality: u16,
pub splice_fd_in: i32,
pub addr3: u64,
pub(crate) _pad2: [u64; 1],
}
impl Default for IoUringSqe {
fn default() -> Self {
unsafe { core::mem::zeroed() }
}
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct IoUringCqe {
pub user_data: u64,
pub res: i32,
pub flags: u32,
}
bitflags! {
pub struct CqeFlags(u32);
const BUFFER = 1 << 0;
const MORE = 1 << 1;
const SOCK_NONEMPTY = 1 << 2;
const NOTIF = 1 << 3;
}
impl CqeFlags {
pub(crate) const fn from_raw(raw: u32) -> Self {
Self(raw)
}
}
pub type RawFd = i32;
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct IoVec {
base: *mut u8,
len: usize,
}
impl IoVec {
#[must_use]
pub const unsafe fn new(base: *mut u8, len: usize) -> Self {
Self { base, len }
}
#[must_use]
pub const fn base(&self) -> *mut u8 {
self.base
}
#[must_use]
pub const fn len(&self) -> usize {
self.len
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct Timespec {
tv_sec: i64,
tv_nsec: i64,
}
impl Timespec {
#[must_use]
pub const fn new(sec: i64, nsec: i64) -> Self {
assert!(
nsec >= 0 && nsec < 1_000_000_000,
"nsec out of range 0..1_000_000_000"
);
Self {
tv_sec: sec,
tv_nsec: nsec,
}
}
#[must_use]
#[allow(clippy::cast_possible_wrap)]
pub const fn from_millis(ms: u64) -> Self {
Self::new((ms / 1000) as i64, ((ms % 1000) * 1_000_000) as i64)
}
#[must_use]
pub const fn tv_sec(&self) -> i64 {
self.tv_sec
}
#[must_use]
pub const fn tv_nsec(&self) -> i64 {
self.tv_nsec
}
}
bitflags! {
pub struct TimeoutFlags(u32);
const ABS = 1 << 0;
}
bitflags! {
pub struct FsyncFlags(u32);
const DATASYNC = 1 << 0;
}
bitflags! {
pub struct PollMask(u32);
const IN = 0x0001;
const OUT = 0x0004;
const ERR = 0x0008;
const HUP = 0x0010;
const RDHUP = 0x2000;
}
bitflags! {
pub struct FallocateMode(u32);
const KEEP_SIZE = 0x01;
const PUNCH_HOLE = 0x02;
const ZERO_RANGE = 0x10;
}
bitflags! {
pub struct StatxFlags(u32);
const EMPTY_PATH = 0x1000;
const SYMLINK_NOFOLLOW = 0x100;
}
bitflags! {
pub struct StatxMask(u32);
const TYPE = 0x0001;
const MODE = 0x0002;
const NLINK = 0x0004;
const UID = 0x0008;
const GID = 0x0010;
const ATIME = 0x0020;
const MTIME = 0x0040;
const CTIME = 0x0080;
const INO = 0x0100;
const SIZE = 0x0200;
const BLOCKS = 0x0400;
const BASIC_STATS = 0x07FF;
const ALL = 0x0FFF;
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct StatxTimestamp {
pub tv_sec: i64,
pub tv_nsec: u32,
pub(crate) _reserved: i32,
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct Statx {
pub stx_mask: u32,
pub stx_blksize: u32,
pub stx_attributes: u64,
pub stx_nlink: u32,
pub stx_uid: u32,
pub stx_gid: u32,
pub stx_mode: u16,
pub(crate) _spare0: u16,
pub stx_ino: u64,
pub stx_size: u64,
pub stx_blocks: u64,
pub stx_attributes_mask: u64,
pub stx_atime: StatxTimestamp,
pub stx_btime: StatxTimestamp,
pub stx_ctime: StatxTimestamp,
pub stx_mtime: StatxTimestamp,
pub stx_rdev_major: u32,
pub stx_rdev_minor: u32,
pub stx_dev_major: u32,
pub stx_dev_minor: u32,
pub stx_mnt_id: u64,
pub stx_dio_mem_align: u32,
pub stx_dio_offset_align: u32,
pub(crate) _spare3: [u64; 12],
}
bitflags! {
pub struct RenameFlags(u32);
const NOREPLACE = 1 << 0;
const EXCHANGE = 1 << 1;
}
bitflags! {
pub struct UnlinkFlags(u32);
const REMOVEDIR = 0x200;
}
pub const AF_INET: i32 = 2;
pub const AF_INET6: i32 = 10;
pub const SOCK_STREAM: i32 = 1;
pub const SOCK_DGRAM: i32 = 2;
pub const SOCK_NONBLOCK: i32 = 0o4000;
pub const SOL_SOCKET: i32 = 1;
pub const SO_REUSEADDR: i32 = 2;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum ShutdownHow {
Read = 0,
Write = 1,
Both = 2,
}
impl From<ShutdownHow> for u32 {
fn from(how: ShutdownHow) -> Self {
how as Self
}
}
bitflags! {
pub struct MsgFlags(u32);
const DONTWAIT = 0x40;
const NOSIGNAL = 0x4000;
const WAITALL = 0x100;
}
bitflags! {
pub struct AcceptFlags(u32);
const NONBLOCK = 0o4000;
}
bitflags! {
pub struct SocketFlags(u32);
const NONBLOCK = 0o4000;
const CLOEXEC = 0o2_000_000;
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct SockAddrIn {
pub sin_family: u16,
pub sin_port: u16,
pub sin_addr: u32,
pub sin_zero: [u8; 8],
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct MsgHdr {
pub msg_name: *mut u8,
pub msg_namelen: u32,
pub(crate) _pad1: u32,
pub msg_iov: *mut IoVec,
pub msg_iovlen: usize,
pub msg_control: *mut u8,
pub msg_controllen: usize,
pub msg_flags: i32,
pub(crate) _pad2: u32,
}
impl Default for MsgHdr {
fn default() -> Self {
unsafe { core::mem::zeroed() }
}
}