Skip to content

Commit 603087a

Browse files
authored
simplify chunks_vectored implementation (#13)
1 parent 9c89e3c commit 603087a

File tree

2 files changed

+51
-42
lines changed

2 files changed

+51
-42
lines changed

src/cursor/mod.rs

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ impl<T: AsRef<BufList>> Buf for Cursor<T> {
201201
total.saturating_sub(self.data.pos) as usize
202202
}
203203

204+
fn has_remaining(&self) -> bool {
205+
self.data.num_bytes(self.inner.as_ref()) > self.data.pos
206+
}
207+
204208
fn chunk(&self) -> &[u8] {
205209
self.data.fill_buf_impl(self.inner.as_ref())
206210
}
@@ -210,40 +214,30 @@ impl<T: AsRef<BufList>> Buf for Cursor<T> {
210214
}
211215

212216
fn chunks_vectored<'iovs>(&'iovs self, iovs: &mut [IoSlice<'iovs>]) -> usize {
213-
if iovs.is_empty() {
217+
let list = self.inner.as_ref();
218+
219+
if iovs.is_empty() || !self.has_remaining() {
214220
return 0;
215221
}
216222

217-
let list = self.inner.as_ref();
218-
let mut filled = 0;
219-
let mut current_chunk = self.data.chunk;
220-
let mut current_pos = self.data.pos;
221-
222-
// Iterate through chunks starting from the current position
223-
while filled < iovs.len() && current_chunk < list.num_chunks() {
224-
if let Some(chunk) = list.get_chunk(current_chunk) {
225-
let chunk_start_pos = list.get_start_pos()[current_chunk];
226-
let offset_in_chunk = (current_pos - chunk_start_pos) as usize;
227-
228-
if offset_in_chunk < chunk.len() {
229-
let chunk_slice = &chunk.as_ref()[offset_in_chunk..];
230-
iovs[filled] = IoSlice::new(chunk_slice);
231-
filled += 1;
232-
}
223+
let current_chunk = self.data.chunk;
224+
let chunk_start_pos = list.get_start_pos()[current_chunk];
225+
let offset_in_chunk = (self.data.pos - chunk_start_pos) as usize;
233226

234-
current_chunk += 1;
235-
// Move to the start of the next chunk
236-
if let Some(&next_start_pos) = list.get_start_pos().get(current_chunk) {
237-
current_pos = next_start_pos;
238-
} else {
239-
break;
240-
}
241-
} else {
242-
break;
243-
}
227+
iovs[0] = IoSlice::new(
228+
&list.get_chunk(current_chunk).expect("chunk is in range")[offset_in_chunk..],
229+
);
230+
// Fill up the remaining iovs with as many slices as possible.
231+
let to_fill = (iovs.len()).min(list.num_chunks() - current_chunk);
232+
for (i, iov) in iovs.iter_mut().enumerate().take(to_fill).skip(1) {
233+
*iov = IoSlice::new(
234+
&list
235+
.get_chunk(current_chunk + i)
236+
.expect("chunk is in range")[..],
237+
);
244238
}
245239

246-
filled
240+
to_fill
247241
}
248242
}
249243

src/cursor/tests.rs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ enum CursorOp {
5757
// return value separately.
5858
Consume(prop::sample::Index),
5959
// Buf trait operations
60-
BufRemaining,
6160
BufChunk,
6261
BufAdvance(prop::sample::Index),
6362
BufChunksVectored(prop::sample::Index),
@@ -192,18 +191,6 @@ impl CursorOp {
192191
buf_list.consume(amt);
193192
oracle.consume(amt);
194193
}
195-
Self::BufRemaining => {
196-
eprintln!("buf_remaining");
197-
198-
let buf_list_remaining = buf_list.remaining();
199-
let oracle_remaining = oracle.remaining();
200-
ensure!(
201-
buf_list_remaining == oracle_remaining,
202-
"remaining didn't match: buf_list {} == oracle {}",
203-
buf_list_remaining,
204-
oracle_remaining
205-
);
206-
}
207194
Self::BufChunk => {
208195
eprintln!("buf_chunk");
209196

@@ -297,7 +284,8 @@ impl CursorOp {
297284
ensure!(
298285
!buf_list_bytes.is_empty(),
299286
"chunks_vectored should return some data \
300-
when remaining > 0 and num_iovs > 0"
287+
when remaining = {buf_list_remaining} > 0 \
288+
and num_iovs = {num_iovs} > 0"
301289
);
302290
ensure!(
303291
!oracle_bytes.is_empty(),
@@ -312,6 +300,14 @@ impl CursorOp {
312300
"buf_list chunks_vectored data should match beginning \
313301
of oracle data"
314302
);
303+
304+
// Verify that all iovs up to buf_list_filled are non-empty.
305+
for (i, iov) in buf_list_iovs[..buf_list_filled].iter().enumerate() {
306+
ensure!(
307+
!iov.is_empty(),
308+
"buf_list iov at index {i} should be non-empty",
309+
);
310+
}
315311
} else if buf_list_remaining == 0 {
316312
// If no bytes remaining, should return no data
317313
ensure!(
@@ -449,6 +445,25 @@ impl CursorOp {
449445
}
450446
}
451447

448+
// Check general properties: remaining and has_remaining are the same.
449+
let buf_list_remaining = buf_list.remaining();
450+
let oracle_remaining = oracle.remaining();
451+
ensure!(
452+
buf_list_remaining == oracle_remaining,
453+
"remaining didn't match: buf_list {} == oracle {}",
454+
buf_list_remaining,
455+
oracle_remaining
456+
);
457+
458+
let buf_list_has_remaining = buf_list.has_remaining();
459+
let oracle_has_remaining = oracle.has_remaining();
460+
ensure!(
461+
buf_list_has_remaining == oracle_has_remaining,
462+
"has_remaining didn't match: buf_list {} == oracle {}",
463+
buf_list_has_remaining,
464+
oracle_has_remaining
465+
);
466+
452467
// Also check that the position is the same.
453468
let buf_list_position = buf_list.position();
454469
ensure!(

0 commit comments

Comments
 (0)