diff --git a/.travis.yml b/.travis.yml index 8600e8fe327a60497157104c36139359f1faf0a0..dbc744e9f63495a3f722709d742c9ae52e688a7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,6 +42,24 @@ matrix: - rustup target add wasm32-unknown-unknown - cargo build --target=wasm32-unknown-unknown + # Sanitizers + - rust: nightly + os: linux + script: + - | + set -e + + export RUST_TEST_THREADS=1 + export ASAN_OPTIONS="detect_odr_violation=0 detect_leaks=0" + export TSAN_OPTIONS="suppressions=`pwd`/ci/tsan" + + # Run address sanitizer + RUSTFLAGS="-Z sanitizer=address" \ + cargo test --tests --target x86_64-unknown-linux-gnu + + # Run thread sanitizer + RUSTFLAGS="-Z sanitizer=thread" \ + cargo test --tests --target x86_64-unknown-linux-gnu before_install: set -e diff --git a/CHANGELOG.md b/CHANGELOG.md index 1373a58b0a81e71b7a2f8c91ff8ebb3653670c20..881632fde5cb113599f5a615bf7ef238eac65336 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # 0.5.0 (unreleased) +# 0.4.7 (April 27, 2018) + +* Make `Buf` and `BufMut` usable as trait objects (#186). +* impl BorrowMut for BytesMut (#185). +* Improve accessor performance (#195). + # 0.4.6 (Janary 8, 2018) * Implement FromIterator for Bytes/BytesMut (#148). diff --git a/ci/tsan b/ci/tsan new file mode 100644 index 0000000000000000000000000000000000000000..34f76abaf47208dfc531c70e81b5e75a6b68bc1c --- /dev/null +++ b/ci/tsan @@ -0,0 +1,17 @@ +# TSAN suppressions file for `bytes` + +# TSAN does not understand fences and `Arc::drop` is implemented using a fence. +# This causes many false positives. +race:Arc*drop +race:arc*Weak*drop + +# `std` mpsc is not used in any Bytes code base. This race is triggered by some +# rust runtime logic. +race:std*mpsc_queue + +# Probably more fences in std. +race:__call_tls_dtors + +# `is_inline` is explicitly called concurrently without synchronization. The +# safety explanation can be found in a comment. +race:Inner::is_inline diff --git a/src/bytes.rs b/src/bytes.rs index c85ebf32fd8c0db07fa66fe3b15ea804310053be..4650235049dc0cc41290e339f8b998e587557de7 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -930,6 +930,7 @@ impl FromIterator<u8> for BytesMut { let mut out = BytesMut::with_capacity(maybe_max.unwrap_or(min)); for i in iter { + out.reserve(1); out.put(i); } @@ -1350,6 +1351,32 @@ impl BytesMut { self.truncate(0); } + /// Resizes the buffer so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the buffer is extended by the + /// difference with each additional byte set to `value`. If `new_len` is + /// less than `len`, the buffer is simply truncated. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::new(); + /// + /// buf.resize(3, 0x1); + /// assert_eq!(&buf[..], &[0x1, 0x1, 0x1]); + /// + /// buf.resize(2, 0x2); + /// assert_eq!(&buf[..], &[0x1, 0x1]); + /// + /// buf.resize(4, 0x3); + /// assert_eq!(&buf[..], &[0x1, 0x1, 0x3, 0x3]); + /// ``` + pub fn resize(&mut self, new_len: usize, value: u8) { + self.inner.resize(new_len, value); + } + /// Sets the length of the buffer. /// /// This will explicitly set the size of the buffer without actually @@ -1975,6 +2002,21 @@ impl Inner { } } + fn resize(&mut self, new_len: usize, value: u8) { + let len = self.len(); + if new_len > len { + let additional = new_len - len; + self.reserve(additional); + unsafe { + let dst = self.as_raw()[len..].as_mut_ptr(); + ptr::write_bytes(dst, value, additional); + self.set_len(new_len); + } + } else { + self.truncate(new_len); + } + } + unsafe fn set_start(&mut self, start: usize) { // Setting the start to 0 is a no-op, so return early if this is the // case. diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs index 4ab86699c95278c5a8c20b702064831a9abddbb7..ccc89fa0a2c5f8966db07f90e16cb68cc881f2dd 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -823,3 +823,24 @@ fn bytes_mut_unsplit_two_split_offs() { buf.unsplit(buf2); assert_eq!(b"aaaabbbbccccdddd", &buf[..]); } + +#[test] +fn from_iter_no_size_hint() { + use std::iter; + + let mut expect = vec![]; + + let actual: Bytes = iter::repeat(b'x') + .scan(100, |cnt, item| { + if *cnt >= 1 { + *cnt -= 1; + expect.push(item); + Some(item) + } else { + None + } + }) + .collect(); + + assert_eq!(&actual[..], &expect[..]); +}