use super::Op;
use crate::{
buf::{
IoBuf,
PtrBuf,
},
future::Future,
};
pub struct Write<B: IoBuf> {
fd: lx::RawFd,
buf: B,
off: u64,
}
unsafe impl<B: IoBuf> Op for Write<B> {
type Output = (lx::Result<u32>, B);
fn fill_sqe(&mut self, sqe: &mut lx::io_uring_sqe) {
sqe.opcode = lx::IORING_OP_WRITE;
sqe.fd = self.fd;
sqe.off = self.off;
sqe.addr = self.buf.as_ref().as_ptr() as u64;
sqe.len = u32::try_from(self.buf.as_ref().len()).unwrap();
}
fn complete(self, ret: i32) -> Self::Output {
let ret = ret as u32;
if let Ok(err) = lx::Error::try_from(ret) {
return (Err(err), self.buf);
}
(Ok(ret), self.buf)
}
}
pub fn write<B: IoBuf>(fd: &impl lx::AsRawFd, buf: B, off: u64) -> Future<Write<B>> {
Future::new(Write {
fd: fd.as_raw_fd(),
buf,
off,
})
}
pub async fn write_all<B: IoBuf>(
fd: &impl lx::AsRawFd,
buf: B,
mut off: u64,
) -> (lx::Result<()>, B) {
let max_len = usize::try_from(u32::MAX - u32::from(lx::MAX_ERRNO)).unwrap_or(usize::MAX);
let mut done = 0;
let total = buf.as_ref().len();
while done != total {
let end = (done + max_len).min(total);
let slice_buf = unsafe { PtrBuf::new(&buf.as_ref()[done..end]) };
let (ret, _slice_buf) = write(fd, slice_buf, off).await;
let n = match ret {
Ok(n) => n,
Err(err) => return (Err(err), buf),
};
done += usize::try_from(n).unwrap();
if off != u64::MAX {
off += u64::from(n);
}
}
(Ok(()), buf)
}