Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implicitly grow BytesMut; add BufMutExt::chain_mut #316

Merged
merged 8 commits into from Nov 20, 2019
2 changes: 1 addition & 1 deletion src/buf/buf_mut.rs
Expand Up @@ -270,7 +270,7 @@ pub trait BufMut {
fn put_slice(&mut self, src: &[u8]) {
let mut off = 0;

assert!(self.remaining_mut() >= src.len(), "buffer overflow");
assert!(self.remaining_mut() >= src.len(), "buffer overflow; remaining = {}; src = {}", self.remaining_mut(), src.len());

while off < src.len() {
let cnt;
Expand Down
26 changes: 26 additions & 0 deletions src/buf/ext/mod.rs
Expand Up @@ -124,6 +124,32 @@ pub trait BufMutExt: BufMut {
fn writer(self) -> Writer<Self> where Self: Sized {
writer::new(self)
}

/// Creates an adapter which will chain this buffer with another.
///
/// The returned `BufMut` instance will first write to all bytes from
/// `self`. Afterwards, it will write to `next`.
///
/// # Examples
///
/// ```
/// use bytes::{BufMut, buf::BufMutExt};
///
/// let mut a = [0u8; 5];
/// let mut b = [0u8; 6];
///
/// let mut chain = (&mut a[..]).chain_mut(&mut b[..]);
///
/// chain.put_slice(b"hello world");
///
/// assert_eq!(&a[..], b"hello");
/// assert_eq!(&b[..], b" world");
/// ```
fn chain_mut<U: BufMut>(self, next: U) -> Chain<Self, U>
where Self: Sized
{
Chain::new(self, next)
}
}

impl<B: BufMut + ?Sized> BufMutExt for B {}
35 changes: 20 additions & 15 deletions src/bytes_mut.rs
@@ -1,4 +1,5 @@
use core::{cmp, fmt, hash, isize, mem, slice, usize};
use core::{cmp, fmt, hash, isize, slice, usize};
use core::mem::{self, ManuallyDrop};
use core::ops::{Deref, DerefMut};
use core::ptr::{self, NonNull};
use core::iter::{FromIterator, Iterator};
Expand Down Expand Up @@ -559,17 +560,15 @@ impl BytesMut {
self.cap += off;
} else {
// No space - allocate more
let mut v = rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off);
let mut v = ManuallyDrop::new(rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off));
v.reserve(additional);

// Update the info
self.ptr = vptr(v.as_mut_ptr().offset(off as isize));
self.len = v.len() - off;
self.cap = v.capacity() - off;

// Drop the vec reference
mem::forget(v);
}

return;
}
}
Expand All @@ -582,7 +581,8 @@ impl BytesMut {
// allocating a new vector with the requested capacity.
//
// Compute the new capacity
let mut new_cap = len + additional;
let mut new_cap = len.checked_add(additional).expect("overflow");

let original_capacity;
let original_capacity_repr;

Expand Down Expand Up @@ -618,16 +618,18 @@ impl BytesMut {
// There are some situations, using `reserve_exact` that the
// buffer capacity could be below `original_capacity`, so do a
// check.
let double = v.capacity().checked_shl(1).unwrap_or(new_cap);

new_cap = cmp::max(
cmp::max(v.capacity() << 1, new_cap),
cmp::max(double, new_cap),
original_capacity);
} else {
new_cap = cmp::max(new_cap, original_capacity);
}
}

// Create a new vector to store the data
let mut v = Vec::with_capacity(new_cap);
let mut v = ManuallyDrop::new(Vec::with_capacity(new_cap));

