use super::{const_buf, mut_buf, Fd, IoVec, IoVecMut};
use crate::runtime::wait_event;
use crate::{
event::{POLLET, POLLIN, POLLOUT},
Error, Result,
};
use core::ops::Deref;
use core::ptr;
#[repr(C)]
pub struct AioFd<'a> {
fd: &'a Fd,
}
unsafe impl Send for AioFd<'_> {}
impl Deref for AioFd<'_> {
type Target = Fd;
fn deref(&self) -> &Self::Target {
self.fd
}
}
impl<'a> AioFd<'a> {
pub fn new(fd: &'a Fd) -> Self {
Self { fd }
}
}
impl AioFd<'_> {
pub async fn wait(&mut self, events: u32) -> Result<()> {
wait_event(self.fd(), events | POLLET).await.map(|_| ())
}
pub async fn read_all(&mut self, mut buf: &mut [u8]) -> Result<usize> {
let mut recved = 0;
loop {
let ret = unsafe { libc::read(self.fd.fd, mut_buf(buf), buf.len()) };
#[allow(clippy::comparison_chain)]
if ret > 0 {
let n = ret as usize;
recved += n;
if n == buf.len() {
return Ok(recved);
}
buf = &mut buf[n..];
} else if ret == 0 {
return Ok(recved);
} else {
let e = Error::last();
if e.errno == libc::EAGAIN {
self.wait(POLLIN).await?;
} else if e.errno != libc::EINTR {
return Err(e);
}
}
}
}
pub async fn write_all(&mut self, mut buf: &[u8]) -> Result<usize> {
let mut sended = 0;
loop {
let ret = unsafe { libc::write(self.fd.fd, const_buf(buf), buf.len()) };
if ret >= 0 {
let n = ret as usize;
sended += n;
if n == buf.len() {
return Ok(sended);
}
buf = &buf[n..];
} else {
let e = Error::last();
if e.errno == libc::EAGAIN {
self.wait(POLLOUT).await?;
} else if e.errno != libc::EINTR {
return Err(e);
}
}
}
}
pub async fn readv_all(&mut self, fd: i32, buf: &[&mut [u8]], off: usize) -> Result<usize> {
let iovec = &mut [libc::iovec {
iov_base: ptr::null_mut(),
iov_len: 0,
}; 64];
let mut buf = IoVecMut::new(buf, off);
let mut bytes = 0_usize;
'top: while let Some((piovec, iovcnt, size)) = buf.to_iovec(iovec) {
loop {
let ret = unsafe { libc::readv(fd, piovec, iovcnt) };
if ret > 0 {
bytes += ret as usize;
if ret as usize == size {
buf = buf.next_iovec(iovcnt as usize);
} else {
buf = buf.next_bytes(ret as usize);
}
continue 'top;
} else if ret == 0 {
break 'top;
} else {
let errno = Error::last().errno;
match errno {
hierr::EAGAIN => self.wait(POLLIN).await?,
hierr::EINTR => continue,
_ if bytes > 0 => break 'top,
_ => return Err(Error::new(errno)),
}
}
}
}
Ok(bytes)
}
pub async fn writev_all(&mut self, fd: i32, buf: &[&[u8]], off: usize) -> Result<usize> {
let iovec = &mut [libc::iovec {
iov_base: ptr::null_mut(),
iov_len: 0,
}; 64];
let mut buf = IoVec::new(buf, off);
let mut bytes = 0_usize;
'top: while let Some((piovec, iovcnt, size)) = buf.to_iovec(iovec) {
loop {
let ret = unsafe { libc::writev(fd, piovec, iovcnt) };
if ret > 0 {
bytes += ret as usize;
if ret as usize == size {
buf = buf.next_iovec(iovcnt as usize);
} else {
buf = buf.next_bytes(ret as usize);
}
continue 'top;
} else {
let errno = Error::last().errno;
match errno {
hierr::EAGAIN => self.wait(POLLOUT).await?,
hierr::EINTR => continue,
_ if bytes > 0 => break 'top,
_ => return Err(Error::new(errno)),
}
}
}
}
Ok(bytes)
}
pub async fn sendfile_all(&mut self, in_fd: i32, off: usize, count: usize) -> Result<usize> {
let mut off = off as i64;
let mut len = count;
let end = off + count as i64;
loop {
let ret = unsafe { libc::sendfile(self.fd.fd, in_fd, &mut off, len) };
if ret >= 0 {
if off == end {
return Ok(count);
}
len -= ret as usize;
} else {
let e = Error::last();
if e.errno == libc::EAGAIN {
self.wait(POLLOUT).await?;
} else if e.errno != libc::EINTR {
return Err(e);
}
}
}
}
pub async fn sendfile(&mut self, in_fd: i32, off: usize, count: usize) -> Result<usize> {
let mut off = off as i64;
loop {
let ret = unsafe { libc::sendfile(self.fd.fd, in_fd, &mut off, count) };
if ret >= 0 {
return Ok(ret as usize);
} else {
let e = Error::last();
if e.errno == libc::EAGAIN {
self.wait(POLLOUT).await?;
} else if e.errno != libc::EINTR {
return Err(e);
}
}
}
}
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
loop {
let ret = unsafe { libc::read(self.fd.fd, mut_buf(buf), buf.len()) };
if ret >= 0 {
return Ok(ret as usize);
} else {
let e = Error::last();
if e.errno == libc::EAGAIN {
self.wait(POLLIN).await?;
} else if e.errno != libc::EINTR {
return Err(e);
}
}
}
}
pub async fn write(&mut self, buf: &[u8]) -> Result<usize> {
loop {
let ret = unsafe { libc::write(self.fd.fd, const_buf(buf), buf.len()) };
if ret >= 0 {
return Ok(ret as usize);
} else {
let e = Error::last();
if e.errno == libc::EAGAIN {
self.wait(POLLOUT).await?;
} else if e.errno != libc::EINTR {
return Err(e);
}
}
}
}
}