#![allow(clippy::doc_overindented_list_items)]
use std::{
io::{self, IoSlice, IoSliceMut},
os::unix::io::{AsFd, RawFd},
pin::Pin,
};
use futures::{
task::{Context, Poll},
Future,
};
use mio_aio::AioFsyncMode;
use tokio::io::bsd::{Aio, AioSource};
nix::ioctl_read! {
diocgmediasize, 'd', 129, nix::libc::off_t
}
nix::ioctl_read! {
diocgsectorsize, 'd', 128, nix::libc::c_uint
}
nix::ioctl_read! {
diocgstripesize, 'd', 139, nix::libc::off_t
}
#[derive(Debug)]
struct TokioSource<T>(T);
impl<T: mio_aio::SourceApi> AioSource for TokioSource<T> {
fn register(&mut self, kq: RawFd, token: usize) {
self.0.register_raw(kq, token)
}
fn deregister(&mut self) {
self.0.deregister_raw()
}
}
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct TokioFileFut<T: mio_aio::SourceApi>(Aio<TokioSource<T>>);
impl<T: mio_aio::SourceApi> Future for TokioFileFut<T> {
type Output = io::Result<T::Output>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let poll_result = self.0.poll_ready(cx);
match poll_result {
Poll::Pending => {
if !self.0 .0.in_progress() {
let p = unsafe { self.map_unchecked_mut(|s| &mut s.0 .0) };
match p.submit() {
Ok(()) => (),
Err(e) => {
return Poll::Ready(Err(
io::Error::from_raw_os_error(e as i32),
))
}
}
}
Poll::Pending
}
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
Poll::Ready(Ok(_ev)) => {
let p = unsafe { self.map_unchecked_mut(|s| &mut s.0 .0) };
let result = p.aio_return();
match result {
Ok(r) => Poll::Ready(Ok(r)),
Err(e) => {
Poll::Ready(Err(io::Error::from_raw_os_error(e as i32)))
}
}
}
}
}
}
pub type ReadAt<'a> = TokioFileFut<mio_aio::ReadAt<'a>>;
pub type ReadvAt<'a> = TokioFileFut<mio_aio::ReadvAt<'a>>;
pub type SyncAll<'a> = TokioFileFut<mio_aio::Fsync<'a>>;
pub type WriteAt<'a> = TokioFileFut<mio_aio::WriteAt<'a>>;
pub type WritevAt<'a> = TokioFileFut<mio_aio::WritevAt<'a>>;
pub trait AioFileExt: AsFd {
fn read_at<'a>(
&'a self,
buf: &'a mut [u8],
offset: u64,
) -> io::Result<ReadAt<'a>> {
let fd = self.as_fd();
let source = TokioSource(mio_aio::ReadAt::read_at(fd, offset, buf, 0));
Ok(TokioFileFut(Aio::new_for_aio(source)?))
}
fn readv_at<'a>(
&'a self,
bufs: &mut [IoSliceMut<'a>],
offset: u64,
) -> io::Result<ReadvAt<'a>> {
let fd = self.as_fd();
let source =
TokioSource(mio_aio::ReadvAt::readv_at(fd, offset, bufs, 0));
Ok(TokioFileFut(Aio::new_for_aio(source)?))
}
fn sync_all(&self) -> io::Result<SyncAll> {
let mode = AioFsyncMode::O_SYNC;
let fd = self.as_fd();
let source = TokioSource(mio_aio::Fsync::fsync(fd, mode, 0));
Ok(TokioFileFut(Aio::new_for_aio(source)?))
}
fn write_at<'a>(
&'a self,
buf: &'a [u8],
offset: u64,
) -> io::Result<WriteAt<'a>> {
let fd = self.as_fd();
let source =
TokioSource(mio_aio::WriteAt::write_at(fd, offset, buf, 0));
Ok(TokioFileFut(Aio::new_for_aio(source)?))
}
fn writev_at<'a>(
&'a self,
bufs: &[IoSlice<'a>],
offset: u64,
) -> io::Result<WritevAt<'a>> {
let fd = self.as_fd();
let source =
TokioSource(mio_aio::WritevAt::writev_at(fd, offset, bufs, 0));
Ok(TokioFileFut(Aio::new_for_aio(source)?))
}
}
impl<T: AsFd> AioFileExt for T {}