use std::{
io::{self, IoSlice, IoSliceMut},
os::{fd::AsFd, unix::io::BorrowedFd},
pin::Pin,
};
use mio::{event, Interest, Registry, Token};
pub use nix::sys::aio::AioFsyncMode;
use nix::{
libc::off_t,
sys::{
aio::{self, Aio},
event::EvFlags,
signal::SigevNotify,
},
};
pub type ReadAt<'a> = Source<aio::AioRead<'a>>;
pub type ReadvAt<'a> = Source<aio::AioReadv<'a>>;
pub type Fsync<'a> = Source<aio::AioFsync<'a>>;
pub type WriteAt<'a> = Source<aio::AioWrite<'a>>;
pub type WritevAt<'a> = Source<aio::AioWritev<'a>>;
pub trait SourceApi {
type Output;
fn aio_return(self: Pin<&mut Self>) -> nix::Result<Self::Output>;
fn cancel(self: Pin<&mut Self>) -> nix::Result<aio::AioCancelStat>;
fn error(self: Pin<&mut Self>) -> nix::Result<()>;
fn in_progress(&self) -> bool;
#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
fn deregister_raw(&mut self);
#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
fn register_raw(&mut self, kq: BorrowedFd, udata: usize);
fn submit(self: Pin<&mut Self>) -> nix::Result<()>;
}
#[derive(Debug)]
pub struct Source<T> {
inner: T,
}
impl<T: Aio> Source<T> {
pin_utils::unsafe_pinned!(inner: T);
fn _deregister_raw(&mut self) {
let sigev = SigevNotify::SigevNone;
self.inner.set_sigev_notify(sigev);
}
fn _register_raw<'r>(&'r mut self, kq: BorrowedFd<'r>, udata: usize) {
let sigev = SigevNotify::SigevKeventFlags {
kq,
udata: udata as isize,
flags: EvFlags::EV_ONESHOT,
};
self.inner.set_sigev_notify(sigev);
}
}
impl<T: Aio> SourceApi for Source<T> {
type Output = T::Output;
fn aio_return(self: Pin<&mut Self>) -> nix::Result<Self::Output> {
self.inner().aio_return()
}
fn cancel(self: Pin<&mut Self>) -> nix::Result<aio::AioCancelStat> {
self.inner().cancel()
}
#[cfg(feature = "tokio")]
fn deregister_raw(&mut self) {
self._deregister_raw()
}
fn error(self: Pin<&mut Self>) -> nix::Result<()> {
self.inner().error()
}
fn in_progress(&self) -> bool {
self.inner.in_progress()
}
#[cfg(feature = "tokio")]
fn register_raw(&mut self, kq: BorrowedFd, udata: usize) {
self._register_raw(kq, udata)
}
fn submit(self: Pin<&mut Self>) -> nix::Result<()> {
self.inner().submit()
}
}
impl<T: Aio> event::Source for Source<T> {
fn register(
&mut self,
registry: &Registry,
token: Token,
interests: Interest,
) -> io::Result<()> {
assert!(interests.is_aio());
let udata = usize::from(token);
let kq = registry.as_fd();
self._register_raw(kq, udata);
Ok(())
}
fn reregister(
&mut self,
registry: &Registry,
token: Token,
interests: Interest,
) -> io::Result<()> {
self.register(registry, token, interests)
}
fn deregister(&mut self, _registry: &Registry) -> io::Result<()> {
self._deregister_raw();
Ok(())
}
}
impl<'a> Source<aio::AioFsync<'a>> {
pub fn fsync(fd: BorrowedFd<'a>, mode: AioFsyncMode, prio: i32) -> Self {
let inner = aio::AioFsync::new(fd, mode, prio, SigevNotify::SigevNone);
Source { inner }
}
}
impl<'a> Source<aio::AioRead<'a>> {
pub fn read_at(
fd: BorrowedFd<'a>,
offs: u64,
buf: &'a mut [u8],
prio: i32,
) -> Self {
let inner = aio::AioRead::new(
fd,
offs as off_t,
buf,
prio,
SigevNotify::SigevNone,
);
Source { inner }
}
}
impl<'a> Source<aio::AioReadv<'a>> {
pub fn readv_at(
fd: BorrowedFd<'a>,
offs: u64,
bufs: &mut [IoSliceMut<'a>],
prio: i32,
) -> Self {
let inner = aio::AioReadv::new(
fd,
offs as off_t,
bufs,
prio,
SigevNotify::SigevNone,
);
Source { inner }
}
}
impl<'a> Source<aio::AioWrite<'a>> {
pub fn write_at(
fd: BorrowedFd<'a>,
offs: u64,
buf: &'a [u8],
prio: i32,
) -> Self {
let inner = aio::AioWrite::new(
fd,
offs as off_t,
buf,
prio,
SigevNotify::SigevNone,
);
Source { inner }
}
}
impl<'a> Source<aio::AioWritev<'a>> {
pub fn writev_at(
fd: BorrowedFd<'a>,
offs: u64,
bufs: &[IoSlice<'a>],
prio: i32,
) -> Self {
let inner = aio::AioWritev::new(
fd,
offs as off_t,
bufs,
prio,
SigevNotify::SigevNone,
);
Source { inner }
}
}