Skip to content

Commit 8135c1f

Browse files
authored
implicitly grow BytesMut; add BufMutExt::chain_mut (#316)
This brings `BytesMut` in line with `Vec<u8>` behavior. This also fixes an existing bug in BytesMut::bytes_mut that exposes invalid slices. The bug was recently introduced and was only on master and never released to `crates.io`. In order to fix a test, `BufMutExt::chain_mut` is provided. Withou this, it is not possible to chain two `&mut [u8]`. Closes #170
1 parent 59aea9e commit 8135c1f

6 files changed

Lines changed: 88 additions & 27 deletions

File tree

src/buf/buf_mut.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ pub trait BufMut {
270270
fn put_slice(&mut self, src: &[u8]) {
271271
let mut off = 0;
272272

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

275275
while off < src.len() {
276276
let cnt;

src/buf/ext/mod.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,32 @@ pub trait BufMutExt: BufMut {
124124
fn writer(self) -> Writer<Self> where Self: Sized {
125125
writer::new(self)
126126
}
127+
128+
/// Creates an adapter which will chain this buffer with another.
129+
///
130+
/// The returned `BufMut` instance will first write to all bytes from
131+
/// `self`. Afterwards, it will write to `next`.
132+
///
133+
/// # Examples
134+
///
135+
/// ```
136+
/// use bytes::{BufMut, buf::BufMutExt};
137+
///
138+
/// let mut a = [0u8; 5];
139+
/// let mut b = [0u8; 6];
140+
///
141+
/// let mut chain = (&mut a[..]).chain_mut(&mut b[..]);
142+
///
143+
/// chain.put_slice(b"hello world");
144+
///
145+
/// assert_eq!(&a[..], b"hello");
146+
/// assert_eq!(&b[..], b" world");
147+
/// ```
148+
fn chain_mut<U: BufMut>(self, next: U) -> Chain<Self, U>
149+
where Self: Sized
150+
{
151+
Chain::new(self, next)
152+
}
127153
}
128154

129155
impl<B: BufMut + ?Sized> BufMutExt for B {}

src/bytes_mut.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use core::{cmp, fmt, hash, isize, mem, slice, usize};
1+
use core::{cmp, fmt, hash, isize, slice, usize};
2+
use core::mem::{self, ManuallyDrop};
23
use core::ops::{Deref, DerefMut};
34
use core::ptr::{self, NonNull};
45
use core::iter::{FromIterator, Iterator};
@@ -559,17 +560,15 @@ impl BytesMut {
559560
self.cap += off;
560561
} else {
561562
// No space - allocate more
562-
let mut v = rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off);
563+
let mut v = ManuallyDrop::new(rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off));
563564
v.reserve(additional);
564565

565566
// Update the info
566567
self.ptr = vptr(v.as_mut_ptr().offset(off as isize));
567568
self.len = v.len() - off;
568569
self.cap = v.capacity() - off;
569-
570-
// Drop the vec reference
571-
mem::forget(v);
572570
}
571+
573572
return;
574573
}
575574
}
@@ -582,7 +581,8 @@ impl BytesMut {
582581
// allocating a new vector with the requested capacity.
583582
//
584583
// Compute the new capacity
585-
let mut new_cap = len + additional;
584+
let mut new_cap = len.checked_add(additional).expect("overflow");
585+
586586
let original_capacity;
587587
let original_capacity_repr;
588588

@@ -618,16 +618,18 @@ impl BytesMut {
618618
// There are some situations, using `reserve_exact` that the
619619
// buffer capacity could be below `original_capacity`, so do a
620620
// check.
621+
let double = v.capacity().checked_shl(1).unwrap_or(new_cap);
622+
621623
new_cap = cmp::max(
622-
cmp::max(v.capacity() << 1, new_cap),
624+
cmp::max(double, new_cap),
623625
original_capacity);
624626
} else {
625627
new_cap = cmp::max(new_cap, original_capacity);
626628
}
627629
}
628630

629631
// Create a new vector to store the data
630-
let mut v = Vec::with_capacity(new_cap);
632+
let mut v = ManuallyDrop::new(Vec::with_capacity(new_cap));
631633

