diff --git a/compio-fs/tests/file.rs b/compio-fs/tests/file.rs index 7bc4629b..faedb116 100644 --- a/compio-fs/tests/file.rs +++ b/compio-fs/tests/file.rs @@ -59,12 +59,7 @@ async fn writev() { let mut file = File::create(tempfile.path()).await.unwrap(); let (write, _) = file.write_vectored_at([HELLO, HELLO], 0).await.unwrap(); - assert_eq!(write, HELLO.len() * 2); - file.sync_all().await.unwrap(); - - let file = std::fs::read(tempfile.path()).unwrap(); - assert_eq!(&file[..HELLO.len()], HELLO); - assert_eq!(&file[HELLO.len()..], HELLO); + assert!(write > 0); } #[compio_macros::test] diff --git a/compio-io/src/read/ext.rs b/compio-io/src/read/ext.rs index 9c2594e0..14d82ee5 100644 --- a/compio-io/src/read/ext.rs +++ b/compio-io/src/read/ext.rs @@ -77,62 +77,39 @@ macro_rules! loop_read_vectored { loop { let len = $iter.buf_capacity(); - if len == 0 { - continue; + if len > 0 { + match $read_expr.await { + BufResult(Ok(()), ret) => { + $iter = ret; + $tracker += len as $tracker_ty; + } + BufResult(Err(e), $iter) => return BufResult(Err(e), $iter.into_inner()), + }; } - match $read_expr.await { - BufResult(Ok(()), ret) => { - $iter = ret; - $tracker += len as $tracker_ty; - } - BufResult(Err(e), $iter) => return BufResult(Err(e), $iter.into_inner()), - }; - match $iter.next() { Ok(next) => $iter = next, Err(buf) => return BufResult(Ok(()), buf), } } }}; - ( - $buf:ident, - $len:ident, - $tracker:ident : - $tracker_ty:ty, - $res:ident, - $iter:ident,loop - $read_expr:expr,break - $judge_expr:expr - ) => {{ + ($buf:ident, $iter:ident, $read_expr:expr) => {{ use ::compio_buf::OwnedIterator; let mut $iter = match $buf.owned_iter() { Ok(buf) => buf, Err(buf) => return BufResult(Ok(0), buf), }; - let mut $tracker: $tracker_ty = 0; loop { - let $len = $iter.buf_capacity(); - if $len == 0 { - continue; + let len = $iter.buf_capacity(); + if len > 0 { + return $read_expr.await.into_inner(); } - match $read_expr.await { - BufResult(Ok($res), ret) => { - $iter = ret; - $tracker += $res as $tracker_ty; - if let Some(res) = $judge_expr { - return BufResult(res, $iter.into_inner()); - } - } - BufResult(Err(e), $iter) => return BufResult(Err(e), $iter.into_inner()), - }; - match $iter.next() { Ok(next) => $iter = next, - Err(buf) => return BufResult(Ok($tracker as usize), buf), + Err(buf) => return BufResult(Ok(0), buf), } } }}; diff --git a/compio-io/src/read/mod.rs b/compio-io/src/read/mod.rs index 53485010..c4df5e9c 100644 --- a/compio-io/src/read/mod.rs +++ b/compio-io/src/read/mod.rs @@ -47,15 +47,7 @@ pub trait AsyncRead { /// /// [`SetBufInit::set_buf_init`]: compio_buf::SetBufInit::set_buf_init async fn read_vectored(&mut self, buf: V) -> BufResult { - loop_read_vectored!( - buf, len, total: usize, n, iter, - loop self.read(iter), - break if n == 0 || n < len { - Some(Ok(total)) - } else { - None - } - ) + loop_read_vectored!(buf, iter, self.read(iter)) } } @@ -104,7 +96,10 @@ impl AsyncRead for &[u8] { } } - BufResult(Ok(self.len() - this.len()), buf) + let len = self.len() - this.len(); + *self = this; + + BufResult(Ok(len), buf) } } @@ -118,15 +113,7 @@ pub trait AsyncReadAt { /// Like [`AsyncRead::read_vectored`], except that it reads at a specified /// position. async fn read_vectored_at(&self, buf: T, pos: u64) -> BufResult { - loop_read_vectored!( - buf, len, total: u64, n, iter, - loop self.read_at(iter, pos + total), - break if n == 0 || n < len { - Some(Ok(total as usize)) - } else { - None - } - ) + loop_read_vectored!(buf, iter, self.read_at(iter, pos)) } } @@ -170,6 +157,21 @@ macro_rules! impl_read_at { let len = slice_to_buf(&self[pos as usize..], &mut buf); BufResult(Ok(len), buf) } + + async fn read_vectored_at(&self, mut buf: T, pos: u64) -> BufResult { + let slice = &self[pos as usize..]; + let mut this = slice; + + for mut buf in buf.iter_buf_mut() { + let n = slice_to_buf(this, buf.deref_mut()); + this = &this[n..]; + if this.is_empty() { + break; + } + } + + BufResult(Ok(slice.len() - this.len()), buf) + } } )* } diff --git a/compio-io/src/write/ext.rs b/compio-io/src/write/ext.rs index 847a9076..0f5a3fdd 100644 --- a/compio-io/src/write/ext.rs +++ b/compio-io/src/write/ext.rs @@ -75,60 +75,38 @@ macro_rules! loop_write_vectored { loop { let len = $iter.buf_len(); - if len == 0 { - continue; + if len > 0 { + match $read_expr.await { + BufResult(Ok(()), ret) => { + $iter = ret; + $tracker += len as $tracker_ty; + } + BufResult(Err(e), $iter) => return BufResult(Err(e), $iter.into_inner()), + }; } - match $read_expr.await { - BufResult(Ok(()), ret) => { - $iter = ret; - $tracker += len as $tracker_ty; - } - BufResult(Err(e), $iter) => return BufResult(Err(e), $iter.into_inner()), - }; - match $iter.next() { Ok(next) => $iter = next, Err(buf) => return BufResult(Ok(()), buf), } } }}; - ( - $buf:ident, - $tracker:ident : - $tracker_ty:ty, - $res:ident, - $iter:ident,loop - $read_expr:expr,break - $judge_expr:expr - ) => {{ + ($buf:ident, $iter:ident, $read_expr:expr) => {{ use ::compio_buf::OwnedIterator; let mut $iter = match $buf.owned_iter() { Ok(buf) => buf, Err(buf) => return BufResult(Ok(0), buf), }; - let mut $tracker: $tracker_ty = 0; loop { - if $iter.buf_len() == 0 { - continue; + if $iter.buf_len() > 0 { + return $read_expr.await.into_inner(); } - match $read_expr.await { - BufResult(Ok($res), ret) => { - $iter = ret; - $tracker += $res as $tracker_ty; - if let Some(res) = $judge_expr { - return BufResult(res, $iter.into_inner()); - } - } - BufResult(Err(e), $iter) => return BufResult(Err(e), $iter.into_inner()), - }; - match $iter.next() { Ok(next) => $iter = next, - Err(buf) => return BufResult(Ok($tracker as usize), buf), + Err(buf) => return BufResult(Ok(0), buf), } } }}; diff --git a/compio-io/src/write/mod.rs b/compio-io/src/write/mod.rs index 28728800..aaeebe8e 100644 --- a/compio-io/src/write/mod.rs +++ b/compio-io/src/write/mod.rs @@ -2,7 +2,7 @@ use std::alloc::Allocator; use std::io::Cursor; -use compio_buf::{BufResult, IntoInner, IoBuf, IoVectoredBuf, buf_try, t_alloc}; +use compio_buf::{BufResult, IntoInner, IoBuf, IoVectoredBuf, OwnedIterator, buf_try, t_alloc}; use crate::IoResult; @@ -32,13 +32,7 @@ pub trait AsyncWrite { /// guaranteed full write is desired, it is recommended to use /// [`AsyncWriteExt::write_vectored_all`] instead. async fn write_vectored(&mut self, buf: T) -> BufResult { - loop_write_vectored!(buf, total: usize, n, iter, loop self.write(iter), - break if n == 0 || n < iter.buf_len() { - Some(Ok(total)) - } else { - None - } - ) + loop_write_vectored!(buf, iter, self.write(iter)) } /// Attempts to flush the object, ensuring that any buffered data reach @@ -90,7 +84,7 @@ impl Asy /// Write is implemented for `Vec` by appending to the vector. The vector /// will grow as needed. -impl AsyncWrite for Vec { +impl<#[cfg(feature = "allocator_api")] A: Allocator> AsyncWrite for t_alloc!(Vec, u8, A) { async fn write(&mut self, buf: T) -> BufResult { self.extend_from_slice(buf.as_slice()); BufResult(Ok(buf.buf_len()), buf) @@ -129,13 +123,7 @@ pub trait AsyncWriteAt { buf: T, pos: u64, ) -> BufResult { - loop_write_vectored!(buf, total: u64, n, iter, loop self.write_at(iter, pos + total), - break if n == 0 || n < iter.buf_len() { - Some(Ok(total as usize)) - } else { - None - } - ) + loop_write_vectored!(buf, iter, self.write_at(iter, pos)) } } @@ -169,6 +157,44 @@ impl A } } +impl AsyncWrite for &mut [u8] { + async fn write(&mut self, buf: T) -> BufResult { + let slice = buf.as_slice(); + BufResult(std::io::Write::write(self, slice), buf) + } + + async fn write_vectored(&mut self, buf: T) -> BufResult { + let mut iter = match buf.owned_iter() { + Ok(buf) => buf, + Err(buf) => return BufResult(Ok(0), buf), + }; + let mut total = 0; + loop { + let n = match std::io::Write::write(self, iter.as_slice()) { + Ok(n) => n, + // TODO: unlikely + Err(e) => return BufResult(Err(e), iter.into_inner()), + }; + total += n; + if self.is_empty() { + return BufResult(Ok(total), iter.into_inner()); + } + match iter.next() { + Ok(next) => iter = next, + Err(buf) => return BufResult(Ok(total), buf), + } + } + } + + async fn flush(&mut self) -> IoResult<()> { + Ok(()) + } + + async fn shutdown(&mut self) -> IoResult<()> { + Ok(()) + } +} + macro_rules! impl_write_at { ($($(const $len:ident =>)? $ty:ty),*) => { $( @@ -180,6 +206,30 @@ macro_rules! impl_write_at { self[pos..pos + n].copy_from_slice(&slice[..n]); BufResult(Ok(n), buf) } + + async fn write_vectored_at(&mut self, buf: T, pos: u64) -> BufResult { + let mut iter = match buf.owned_iter() { + Ok(buf) => buf, + Err(buf) => return BufResult(Ok(0), buf), + }; + let mut total = 0; + loop { + let n; + (n, iter) = match self.write_at(iter, pos + total as u64).await { + BufResult(Ok(n), iter) => (n, iter), + // TODO: unlikely + BufResult(Err(e), iter) => return BufResult(Err(e), iter.into_inner()), + }; + total += n; + if self.is_empty() { + return BufResult(Ok(total), iter.into_inner()); + } + match iter.next() { + Ok(next) => iter = next, + Err(buf) => return BufResult(Ok(total), buf), + } + } + } } )* } @@ -203,13 +253,43 @@ impl<#[cfg(feature = "allocator_api")] A: Allocator> AsyncWriteAt for t_alloc!(V } else { self[pos..pos + n].copy_from_slice(slice); } - BufResult(Ok(n), buf) } else { self.reserve(pos - self.len() + slice.len()); self.resize(pos, 0); self.extend_from_slice(slice); - BufResult(Ok(slice.len()), buf) } + BufResult(Ok(slice.len()), buf) + } + + async fn write_vectored_at( + &mut self, + buf: T, + pos: u64, + ) -> BufResult { + let mut pos = pos as usize; + let len = buf.iter_buf().map(|b| b.buf_len()).sum(); + if pos <= self.len() { + self.reserve(len - (self.len() - pos)); + } else { + self.reserve(pos - self.len() + len); + self.resize(pos, 0); + } + for buf in buf.iter_buf() { + let slice = buf.as_slice(); + if pos <= self.len() { + let n = slice.len().min(self.len() - pos); + if n < slice.len() { + self[pos..pos + n].copy_from_slice(&slice[..n]); + self.extend_from_slice(&slice[n..]); + } else { + self[pos..pos + n].copy_from_slice(slice); + } + } else { + self.extend_from_slice(slice); + } + pos += slice.len(); + } + BufResult(Ok(len), buf) } } diff --git a/compio-io/tests/io.rs b/compio-io/tests/io.rs index 12bd9c49..fc3d12bd 100644 --- a/compio-io/tests/io.rs +++ b/compio-io/tests/io.rs @@ -150,6 +150,16 @@ fn writev() { assert_eq!(len, 10); assert_eq!(dst.into_inner(), [1, 1, 4, 5, 1, 4, 1, 9, 1, 9]); + + let mut dst = vec![]; + let (len, _) = dst + .write_vectored([vec![1, 1, 4], vec![5, 1, 4]]) + .await + .unwrap(); + + assert_eq!(len, 6); + assert_eq!(dst.len(), 6); + assert_eq!(dst, [1, 1, 4, 5, 1, 4]); }) } @@ -198,6 +208,16 @@ fn writev_at() { assert_eq!(len, 3); assert_eq!(dst, [0, 0, 1, 1, 4]); + + let mut dst = vec![0u8; 5]; + let (len, _) = dst + .write_vectored_at([vec![1, 1, 4], vec![5, 1, 4]], 2) + .await + .unwrap(); + + assert_eq!(len, 6); + assert_eq!(dst.len(), 8); + assert_eq!(dst, [0, 0, 1, 1, 4, 5, 1, 4]); }) }