// Copy the bytes
v.extend_from_slice(self.as_ref());
Expand All @@ -642,10 +644,6 @@ impl BytesMut {
self.ptr = vptr(v.as_mut_ptr());
self.len = v.len();
self.cap = v.capacity();

// Forget the vector handle
mem::forget(v);

}
/// Appends given bytes to this object.
///
Expand Down Expand Up @@ -924,20 +922,27 @@ impl Buf for BytesMut {
impl BufMut for BytesMut {
#[inline]
fn remaining_mut(&self) -> usize {
self.capacity() - self.len()
usize::MAX - self.len()
}

#[inline]
unsafe fn advance_mut(&mut self, cnt: usize) {
let new_len = self.len() + cnt;
assert!(new_len <= self.cap);
assert!(new_len <= self.cap, "new_len = {}; capacity = {}", new_len, self.cap);
self.len = new_len;
}

#[inline]
fn bytes_mut(&mut self) -> &mut [mem::MaybeUninit<u8>] {
if self.capacity() == self.len() {
self.reserve(64);
}
carllerche marked this conversation as resolved.
Show resolved Hide resolved

unsafe {
slice::from_raw_parts_mut(self.ptr.as_ptr().offset(self.len as isize) as *mut mem::MaybeUninit<u8>, self.cap)
let ptr = self.ptr.as_ptr().offset(self.len as isize);
let len = self.cap - self.len;

slice::from_raw_parts_mut(ptr as *mut mem::MaybeUninit<u8>, len)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/test_buf_mut.rs
Expand Up @@ -74,7 +74,7 @@ fn test_bufs_vec_mut() {
// with no capacity
let mut buf = BytesMut::new();
assert_eq!(buf.capacity(), 0);
assert_eq!(0, buf.bytes_vectored_mut(&mut dst[..]));
assert_eq!(1, buf.bytes_vectored_mut(&mut dst[..]));

// with capacity
let mut buf = BytesMut::with_capacity(64);
Expand Down
37 changes: 35 additions & 2 deletions tests/test_bytes.rs
Expand Up @@ -2,6 +2,8 @@

use bytes::{Bytes, BytesMut, Buf, BufMut};

use std::usize;

const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb";
const SHORT: &'static [u8] = b"hello world";

Expand Down Expand Up @@ -93,8 +95,8 @@ fn fmt_write() {


let mut c = BytesMut::with_capacity(64);
write!(c, "{}", s).unwrap_err();
assert!(c.is_empty());
write!(c, "{}", s).unwrap();
assert_eq!(c, s[..].as_bytes());
}

#[test]
Expand Down Expand Up @@ -820,3 +822,34 @@ fn empty_slice_ref_catches_not_an_empty_subset() {

bytes.slice_ref(slice);
}

#[test]
fn bytes_buf_mut_advance() {
let mut bytes = BytesMut::with_capacity(1024);

unsafe {
let ptr = bytes.bytes_mut().as_ptr();
assert_eq!(1024, bytes.bytes_mut().len());

bytes.advance_mut(10);

let next = bytes.bytes_mut().as_ptr();
assert_eq!(1024 - 10, bytes.bytes_mut().len());
assert_eq!(ptr.offset(10), next);

// advance to the end
bytes.advance_mut(1024 - 10);

// The buffer size is doubled
assert_eq!(1024, bytes.bytes_mut().len());
}
}

#[test]
#[should_panic]
fn bytes_reserve_overflow() {
let mut bytes = BytesMut::with_capacity(1024);
bytes.put_slice(b"hello world");

bytes.reserve(usize::MAX);
}
13 changes: 5 additions & 8 deletions tests/test_chain.rs
@@ -1,7 +1,7 @@
#![deny(warnings, rust_2018_idioms)]

use bytes::{Buf, BufMut, Bytes, BytesMut};
use bytes::buf::BufExt;
use bytes::{Buf, BufMut, Bytes};
use bytes::buf::{BufExt, BufMutExt};
use std::io::IoSlice;

#[test]
Expand All @@ -15,20 +15,17 @@ fn collect_two_bufs() {

#[test]
fn writing_chained() {
let mut a = BytesMut::with_capacity(64);
let mut b = BytesMut::with_capacity(64);
let mut a = [0u8; 64];
let mut b = [0u8; 64];

{
let mut buf = (&mut a).chain(&mut b);
let mut buf = (&mut a[..]).chain_mut(&mut b[..]);

for i in 0u8..128 {
buf.put_u8(i);
}
}

assert_eq!(64, a.len());
assert_eq!(64, b.len());

for i in 0..64 {
let expect = i as u8;
assert_eq!(expect, a[i]);
Expand Down