Skip to content

Commit aae4969

Browse files
srijsDarksonnvorner
authored
Add specialized Buf::chunks_vectored for Take (#617)
Co-authored-by: Alice Ryhl <aliceryhl@google.com> Co-authored-by: Michal 'vorner' Vaner <vorner@vorner.cz>
1 parent 103d7bf commit aae4969

File tree

3 files changed

+102
-1
lines changed

3 files changed

+102
-1
lines changed

src/buf/take.rs

+49
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ use crate::{Buf, Bytes};
22

33
use core::cmp;
44

5+
#[cfg(feature = "std")]
6+
use std::io::IoSlice;
7+
58
/// A `Buf` adapter which limits the bytes read from an underlying buffer.
69
///
710
/// This struct is generally created by calling `take()` on `Buf`. See
@@ -152,4 +155,50 @@ impl<T: Buf> Buf for Take<T> {
152155
self.limit -= len;
153156
r
154157
}
158+
159+
#[cfg(feature = "std")]
160+
fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
161+
if self.limit == 0 {
162+
return 0;
163+
}
164+
165+
const LEN: usize = 16;
166+
let mut slices: [IoSlice<'a>; LEN] = [
167+
IoSlice::new(&[]),
168+
IoSlice::new(&[]),
169+
IoSlice::new(&[]),
170+
IoSlice::new(&[]),
171+
IoSlice::new(&[]),
172+
IoSlice::new(&[]),
173+
IoSlice::new(&[]),
174+
IoSlice::new(&[]),
175+
IoSlice::new(&[]),
176+
IoSlice::new(&[]),
177+
IoSlice::new(&[]),
178+
IoSlice::new(&[]),
179+
IoSlice::new(&[]),
180+
IoSlice::new(&[]),
181+
IoSlice::new(&[]),
182+
IoSlice::new(&[]),
183+
];
184+
185+
let cnt = self
186+
.inner
187+
.chunks_vectored(&mut slices[..dst.len().min(LEN)]);
188+
let mut limit = self.limit;
189+
for (i, (dst, slice)) in dst[..cnt].iter_mut().zip(slices.iter()).enumerate() {
190+
if let Some(buf) = slice.get(..limit) {
191+
// SAFETY: We could do this safely with `IoSlice::advance` if we had a larger MSRV.
192+
let buf = unsafe { std::mem::transmute::<&[u8], &'a [u8]>(buf) };
193+
*dst = IoSlice::new(buf);
194+
return i + 1;
195+
} else {
196+
// SAFETY: We could do this safely with `IoSlice::advance` if we had a larger MSRV.
197+
let buf = unsafe { std::mem::transmute::<&[u8], &'a [u8]>(slice) };
198+
*dst = IoSlice::new(buf);
199+
limit -= slice.len();
200+
}
201+
}
202+
cnt
203+
}
155204
}

tests/test_buf.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ mod chain_limited_slices {
404404
Buf::take(Buf::chain(Buf::chain(a, b), Buf::chain(c, d)), buf.len())
405405
}
406406

407-
buf_tests!(make_input, /* `Limit` does not forward `chucks_vectored */ false);
407+
buf_tests!(make_input, true);
408408
}
409409

410410
#[allow(unused_allocation)] // This is intentional.

tests/test_take.rs

+52
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,55 @@ fn take_copy_to_bytes_panics() {
3030
let abcd = Bytes::copy_from_slice(b"abcd");
3131
abcd.take(2).copy_to_bytes(3);
3232
}
33+
34+
#[cfg(feature = "std")]
35+
#[test]
36+
fn take_chunks_vectored() {
37+
fn chain() -> impl Buf {
38+
Bytes::from([1, 2, 3].to_vec()).chain(Bytes::from([4, 5, 6].to_vec()))
39+
}
40+
41+
{
42+
let mut dst = [std::io::IoSlice::new(&[]); 2];
43+
let take = chain().take(0);
44+
assert_eq!(take.chunks_vectored(&mut dst), 0);
45+
}
46+
47+
{
48+
let mut dst = [std::io::IoSlice::new(&[]); 2];
49+
let take = chain().take(1);
50+
assert_eq!(take.chunks_vectored(&mut dst), 1);
51+
assert_eq!(&*dst[0], &[1]);
52+
}
53+
54+
{
55+
let mut dst = [std::io::IoSlice::new(&[]); 2];
56+
let take = chain().take(3);
57+
assert_eq!(take.chunks_vectored(&mut dst), 1);
58+
assert_eq!(&*dst[0], &[1, 2, 3]);
59+
}
60+
61+
{
62+
let mut dst = [std::io::IoSlice::new(&[]); 2];
63+
let take = chain().take(4);
64+
assert_eq!(take.chunks_vectored(&mut dst), 2);
65+
assert_eq!(&*dst[0], &[1, 2, 3]);
66+
assert_eq!(&*dst[1], &[4]);
67+
}
68+
69+
{
70+
let mut dst = [std::io::IoSlice::new(&[]); 2];
71+
let take = chain().take(6);
72+
assert_eq!(take.chunks_vectored(&mut dst), 2);
73+
assert_eq!(&*dst[0], &[1, 2, 3]);
74+
assert_eq!(&*dst[1], &[4, 5, 6]);
75+
}
76+
77+
{
78+
let mut dst = [std::io::IoSlice::new(&[]); 2];
79+
let take = chain().take(7);
80+
assert_eq!(take.chunks_vectored(&mut dst), 2);
81+
assert_eq!(&*dst[0], &[1, 2, 3]);
82+
assert_eq!(&*dst[1], &[4, 5, 6]);
83+
}
84+
}

0 commit comments

Comments
 (0)