perf(body): specialize BufList::copy_to_bytes (#2413)
Some implementations of the Buf trait have an optimized version (for example Bytes) of copy_to_bytes, opportunistically use that one.
This commit is contained in:
committed by
GitHub
parent
5e8238c1b8
commit
4d2125c67c
@@ -1,7 +1,7 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::io::IoSlice;
|
||||
|
||||
use bytes::Buf;
|
||||
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||
|
||||
pub(crate) struct BufList<T> {
|
||||
bufs: VecDeque<T>,
|
||||
@@ -70,4 +70,82 @@ impl<T: Buf> Buf for BufList<T> {
|
||||
}
|
||||
vecs
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_bytes(&mut self, len: usize) -> Bytes {
|
||||
// Our inner buffer may have an optimized version of copy_to_bytes, and if the whole
|
||||
// request can be fulfilled by the front buffer, we can take advantage.
|
||||
match self.bufs.front_mut() {
|
||||
Some(front) if front.remaining() == len => {
|
||||
let b = front.copy_to_bytes(len);
|
||||
self.bufs.pop_front();
|
||||
b
|
||||
}
|
||||
Some(front) if front.remaining() > len => front.copy_to_bytes(len),
|
||||
_ => {
|
||||
assert!(len <= self.remaining(), "`len` greater than remaining");
|
||||
let mut bm = BytesMut::with_capacity(len);
|
||||
bm.put(self.take(len));
|
||||
bm.freeze()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ptr;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn hello_world_buf() -> BufList<Bytes> {
|
||||
BufList {
|
||||
bufs: vec![Bytes::from("Hello"), Bytes::from(" "), Bytes::from("World")].into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_bytes_shorter() {
|
||||
let mut bufs = hello_world_buf();
|
||||
let old_ptr = bufs.chunk().as_ptr();
|
||||
let start = bufs.copy_to_bytes(4);
|
||||
assert_eq!(start, "Hell");
|
||||
assert!(ptr::eq(old_ptr, start.as_ptr()));
|
||||
assert_eq!(bufs.chunk(), b"o");
|
||||
assert!(ptr::eq(old_ptr.wrapping_add(4), bufs.chunk().as_ptr()));
|
||||
assert_eq!(bufs.remaining(), 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_bytes_eq() {
|
||||
let mut bufs = hello_world_buf();
|
||||
let old_ptr = bufs.chunk().as_ptr();
|
||||
let start = bufs.copy_to_bytes(5);
|
||||
assert_eq!(start, "Hello");
|
||||
assert!(ptr::eq(old_ptr, start.as_ptr()));
|
||||
assert_eq!(bufs.chunk(), b" ");
|
||||
assert_eq!(bufs.remaining(), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_bytes_longer() {
|
||||
let mut bufs = hello_world_buf();
|
||||
let start = bufs.copy_to_bytes(7);
|
||||
assert_eq!(start, "Hello W");
|
||||
assert_eq!(bufs.remaining(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_long_buf_to_bytes() {
|
||||
let mut buf = BufList::new();
|
||||
buf.push(b"Hello World" as &[_]);
|
||||
assert_eq!(buf.copy_to_bytes(5), "Hello");
|
||||
assert_eq!(buf.chunk(), b" World");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "`len` greater than remaining")]
|
||||
fn buf_to_bytes_too_many() {
|
||||
hello_world_buf().copy_to_bytes(42);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user