diff --git a/src/buf/mod.rs b/src/buf.rs similarity index 91% rename from src/buf/mod.rs rename to src/buf.rs index cab96c50da05660f9896227dbad1812f21f730a0..a45ed604d65877d9715aa743f190ee818c175a17 100644 --- a/src/buf/mod.rs +++ b/src/buf.rs @@ -2,9 +2,30 @@ use {Bytes}; use byteorder::ByteOrder; use std::{cmp, io, ptr, usize}; -/// A trait for values that provide sequential read access to bytes. +/// Read bytes from a buffer. +/// +/// A buffer stores bytes in memory such that read access is infallible. The +/// underlying storage may or may not be in contiguous memory. A `Buf` value is +/// a cursor into the buffer. Reading from `Buf` advances the cursor position. +/// +/// The simplest `Buf` is a `Cursor` wrapping a `[u8]`. +/// +/// ``` +/// use bytes::Buf; +/// use std::io::Cursor; +/// +/// let mut buf = Cursor::new(b"hello world"); +/// +/// assert_eq!(b'h', buf.get_u8()); +/// assert_eq!(b'e', buf.get_u8()); +/// assert_eq!(b'l', buf.get_u8()); +/// +/// let mut rest = vec![]; +/// buf.copy_to(&mut rest); +/// +/// assert_eq!(&rest[..], b"lo world"); +/// ``` pub trait Buf { - /// Returns the number of bytes that can be accessed from the Buf fn remaining(&self) -> usize; @@ -70,16 +91,6 @@ pub trait Buf { } } - /// Gets an unsigned 8 bit integer from the `Buf` without advancing the - /// buffer cursor - fn peek_u8(&self) -> Option<u8> { - if self.has_remaining() { - Some(self.bytes()[0]) - } else { - None - } - } - /// Gets an unsigned 8 bit integer from the `Buf`. fn get_u8(&mut self) -> u8 { let mut buf = [0; 1]; @@ -203,7 +214,7 @@ pub trait BufMut { /// /// Panics if `self` does not have enough capacity to copy all the data /// from `src` - fn copy_from<S: Source>(&mut self, src: S) where Self: Sized { + fn put<S: Source>(&mut self, src: S) where Self: Sized { src.source(self); } @@ -219,14 +230,14 @@ pub trait BufMut { /// /// { /// let mut buf = Cursor::new(&mut dst); - /// buf.copy_from_slice(b"hello"); + /// buf.put_slice(b"hello"); /// /// assert_eq!(1, buf.remaining_mut()); /// } /// /// assert_eq!(b"hello\0", &dst); /// ``` - fn copy_from_slice(&mut self, src: &[u8]) { + fn put_slice(&mut self, src: &[u8]) { let mut off = 0; assert!(self.remaining_mut() >= src.len(), "buffer overflow"); @@ -251,66 +262,46 @@ pub trait BufMut { } } - /// Writes the given string into self. - /// - /// # Panics - /// - /// The function panics if `self` does not have enough remaining capacity - /// to write the full string. - fn put_str(&mut self, src: &str) { - self.copy_from_slice(src.as_bytes()); - } - - /// Writes an unsigned 8 bit integer to the BufMut. - fn put_u8(&mut self, n: u8) { - self.copy_from_slice(&[n]) - } - - /// Writes a signed 8 bit integer to the BufMut. - fn put_i8(&mut self, n: i8) { - self.copy_from_slice(&[n as u8]) - } - /// Writes an unsigned 16 bit integer to the BufMut. fn put_u16<T: ByteOrder>(&mut self, n: u16) { let mut buf = [0; 2]; T::write_u16(&mut buf, n); - self.copy_from_slice(&buf) + self.put_slice(&buf) } /// Writes a signed 16 bit integer to the BufMut. fn put_i16<T: ByteOrder>(&mut self, n: i16) { let mut buf = [0; 2]; T::write_i16(&mut buf, n); - self.copy_from_slice(&buf) + self.put_slice(&buf) } /// Writes an unsigned 32 bit integer to the BufMut. fn put_u32<T: ByteOrder>(&mut self, n: u32) { let mut buf = [0; 4]; T::write_u32(&mut buf, n); - self.copy_from_slice(&buf) + self.put_slice(&buf) } /// Writes a signed 32 bit integer to the BufMut. fn put_i32<T: ByteOrder>(&mut self, n: i32) { let mut buf = [0; 4]; T::write_i32(&mut buf, n); - self.copy_from_slice(&buf) + self.put_slice(&buf) } /// Writes an unsigned 64 bit integer to the BufMut. fn put_u64<T: ByteOrder>(&mut self, n: u64) { let mut buf = [0; 8]; T::write_u64(&mut buf, n); - self.copy_from_slice(&buf) + self.put_slice(&buf) } /// Writes a signed 64 bit integer to the BufMut. fn put_i64<T: ByteOrder>(&mut self, n: i64) { let mut buf = [0; 8]; T::write_i64(&mut buf, n); - self.copy_from_slice(&buf) + self.put_slice(&buf) } /// Writes an unsigned n-bytes integer to the BufMut. @@ -320,7 +311,7 @@ pub trait BufMut { fn put_uint<T: ByteOrder>(&mut self, n: u64, nbytes: usize) { let mut buf = [0; 8]; T::write_uint(&mut buf, n, nbytes); - self.copy_from_slice(&buf[0..nbytes]) + self.put_slice(&buf[0..nbytes]) } /// Writes a signed n-bytes integer to the BufMut. @@ -330,7 +321,7 @@ pub trait BufMut { fn put_int<T: ByteOrder>(&mut self, n: i64, nbytes: usize) { let mut buf = [0; 8]; T::write_int(&mut buf, n, nbytes); - self.copy_from_slice(&buf[0..nbytes]) + self.put_slice(&buf[0..nbytes]) } /// Writes a IEEE754 single-precision (4 bytes) floating point number to @@ -338,7 +329,7 @@ pub trait BufMut { fn put_f32<T: ByteOrder>(&mut self, n: f32) { let mut buf = [0; 4]; T::write_f32(&mut buf, n); - self.copy_from_slice(&buf) + self.put_slice(&buf) } /// Writes a IEEE754 double-precision (8 bytes) floating point number to @@ -346,7 +337,7 @@ pub trait BufMut { fn put_f64<T: ByteOrder>(&mut self, n: f64) { let mut buf = [0; 8]; T::write_f64(&mut buf, n); - self.copy_from_slice(&buf) + self.put_slice(&buf) } /// Creates a "by reference" adaptor for this instance of BufMut @@ -446,14 +437,26 @@ pub trait Source { impl<'a> Source for &'a [u8] { fn source<B: BufMut>(self, buf: &mut B) { - buf.copy_from_slice(self); + buf.put_slice(self); + } +} + +impl<'a> Source for &'a str { + fn source<B: BufMut>(self, buf: &mut B) { + buf.put_slice(self.as_bytes()); } } impl Source for u8 { fn source<B: BufMut>(self, buf: &mut B) { let src = [self]; - buf.copy_from_slice(&src); + buf.put_slice(&src); + } +} + +impl Source for i8 { + fn source<B: BufMut>(self, buf: &mut B) { + buf.put_slice(&[self as u8]) } } @@ -584,7 +587,7 @@ impl<B: BufMut + Sized> io::Write for Writer<B> { fn write(&mut self, src: &[u8]) -> io::Result<usize> { let n = cmp::min(self.buf.remaining_mut(), src.len()); - self.buf.copy_from(&src[0..n]); + self.buf.put(&src[0..n]); Ok(n) } diff --git a/src/buf/take.rs b/src/buf/take.rs deleted file mode 100644 index f92a9933769c9f21d0ef672a1efa313ded33f8e5..0000000000000000000000000000000000000000 --- a/src/buf/take.rs +++ /dev/null @@ -1,182 +0,0 @@ -use {Buf, BufMut}; -use std::{cmp, fmt}; - -/// A buffer adapter which limits the bytes read from an underlying value. -#[derive(Debug)] -pub struct Take<T> { - inner: T, - limit: usize, -} - -/// A buffer adapter which limits the bytes written from an underlying value. -#[derive(Debug)] -pub struct TakeMut<T> { - inner: T, - limit: usize, -} - -pub fn new<T>(inner: T, limit: usize) -> Take<T> { - Take { - inner: inner, - limit: limit, - } -} - -pub fn new_mut<T>(inner: T, limit: usize) -> TakeMut<T> { - TakeMut { - inner: inner, - limit: limit, - } -} - -/* - * - * ===== impl Take ===== - * - */ - -impl<T> Take<T> { - /// Consumes this `Take`, returning the underlying value. - pub fn into_inner(self) -> T { - self.inner - } - - /// Gets a reference to the underlying value in this `Take`. - pub fn get_ref(&self) -> &T { - &self.inner - } - - /// Gets a mutable reference to the underlying value in this `Take`. - pub fn get_mut(&mut self) -> &mut T { - &mut self.inner - } - - /// Returns the maximum number of bytes that are made available from the - /// underlying value. - pub fn limit(&self) -> usize { - self.limit - } - - /// Sets the maximum number of bytes that are made available from the - /// underlying value. - pub fn set_limit(&mut self, lim: usize) { - self.limit = lim - } -} - -impl<T: Buf> Buf for Take<T> { - fn remaining(&self) -> usize { - cmp::min(self.inner.remaining(), self.limit) - } - - fn bytes(&self) -> &[u8] { - &self.inner.bytes()[..self.limit] - } - - fn advance(&mut self, cnt: usize) { - let cnt = cmp::min(cnt, self.limit); - self.limit -= cnt; - self.inner.advance(cnt); - } -} - -impl<T: BufMut> BufMut for Take<T> { - fn remaining_mut(&self) -> usize { - self.inner.remaining_mut() - } - - unsafe fn bytes_mut(&mut self) -> &mut [u8] { - self.inner.bytes_mut() - } - - unsafe fn advance_mut(&mut self, cnt: usize) { - self.inner.advance_mut(cnt) - } -} - -impl<T: BufMut> fmt::Write for Take<T> { - fn write_str(&mut self, s: &str) -> fmt::Result { - BufMut::put_str(self, s); - Ok(()) - } - - fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result { - fmt::write(self, args) - } -} - -/* - * - * ===== impl TakeMut ===== - * - */ - -impl<T> TakeMut<T> { - /// Consumes this `TakeMut`, returning the underlying value. - pub fn into_inner(self) -> T { - self.inner - } - - /// Gets a reference to the underlying value in this `TakeMut`. - pub fn get_ref(&self) -> &T { - &self.inner - } - - /// Gets a mutable reference to the underlying value in this `TakeMut`. - pub fn get_mut(&mut self) -> &mut T { - &mut self.inner - } - - /// Returns the maximum number of bytes that are made available from the - /// underlying value. - pub fn limit(&self) -> usize { - self.limit - } - - /// Sets the maximum number of bytes that are made available from the - /// underlying value. - pub fn set_limit(&mut self, lim: usize) { - self.limit = lim - } -} - -impl<T: Buf> Buf for TakeMut<T> { - fn remaining(&self) -> usize { - self.inner.remaining() - } - - fn bytes(&self) -> &[u8] { - self.inner.bytes() - } - - fn advance(&mut self, cnt: usize) { - self.inner.advance(cnt) - } -} - -impl<T: BufMut> BufMut for TakeMut<T> { - fn remaining_mut(&self) -> usize { - cmp::min(self.inner.remaining_mut(), self.limit) - } - - unsafe fn bytes_mut(&mut self) -> &mut [u8] { - &mut self.inner.bytes_mut()[..self.limit] - } - - unsafe fn advance_mut(&mut self, cnt: usize) { - let cnt = cmp::min(cnt, self.limit); - self.limit -= cnt; - self.inner.advance_mut(cnt); - } -} - -impl<T: BufMut> fmt::Write for TakeMut<T> { - fn write_str(&mut self, s: &str) -> fmt::Result { - BufMut::put_str(self, s); - Ok(()) - } - - fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result { - fmt::write(self, args) - } -} diff --git a/src/bytes.rs b/src/bytes.rs index ed56618876bd2fe131fbfa0122d47c3897e1cd59..3160bbdd4738adac3f26d015604ad4200c4712bf 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -114,9 +114,9 @@ pub struct Bytes { /// /// let mut buf = BytesMut::with_capacity(64); /// -/// buf.put_u8(b'h'); -/// buf.put_u8(b'e'); -/// buf.put_str("llo"); +/// buf.put(b'h'); +/// buf.put(b'e'); +/// buf.put("llo"); /// /// assert_eq!(&buf[..], b"hello"); /// @@ -489,12 +489,24 @@ impl From<Vec<u8>> for Bytes { } } +impl From<String> for Bytes { + fn from(src: String) -> Bytes { + BytesMut::from(src).freeze() + } +} + impl<'a> From<&'a [u8]> for Bytes { fn from(src: &'a [u8]) -> Bytes { BytesMut::from(src).freeze() } } +impl<'a> From<&'a str> for Bytes { + fn from(src: &'a str) -> Bytes { + BytesMut::from(src).freeze() + } +} + impl PartialEq for Bytes { fn eq(&self, other: &Bytes) -> bool { self.inner.as_ref() == other.inner.as_ref() @@ -538,7 +550,7 @@ impl BytesMut { /// // `bytes` contains no data, even though there is capacity /// assert_eq!(bytes.len(), 0); /// - /// bytes.copy_from_slice(b"hello world"); + /// bytes.put(&b"hello world"[..]); /// /// assert_eq!(&bytes[..], b"hello world"); /// ``` @@ -618,7 +630,7 @@ impl BytesMut { /// use std::thread; /// /// let mut b = BytesMut::with_capacity(64); - /// b.put_str("hello world"); + /// b.put("hello world"); /// let b1 = b.freeze(); /// let b2 = b1.clone(); /// @@ -785,6 +797,63 @@ impl BytesMut { pub unsafe fn set_len(&mut self, len: usize) { self.inner.set_len(len) } + + /// Reserves capacity for at least `additional` more bytes to be inserted + /// into the given `BytesMut`. + /// + /// More than `additional` bytes may be reserved in order to avoid frequent + /// reallocations. A call to `reserve` may result in an allocation. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut b = BytesMut::from(&b"hello"[..]); + /// b.reserve(64); + /// assert!(b.capacity() >= 69); + /// ``` + /// + /// # Panics + /// + /// Panics if the new capacity overflows usize. + pub fn reserve(&mut self, additional: usize) { + self.inner.reserve(additional) + } + + /// Attempts to reclaim ownership of the full buffer. + /// + /// Returns `true` if the reclaim is successful. + /// + /// If the `BytesMut` handle is the only outstanding handle pointing to the + /// memory slice, the handle's view will be set to the full memory slice, + /// enabling reusing buffer space without allocating. + /// + /// Any data in the `BytesMut` handle will be copied to the start of the + /// memory region. + /// + /// ```rust + /// use bytes::BytesMut; + /// + /// let mut bytes = BytesMut::from( + /// "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + /// + /// // Create a new handle to the shared memory region + /// let a = bytes.drain_to(5); + /// + /// // Attempting to reclaim here will fail due to `a` still being in + /// // existence. + /// assert!(!bytes.try_reclaim()); + /// assert_eq!(bytes.capacity(), 51); + /// + /// // Dropping the handle will allow reclaim to succeed. + /// drop(a); + /// assert!(bytes.try_reclaim()); + /// assert_eq!(bytes.capacity(), 56); + /// ``` + pub fn try_reclaim(&mut self) -> bool { + self.inner.try_reclaim() + } } impl BufMut for BytesMut { @@ -806,7 +875,7 @@ impl BufMut for BytesMut { } #[inline] - fn copy_from_slice(&mut self, src: &[u8]) { + fn put_slice(&mut self, src: &[u8]) { assert!(self.remaining_mut() >= src.len()); let len = src.len(); @@ -875,6 +944,12 @@ impl From<Vec<u8>> for BytesMut { } } +impl From<String> for BytesMut { + fn from(src: String) -> BytesMut { + BytesMut::from(src.into_bytes()) + } +} + impl<'a> From<&'a [u8]> for BytesMut { fn from(src: &'a [u8]) -> BytesMut { if src.len() <= INLINE_CAP { @@ -894,12 +969,18 @@ impl<'a> From<&'a [u8]> for BytesMut { } } else { let mut buf = BytesMut::with_capacity(src.len()); - buf.copy_from_slice(src.as_ref()); + buf.put(src.as_ref()); buf } } } +impl<'a> From<&'a str> for BytesMut { + fn from(src: &'a str) -> BytesMut { + BytesMut::from(src.as_bytes()) + } +} + impl From<Bytes> for BytesMut { fn from(src: Bytes) -> BytesMut { src.try_mut() @@ -924,7 +1005,7 @@ impl fmt::Debug for BytesMut { impl fmt::Write for BytesMut { fn write_str(&mut self, s: &str) -> fmt::Result { - BufMut::put_str(self, s); + BufMut::put(self, s); Ok(()) } @@ -1220,6 +1301,150 @@ impl Inner { } } + #[inline] + fn reserve(&mut self, additional: usize) { + let len = self.len(); + let rem = self.capacity() - len; + + if additional <= rem { + // Nothing more to do + return; + } + + match self.kind() { + Kind::Vec => { + unsafe { + let d = &mut *self.data.get(); + + // Promote this `Bytes` to an arc, and clone it + let mut v = Vec::from_raw_parts(d.ptr, d.len, d.cap); + v.reserve(additional); + + // Update the info + d.ptr = v.as_mut_ptr(); + d.len = v.len(); + d.cap = v.capacity(); + + // Drop the vec reference + mem::forget(v); + } + } + Kind::Arc => { + unsafe { + // Compute the new capacity + let new_cap = len + additional; + + // Create a new vector to store the data + let mut v = Vec::with_capacity(new_cap); + + // Copy the bytes + v.extend_from_slice(self.as_ref()); + + let d = &mut *self.data.get(); + + d.ptr = v.as_mut_ptr(); + d.len = v.len(); + d.cap = v.capacity(); + + mem::forget(v); + + // Drop the arc reference + let _: Arc<UnsafeCell<Vec<u8>>> = mem::transmute(self.arc.get()); + + self.arc.set(0); + } + } + Kind::Inline => { + let new_cap = len + additional; + + unsafe { + if new_cap <= INLINE_CAP { + let dst = &mut self.data as *mut _ as *mut u8; + let src = self.inline_ptr(); + + ptr::copy(src, dst, len); + + let mut a = KIND_INLINE; + a |= len << INLINE_LEN_OFFSET; + + self.arc.set(a); + } else { + let mut v = Vec::with_capacity(new_cap); + + // Copy the bytes + v.extend_from_slice(self.as_ref()); + + let d = &mut *self.data.get(); + + d.ptr = v.as_mut_ptr(); + d.len = v.len(); + d.cap = v.capacity(); + + mem::forget(v); + + self.arc.set(0); + } + } + } + Kind::Static => unreachable!(), + } + } + + /// This must take `&mut self` in order to be able to copy memory in the + /// inline case. + #[inline] + fn try_reclaim(&mut self) -> bool { + match self.kind() { + Kind::Inline => { + if self.inline_start() > 0 { + // Shift the data back to the front + unsafe { + let len = self.inline_len(); + let dst = &mut self.data as *mut _ as *mut u8; + let src = self.inline_ptr(); + + ptr::copy(src, dst, len); + + let mut a = KIND_INLINE; + a |= len << INLINE_LEN_OFFSET; + + self.arc.set(a); + } + } + + true + } + Kind::Arc => { + unsafe { + let arc: &mut Shared = mem::transmute(&mut self.arc); + + // Check if mut safe + if Arc::get_mut(arc).is_none() { + return false; + } + + let v = &mut *arc.get(); + let d = &mut *self.data.get(); + + let len = v.len(); + let ptr = v.as_mut_ptr(); + + ptr::copy(d.ptr, ptr, len); + + d.ptr = ptr; + d.len = len; + d.cap = v.capacity(); + + true + } + } + Kind::Vec => { + true + } + Kind::Static => unreachable!(), + } + } + #[inline] fn kind(&self) -> Kind { let arc = self.arc.get(); @@ -1283,6 +1508,12 @@ impl PartialEq<[u8]> for BytesMut { } } +impl PartialEq<str> for BytesMut { + fn eq(&self, other: &str) -> bool { + &**self == other.as_bytes() + } +} + impl PartialEq<BytesMut> for [u8] { fn eq(&self, other: &BytesMut) -> bool { *other == *self @@ -1295,12 +1526,24 @@ impl PartialEq<Vec<u8>> for BytesMut { } } +impl PartialEq<String> for BytesMut { + fn eq(&self, other: &String) -> bool { + *self == &other[..] + } +} + impl PartialEq<BytesMut> for Vec<u8> { fn eq(&self, other: &BytesMut) -> bool { *other == *self } } +impl PartialEq<BytesMut> for String { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + impl<'a, T: ?Sized> PartialEq<&'a T> for BytesMut where BytesMut: PartialEq<T> { @@ -1315,36 +1558,72 @@ impl<'a> PartialEq<BytesMut> for &'a [u8] { } } +impl<'a> PartialEq<BytesMut> for &'a str { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + impl PartialEq<[u8]> for Bytes { fn eq(&self, other: &[u8]) -> bool { self.inner.as_ref() == other } } +impl PartialEq<str> for Bytes { + fn eq(&self, other: &str) -> bool { + self.inner.as_ref() == other.as_bytes() + } +} + impl PartialEq<Bytes> for [u8] { fn eq(&self, other: &Bytes) -> bool { *other == *self } } +impl PartialEq<Bytes> for str { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + impl PartialEq<Vec<u8>> for Bytes { fn eq(&self, other: &Vec<u8>) -> bool { *self == &other[..] } } +impl PartialEq<String> for Bytes { + fn eq(&self, other: &String) -> bool { + *self == &other[..] + } +} + impl PartialEq<Bytes> for Vec<u8> { fn eq(&self, other: &Bytes) -> bool { *other == *self } } +impl PartialEq<Bytes> for String { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + impl<'a> PartialEq<Bytes> for &'a [u8] { fn eq(&self, other: &Bytes) -> bool { *other == *self } } +impl<'a> PartialEq<Bytes> for &'a str { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + impl<'a, T: ?Sized> PartialEq<&'a T> for Bytes where Bytes: PartialEq<T> { diff --git a/src/lib.rs b/src/lib.rs index 9d2a2e28fadb8ad21361ed2aeaa60a44f0163ccf..834f5b0a0b9c9a5ed62c102db3ee040574ec1251 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,67 @@ //! Provides abstractions for working with bytes. +//! +//! The `bytes` crate provides an efficient byte buffer structure +//! ([`Bytes`](struct.Bytes.html)) and traits for working with buffer +//! implementations ([`Buf`](trait.Buf.html), [`BufMut`](trait.BufMut.html)). +//! +//! # `Bytes` +//! +//! `Bytes` is an efficient container for storing and operating on continguous +//! slices of memory. It is intended for use primarily in networking code, but +//! could have applications elsewhere as well. +//! +//! `Bytes` values facilitate zero-copy network programming by allowing multiple +//! `Bytes` objects to point to the same underlying memory. This is managed by +//! using a reference count to track when the memory is no longer needed and can +//! be freed. +//! +//! See the [struct docs](struct.Bytes.html) for more details. +//! +//! # `Buf`, `BufMut` +//! +//! These two traits provide read and write access to buffers. The underlying +//! storage may or may not be in contiguous memory. For example, `Bytes` is a +//! buffer that guarantees contiguous memory, but a +//! [rope](https://en.wikipedia.org/wiki/Rope_(data_structure)) stores the bytes +//! in disjoint chunks. `Buf` and `BufMut` maintain cursors tracking the current +//! position in the underlying byte storage. When bytes are read or written, the +//! cursor is advanced. +//! +//! ## Relation with `Read` and `Write` +//! +//! At first glance, it may seem that `Buf` and `BufMut` overlap in +//! functionality with `std::io::Ready` and `std::io::Write`. However, they +//! serve different purposes. A buffer is the value that is provided as an +//! argument to `Read::read` and `Write::write`. `Read` and `Write` may then +//! perform a syscall, which has the potential of failing. Operations on `Buf` +//! and `BufMut` are infallible. +//! +//! # Example +//! +//! ``` +//! use bytes::{BytesMut, Buf, BufMut}; +//! use std::io::Cursor; +//! use std::thread; +//! +//! // Allocate a buffer capable of holding 1024 bytes. +//! let mut buf = BytesMut::with_capacity(1024); +//! +//! // Write some data +//! buf.put("Hello world"); +//! buf.put(b'-'); +//! buf.put("goodbye"); +//! +//! // Freeze the buffer, enabling concurrent access +//! let b1 = buf.freeze(); +//! let b2 = b1.clone(); +//! +//! thread::spawn(move || { +//! assert_eq!(&b1[..], b"Hello world-goodbye"); +//! }); +//! +//! let mut buf = Cursor::new(b2); +//! assert_eq!(b'H', buf.get_u8()); +//! ``` #![deny(warnings, missing_docs)] diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs index 521446e1930c8f8249d1d9209a70020706478f2f..1e38e5c7103320ad2d983ec4b2f0925e4278861d 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -1,10 +1,16 @@ extern crate bytes; -use bytes::{Bytes, BytesMut}; +use bytes::{Bytes, BytesMut, BufMut}; const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb"; const SHORT: &'static [u8] = b"hello world"; +#[cfg(target_pointer_width = "64")] +const INLINE_CAP: usize = 8 * 3; + +#[cfg(target_pointer_width = "32")] +const INNER_CAP: usize = 4 * 3; + fn is_sync<T: Sync>() {} fn is_send<T: Send>() {} @@ -193,5 +199,67 @@ fn fns_defined_for_bytes_mut() { // Iterator let v: Vec<u8> = bytes.iter().map(|b| *b).collect(); - assert_eq!(&v[..], &bytes[..]); + assert_eq!(&v[..], bytes); +} + +#[test] +fn reserve() { + // Inline -> Vec + let mut bytes = BytesMut::with_capacity(8); + bytes.put("hello"); + bytes.reserve(40); + assert_eq!(bytes.capacity(), 45); + assert_eq!(bytes, "hello"); + + // Inline -> Inline + let mut bytes = BytesMut::with_capacity(INLINE_CAP); + bytes.put("abcdefghijkl"); + + let a = bytes.drain_to(10); + bytes.reserve(INLINE_CAP - 3); + assert_eq!(INLINE_CAP, bytes.capacity()); + + assert_eq!(bytes, "kl"); + assert_eq!(a, "abcdefghij"); + + // Vec -> Vec + let mut bytes = BytesMut::from(LONG); + bytes.reserve(64); + assert_eq!(bytes.capacity(), LONG.len() + 64); + + // Arc -> Vec + let mut bytes = BytesMut::from(LONG); + let a = bytes.drain_to(30); + + bytes.reserve(128); + assert_eq!(bytes.capacity(), bytes.len() + 128); + + drop(a); +} + +#[test] +fn try_reclaim() { + // Inline w/ start at zero + let mut bytes = BytesMut::from(&SHORT[..]); + assert!(bytes.try_reclaim()); + assert_eq!(bytes.capacity(), INLINE_CAP); + assert_eq!(bytes, SHORT); + + // Inline w/ start not at zero + let mut bytes = BytesMut::from(&SHORT[..]); + let _ = bytes.drain_to(2); + assert_eq!(bytes.capacity(), INLINE_CAP - 2); + assert!(bytes.try_reclaim()); + assert_eq!(bytes.capacity(), INLINE_CAP); + assert_eq!(bytes, &SHORT[2..]); + + // Arc + let mut bytes = BytesMut::from(&LONG[..]); + let a = bytes.drain_to(2); + assert!(!bytes.try_reclaim()); + assert_eq!(bytes.capacity(), LONG.len() - 2); + + drop(a); + assert!(bytes.try_reclaim()); + assert_eq!(bytes.capacity(), LONG.len()); } diff --git a/tests/test_mut_buf.rs b/tests/test_mut_buf.rs index 56660e8c69e1cd1d4ad08b466862e16a30e363c7..d15a9209c7a12c2a4c4196eb959b49d5d737337b 100644 --- a/tests/test_mut_buf.rs +++ b/tests/test_mut_buf.rs @@ -15,7 +15,7 @@ fn test_vec_as_mut_buf() { assert!(buf.bytes_mut().len() >= 64); } - buf.copy_from(&b"zomg"[..]); + buf.put(&b"zomg"[..]); assert_eq!(&buf, b"zomg"); @@ -23,7 +23,7 @@ fn test_vec_as_mut_buf() { assert_eq!(buf.capacity(), 64); for _ in 0..16 { - buf.copy_from(&b"zomg"[..]); + buf.put(&b"zomg"[..]); } assert_eq!(buf.len(), 68); @@ -32,7 +32,7 @@ fn test_vec_as_mut_buf() { #[test] fn test_put_u8() { let mut buf = Vec::with_capacity(8); - buf.put_u8(33); + buf.put::<u8>(33); assert_eq!(b"\x21", &buf[..]); }