632634
// Copy the bytes
633635
v.extend_from_slice(self.as_ref());
@@ -642,10 +644,6 @@ impl BytesMut {
642644
self.ptr = vptr(v.as_mut_ptr());
643645
self.len = v.len();
644646
self.cap = v.capacity();
645-
646-
// Forget the vector handle
647-
mem::forget(v);
648-
649647
}
650648
/// Appends given bytes to this object.
651649
///
@@ -924,20 +922,27 @@ impl Buf for BytesMut {
924922
impl BufMut for BytesMut {
925923
#[inline]
926924
fn remaining_mut(&self) -> usize {
927-
self.capacity() - self.len()
925+
usize::MAX - self.len()
928926
}
929927

930928
#[inline]
931929
unsafe fn advance_mut(&mut self, cnt: usize) {
932930
let new_len = self.len() + cnt;
933-
assert!(new_len <= self.cap);
931+
assert!(new_len <= self.cap, "new_len = {}; capacity = {}", new_len, self.cap);
934932
self.len = new_len;
935933
}
936934

937935
#[inline]
938936
fn bytes_mut(&mut self) -> &mut [mem::MaybeUninit<u8>] {
937+
if self.capacity() == self.len() {
938+
self.reserve(64);
939+
}
940+
939941
unsafe {
940-
slice::from_raw_parts_mut(self.ptr.as_ptr().offset(self.len as isize) as *mut mem::MaybeUninit<u8>, self.cap)
942+
let ptr = self.ptr.as_ptr().offset(self.len as isize);
943+
let len = self.cap - self.len;
944+
945+
slice::from_raw_parts_mut(ptr as *mut mem::MaybeUninit<u8>, len)
941946
}
942947
}
943948
}

tests/test_buf_mut.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ fn test_bufs_vec_mut() {
7474
// with no capacity
7575
let mut buf = BytesMut::new();
7676
assert_eq!(buf.capacity(), 0);
77-
assert_eq!(0, buf.bytes_vectored_mut(&mut dst[..]));
77+
assert_eq!(1, buf.bytes_vectored_mut(&mut dst[..]));
7878

7979
// with capacity
8080
let mut buf = BytesMut::with_capacity(64);

tests/test_bytes.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

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

5+
use std::usize;
6+
57
const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb";
68
const SHORT: &'static [u8] = b"hello world";
79

@@ -93,8 +95,8 @@ fn fmt_write() {
9395

9496

9597
let mut c = BytesMut::with_capacity(64);
96-
write!(c, "{}", s).unwrap_err();
97-
assert!(c.is_empty());
98+
write!(c, "{}", s).unwrap();
99+
assert_eq!(c, s[..].as_bytes());
98100
}
99101

100102
#[test]
@@ -820,3 +822,34 @@ fn empty_slice_ref_catches_not_an_empty_subset() {
820822

821823
bytes.slice_ref(slice);
822824
}
825+
826+
#[test]
827+
fn bytes_buf_mut_advance() {
828+
let mut bytes = BytesMut::with_capacity(1024);
829+
830+
unsafe {
831+
let ptr = bytes.bytes_mut().as_ptr();
832+
assert_eq!(1024, bytes.bytes_mut().len());
833+
834+
bytes.advance_mut(10);
835+
836+
let next = bytes.bytes_mut().as_ptr();
837+
assert_eq!(1024 - 10, bytes.bytes_mut().len());
838+
assert_eq!(ptr.offset(10), next);
839+
840+
// advance to the end
841+
bytes.advance_mut(1024 - 10);
842+
843+
// The buffer size is doubled
844+
assert_eq!(1024, bytes.bytes_mut().len());
845+
}
846+
}
847+
848+
#[test]
849+
#[should_panic]
850+
fn bytes_reserve_overflow() {
851+
let mut bytes = BytesMut::with_capacity(1024);
852+
bytes.put_slice(b"hello world");
853+
854+
bytes.reserve(usize::MAX);
855+
}

tests/test_chain.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![deny(warnings, rust_2018_idioms)]
22

3-
use bytes::{Buf, BufMut, Bytes, BytesMut};
4-
use bytes::buf::BufExt;
3+
use bytes::{Buf, BufMut, Bytes};
4+
use bytes::buf::{BufExt, BufMutExt};
55
use std::io::IoSlice;
66

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

1616
#[test]
1717
fn writing_chained() {
18-
let mut a = BytesMut::with_capacity(64);
19-
let mut b = BytesMut::with_capacity(64);
18+
let mut a = [0u8; 64];
19+
let mut b = [0u8; 64];
2020

2121
{
22-
let mut buf = (&mut a).chain(&mut b);
22+
let mut buf = (&mut a[..]).chain_mut(&mut b[..]);
2323

2424
for i in 0u8..128 {
2525
buf.put_u8(i);
2626
}
2727
}
2828

29-
assert_eq!(64, a.len());
30-
assert_eq!(64, b.len());
31-
3229
for i in 0..64 {
3330
let expect = i as u8;
3431
assert_eq!(expect, a[i]);

0 commit comments

Comments
 (0)