mirror of
https://github.com/tokio-rs/bytes.git
synced 2026-08-23 00:00:13 +02:00
Specialize copy_to_bytes for Chain and Take (#481)
Avoid allocation when `Take` or `Chain` is composed of `Bytes` objects. This works now for `Take`. `Chain` it works if the requested bytes does not cross boundary between `Chain` members.
This commit is contained in:
+19
-1
@@ -1,5 +1,5 @@
|
|||||||
use crate::buf::{IntoIter, UninitSlice};
|
use crate::buf::{IntoIter, UninitSlice};
|
||||||
use crate::{Buf, BufMut};
|
use crate::{Buf, BufMut, Bytes};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::io::IoSlice;
|
use std::io::IoSlice;
|
||||||
@@ -170,6 +170,24 @@ where
|
|||||||
n += self.b.chunks_vectored(&mut dst[n..]);
|
n += self.b.chunks_vectored(&mut dst[n..]);
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copy_to_bytes(&mut self, len: usize) -> Bytes {
|
||||||
|
let a_rem = self.a.remaining();
|
||||||
|
if a_rem >= len {
|
||||||
|
self.a.copy_to_bytes(len)
|
||||||
|
} else if a_rem == 0 {
|
||||||
|
self.b.copy_to_bytes(len)
|
||||||
|
} else {
|
||||||
|
assert!(
|
||||||
|
len - a_rem <= self.b.remaining(),
|
||||||
|
"`len` greater than remaining"
|
||||||
|
);
|
||||||
|
let mut ret = crate::BytesMut::with_capacity(len);
|
||||||
|
ret.put(&mut self.a);
|
||||||
|
ret.put((&mut self.b).take(len - a_rem));
|
||||||
|
ret.freeze()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, U> BufMut for Chain<T, U>
|
unsafe impl<T, U> BufMut for Chain<T, U>
|
||||||
|
|||||||
+9
-1
@@ -1,4 +1,4 @@
|
|||||||
use crate::Buf;
|
use crate::{Buf, Bytes};
|
||||||
|
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
|
|
||||||
@@ -144,4 +144,12 @@ impl<T: Buf> Buf for Take<T> {
|
|||||||
self.inner.advance(cnt);
|
self.inner.advance(cnt);
|
||||||
self.limit -= cnt;
|
self.limit -= cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copy_to_bytes(&mut self, len: usize) -> Bytes {
|
||||||
|
assert!(len <= self.remaining(), "`len` greater than remaining");
|
||||||
|
|
||||||
|
let r = self.inner.copy_to_bytes(len);
|
||||||
|
self.limit -= len;
|
||||||
|
r
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,3 +132,24 @@ fn vectored_read() {
|
|||||||
assert_eq!(iovecs[3][..], b""[..]);
|
assert_eq!(iovecs[3][..], b""[..]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn chain_get_bytes() {
|
||||||
|
let mut ab = Bytes::copy_from_slice(b"ab");
|
||||||
|
let mut cd = Bytes::copy_from_slice(b"cd");
|
||||||
|
let ab_ptr = ab.as_ptr();
|
||||||
|
let cd_ptr = cd.as_ptr();
|
||||||
|
let mut chain = (&mut ab).chain(&mut cd);
|
||||||
|
let a = chain.copy_to_bytes(1);
|
||||||
|
let bc = chain.copy_to_bytes(2);
|
||||||
|
let d = chain.copy_to_bytes(1);
|
||||||
|
|
||||||
|
assert_eq!(Bytes::copy_from_slice(b"a"), a);
|
||||||
|
assert_eq!(Bytes::copy_from_slice(b"bc"), bc);
|
||||||
|
assert_eq!(Bytes::copy_from_slice(b"d"), d);
|
||||||
|
|
||||||
|
// assert `get_bytes` did not allocate
|
||||||
|
assert_eq!(ab_ptr, a.as_ptr());
|
||||||
|
// assert `get_bytes` did not allocate
|
||||||
|
assert_eq!(cd_ptr.wrapping_offset(1), d.as_ptr());
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
use bytes::buf::Buf;
|
use bytes::buf::Buf;
|
||||||
|
use bytes::Bytes;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn long_take() {
|
fn long_take() {
|
||||||
@@ -10,3 +11,22 @@ fn long_take() {
|
|||||||
assert_eq!(11, buf.remaining());
|
assert_eq!(11, buf.remaining());
|
||||||
assert_eq!(b"hello world", buf.chunk());
|
assert_eq!(b"hello world", buf.chunk());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn take_copy_to_bytes() {
|
||||||
|
let mut abcd = Bytes::copy_from_slice(b"abcd");
|
||||||
|
let abcd_ptr = abcd.as_ptr();
|
||||||
|
let mut take = (&mut abcd).take(2);
|
||||||
|
let a = take.copy_to_bytes(1);
|
||||||
|
assert_eq!(Bytes::copy_from_slice(b"a"), a);
|
||||||
|
// assert `to_bytes` did not allocate
|
||||||
|
assert_eq!(abcd_ptr, a.as_ptr());
|
||||||
|
assert_eq!(Bytes::copy_from_slice(b"bcd"), abcd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn take_copy_to_bytes_panics() {
|
||||||
|
let abcd = Bytes::copy_from_slice(b"abcd");
|
||||||
|
abcd.take(2).copy_to_bytes(3);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user