diff --git a/src/cursor/mod.rs b/src/cursor/mod.rs index d9719cf..f90be78 100644 --- a/src/cursor/mod.rs +++ b/src/cursor/mod.rs @@ -201,6 +201,10 @@ impl> Buf for Cursor { total.saturating_sub(self.data.pos) as usize } + fn has_remaining(&self) -> bool { + self.data.num_bytes(self.inner.as_ref()) > self.data.pos + } + fn chunk(&self) -> &[u8] { self.data.fill_buf_impl(self.inner.as_ref()) } @@ -210,40 +214,30 @@ impl> Buf for Cursor { } fn chunks_vectored<'iovs>(&'iovs self, iovs: &mut [IoSlice<'iovs>]) -> usize { - if iovs.is_empty() { + let list = self.inner.as_ref(); + + if iovs.is_empty() || !self.has_remaining() { return 0; } - let list = self.inner.as_ref(); - let mut filled = 0; - let mut current_chunk = self.data.chunk; - let mut current_pos = self.data.pos; - - // Iterate through chunks starting from the current position - while filled < iovs.len() && current_chunk < list.num_chunks() { - if let Some(chunk) = list.get_chunk(current_chunk) { - let chunk_start_pos = list.get_start_pos()[current_chunk]; - let offset_in_chunk = (current_pos - chunk_start_pos) as usize; - - if offset_in_chunk < chunk.len() { - let chunk_slice = &chunk.as_ref()[offset_in_chunk..]; - iovs[filled] = IoSlice::new(chunk_slice); - filled += 1; - } + let current_chunk = self.data.chunk; + let chunk_start_pos = list.get_start_pos()[current_chunk]; + let offset_in_chunk = (self.data.pos - chunk_start_pos) as usize; - current_chunk += 1; - // Move to the start of the next chunk - if let Some(&next_start_pos) = list.get_start_pos().get(current_chunk) { - current_pos = next_start_pos; - } else { - break; - } - } else { - break; - } + iovs[0] = IoSlice::new( + &list.get_chunk(current_chunk).expect("chunk is in range")[offset_in_chunk..], + ); + // Fill up the remaining iovs with as many slices as possible. + let to_fill = (iovs.len()).min(list.num_chunks() - current_chunk); + for (i, iov) in iovs.iter_mut().enumerate().take(to_fill).skip(1) { + *iov = IoSlice::new( + &list + .get_chunk(current_chunk + i) + .expect("chunk is in range")[..], + ); } - filled + to_fill } } diff --git a/src/cursor/tests.rs b/src/cursor/tests.rs index 2adf719..9df480c 100644 --- a/src/cursor/tests.rs +++ b/src/cursor/tests.rs @@ -57,7 +57,6 @@ enum CursorOp { // return value separately. Consume(prop::sample::Index), // Buf trait operations - BufRemaining, BufChunk, BufAdvance(prop::sample::Index), BufChunksVectored(prop::sample::Index), @@ -192,18 +191,6 @@ impl CursorOp { buf_list.consume(amt); oracle.consume(amt); } - Self::BufRemaining => { - eprintln!("buf_remaining"); - - let buf_list_remaining = buf_list.remaining(); - let oracle_remaining = oracle.remaining(); - ensure!( - buf_list_remaining == oracle_remaining, - "remaining didn't match: buf_list {} == oracle {}", - buf_list_remaining, - oracle_remaining - ); - } Self::BufChunk => { eprintln!("buf_chunk"); @@ -297,7 +284,8 @@ impl CursorOp { ensure!( !buf_list_bytes.is_empty(), "chunks_vectored should return some data \ - when remaining > 0 and num_iovs > 0" + when remaining = {buf_list_remaining} > 0 \ + and num_iovs = {num_iovs} > 0" ); ensure!( !oracle_bytes.is_empty(), @@ -312,6 +300,14 @@ impl CursorOp { "buf_list chunks_vectored data should match beginning \ of oracle data" ); + + // Verify that all iovs up to buf_list_filled are non-empty. + for (i, iov) in buf_list_iovs[..buf_list_filled].iter().enumerate() { + ensure!( + !iov.is_empty(), + "buf_list iov at index {i} should be non-empty", + ); + } } else if buf_list_remaining == 0 { // If no bytes remaining, should return no data ensure!( @@ -449,6 +445,25 @@ impl CursorOp { } } + // Check general properties: remaining and has_remaining are the same. + let buf_list_remaining = buf_list.remaining(); + let oracle_remaining = oracle.remaining(); + ensure!( + buf_list_remaining == oracle_remaining, + "remaining didn't match: buf_list {} == oracle {}", + buf_list_remaining, + oracle_remaining + ); + + let buf_list_has_remaining = buf_list.has_remaining(); + let oracle_has_remaining = oracle.has_remaining(); + ensure!( + buf_list_has_remaining == oracle_has_remaining, + "has_remaining didn't match: buf_list {} == oracle {}", + buf_list_has_remaining, + oracle_has_remaining + ); + // Also check that the position is the same. let buf_list_position = buf_list.position(); ensure!(