Start writing docs for bytes

This commit is contained in:
Carl Lerche
2017-02-15 14:43:11 -08:00
parent 4c6ebeba87
commit 53d1c788e0
2 changed files with 266 additions and 101 deletions
+261 -96
View File
@@ -1,23 +1,134 @@
use {IntoBuf, ByteBuf, SliceBuf};
use {IntoBuf, BufMut};
use std::{cmp, fmt, mem, ops, slice, ptr};
use std::cell::{Cell, UnsafeCell};
use std::io::Cursor;
use std::sync::Arc;
/// A reference counted slice of bytes.
/// A reference counted contiguous slice of memory.
///
/// `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.
///
/// ```
/// use bytes::Bytes;
///
/// let mem = Bytes::from_slice(b"Hello world");
/// let a = mem.slice(0, 5);
///
/// assert_eq!(&a[..], b"Hello");
///
/// let b = mem.drain_to(6);
///
/// assert_eq!(&mem[..], b"world");
/// assert_eq!(&b[..], b"Hello ");
/// ```
///
/// # Memory layout
///
/// The `Bytes` struct itself is fairly small, limited to a pointer to the
/// memory and 4 `usize` fields used to track information about which segment of
/// the underlying memory the `Bytes` handle has access to.
///
/// The memory layout looks like this:
///
/// ```text
/// +-------+
/// | Bytes |
/// +-------+
/// / \_____
/// | \
/// v v
/// +-----+------------------------------------+
/// | Arc | | Data | |
/// +-----+------------------------------------+
/// ```
///
/// `Bytes` keeps both a pointer to the shared `Arc` containing the full memory
/// slice and a pointer to the start of the region visible by the handle.
/// `Bytes` also tracks the length of its view into the memory.
///
/// # Sharing
///
/// The memory itself is reference counted, and multiple `Bytes` objects may
/// point to the same region. Each `Bytes` handle point to different sections within
/// the memory region, and `Bytes` handle may or may not have overlapping views
/// into the memory.
///
///
/// ```text
///
/// Arc ptrs +---------+
/// ________________________ / | Bytes 2 |
/// / +---------+
/// / +-----------+ | |
/// |_________/ | Bytes 1 | | |
/// | +-----------+ | |
/// | | | ___/ data | tail
/// | data | tail |/ |
/// v v v v
/// +-----+---------------------------------+-----+
/// | Arc | | | | |
/// +-----+---------------------------------+-----+
/// ```
///
/// # Mutating
///
/// While `Bytes` handles may potentially represent overlapping views of the
/// underlying memory slice and may not be mutated, `BytesMut` handles are
/// guaranteed to be the only handle able to view that slice of memory. As such,
/// `BytesMut` handles are able to mutate the underlying memory. Note that
/// holding a unique view to a region of memory does not mean that there are not
/// other `Bytes` and `BytesMut` handles with disjoint views of the underlying
/// memory.
///
/// # Inline bytes.
///
/// As an opitmization, when the slice referenced by a `Bytes` or `BytesMut`
/// handle is small enough [1], `Bytes` will avoid the allocation by inlining
/// the slice directly in the handle. In this case, a clone is no longer
/// "shallow" and the data will be copied.
///
/// [1] Small enough: 24 bytes on 64 bit systems, 12 on 32 bit systems.
///
/// A `Bytes` is an immutable sequence of bytes. Given that it is guaranteed to
/// be immutable, `Bytes` is `Sync`, `Clone` is shallow (ref count increment),
/// and all operations only update views into the underlying data without
/// requiring any copies.
pub struct Bytes {
inner: Inner,
}
/// A unique reference to a slice of bytes.
/// A unique reference to a continuous slice of memory.
///
/// A `BytesMut` is a unique handle to a slice of bytes allowing mutation of
/// the underlying bytes.
/// `BytesMut` represents a unique view into a potentially shared memory region.
/// Given the uniqueness guarantee, owners of `BytesMut` handles are able to
/// mutate the memory.
///
/// For more detail, see [Bytes](struct.Bytes.html).
///
/// ```
/// use bytes::{BytesMut, BufMut};
///
/// let mut buf = BytesMut::with_capacity(64);
///
/// buf.put_u8(b'h');
/// buf.put_u8(b'e');
/// buf.put_str("llo");
///
/// assert_eq!(&buf[..], b"hello");
///
/// // Freeze the buffer so that it can be shared
/// let a = buf.freeze();
///
/// // This does not allocate, instead `b` points to the same memory.
/// let b = a.clone();
///
/// assert_eq!(&a[..], b"hello");
/// assert_eq!(&b[..], b"hello");
/// ```
pub struct BytesMut {
inner: Inner
}
@@ -208,18 +319,18 @@ impl Bytes {
}
impl IntoBuf for Bytes {
type Buf = SliceBuf<Self>;
type Buf = Cursor<Self>;
fn into_buf(self) -> Self::Buf {
SliceBuf::new(self)
Cursor::new(self)
}
}
impl<'a> IntoBuf for &'a Bytes {
type Buf = SliceBuf<Self>;
type Buf = Cursor<Self>;
fn into_buf(self) -> Self::Buf {
SliceBuf::new(self)
Cursor::new(self)
}
}
@@ -286,9 +397,31 @@ unsafe impl Sync for Bytes {}
impl BytesMut {
/// Create a new `BytesMut` with the specified capacity.
///
/// The returned `BytesMut` will be able to hold at least `capacity` bytes
/// without reallocating. If `capacity` is under `3 * size:of::<usize>()`,
/// then `BytesMut` will not allocate.
///
/// It is important to note that this function does not specify the length
/// of the returned `BytesMut`, but only the capacity.
///
/// # Examples
///
/// ```
/// use bytes::{BytesMut, BufMut};
///
/// let mut bytes = BytesMut::with_capacity(64);
///
/// // `bytes` contains no data, even though there is capacity
/// assert_eq!(bytes.len(), 0);
///
/// bytes.copy_from_slice(b"hello world");
///
/// assert_eq!(&bytes[..], b"hello world");
/// ```
#[inline]
pub fn with_capacity(cap: usize) -> BytesMut {
if cap <= INLINE_CAP {
pub fn with_capacity(capacity: usize) -> BytesMut {
if capacity <= INLINE_CAP {
BytesMut {
inner: Inner {
data: UnsafeCell::new(Data {
@@ -300,7 +433,7 @@ impl BytesMut {
}
}
} else {
BytesMut::from(Vec::with_capacity(cap))
BytesMut::from(Vec::with_capacity(capacity))
}
}
@@ -325,8 +458,9 @@ impl BytesMut {
}
}
} else {
let buf = ByteBuf::from_slice(b);
buf.into_inner()
let mut buf = BytesMut::with_capacity(bytes.as_ref().len());
buf.copy_from_slice(bytes.as_ref());
buf
}
}
@@ -457,6 +591,115 @@ impl BytesMut {
}
}
impl BufMut for BytesMut {
#[inline]
fn remaining_mut(&self) -> usize {
self.capacity() - self.len()
}
#[inline]
unsafe fn advance_mut(&mut self, cnt: usize) {
let new_len = self.len() + cnt;
self.set_len(new_len);
}
#[inline]
unsafe fn bytes_mut(&mut self) -> &mut [u8] {
let len = self.len();
&mut self.as_raw()[len..]
}
#[inline]
fn copy_from_slice(&mut self, src: &[u8]) {
assert!(self.remaining_mut() >= src.len());
let len = src.len();
unsafe {
self.bytes_mut()[..len].copy_from_slice(src);
self.advance_mut(len);
}
}
}
impl IntoBuf for BytesMut {
type Buf = Cursor<Self>;
fn into_buf(self) -> Self::Buf {
Cursor::new(self)
}
}
impl<'a> IntoBuf for &'a BytesMut {
type Buf = Cursor<&'a BytesMut>;
fn into_buf(self) -> Self::Buf {
Cursor::new(self)
}
}
impl AsRef<[u8]> for BytesMut {
fn as_ref(&self) -> &[u8] {
self.inner.as_ref()
}
}
impl ops::Deref for BytesMut {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.as_ref()
}
}
impl ops::DerefMut for BytesMut {
fn deref_mut(&mut self) -> &mut [u8] {
self.as_mut()
}
}
impl From<Vec<u8>> for BytesMut {
fn from(mut src: Vec<u8>) -> BytesMut {
let len = src.len();
let cap = src.capacity();
let ptr = src.as_mut_ptr();
mem::forget(src);
BytesMut {
inner: Inner {
data: UnsafeCell::new(Data {
ptr: ptr,
len: len,
cap: cap,
}),
arc: Cell::new(0),
},
}
}
}
impl<'a> From<&'a [u8]> for BytesMut {
fn from(src: &'a [u8]) -> BytesMut {
BytesMut::from_slice(src)
}
}
impl PartialEq for BytesMut {
fn eq(&self, other: &BytesMut) -> bool {
self.inner.as_ref() == other.inner.as_ref()
}
}
impl Eq for BytesMut {
}
impl fmt::Debug for BytesMut {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.inner.as_ref(), fmt)
}
}
/*
*
* ===== Inner =====
@@ -795,84 +1038,6 @@ impl Drop for Inner {
unsafe impl Send for Inner {}
impl IntoBuf for BytesMut {
type Buf = SliceBuf<Self>;
fn into_buf(self) -> Self::Buf {
SliceBuf::new(self)
}
}
impl<'a> IntoBuf for &'a BytesMut {
type Buf = SliceBuf<&'a BytesMut>;
fn into_buf(self) -> Self::Buf {
SliceBuf::new(self)
}
}
impl AsRef<[u8]> for BytesMut {
fn as_ref(&self) -> &[u8] {
self.inner.as_ref()
}
}
impl ops::Deref for BytesMut {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.as_ref()
}
}
impl ops::DerefMut for BytesMut {
fn deref_mut(&mut self) -> &mut [u8] {
self.as_mut()
}
}
impl From<Vec<u8>> for BytesMut {
fn from(mut src: Vec<u8>) -> BytesMut {
let len = src.len();
let cap = src.capacity();
let ptr = src.as_mut_ptr();
mem::forget(src);
BytesMut {
inner: Inner {
data: UnsafeCell::new(Data {
ptr: ptr,
len: len,
cap: cap,
}),
arc: Cell::new(0),
},
}
}
}
impl<'a> From<&'a [u8]> for BytesMut {
fn from(src: &'a [u8]) -> BytesMut {
BytesMut::from_slice(src)
}
}
impl PartialEq for BytesMut {
fn eq(&self, other: &BytesMut) -> bool {
self.inner.as_ref() == other.inner.as_ref()
}
}
impl Eq for BytesMut {
}
impl fmt::Debug for BytesMut {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.inner.as_ref(), fmt)
}
}
/*
*
* ===== PartialEq =====
+5 -5
View File
@@ -102,7 +102,7 @@ fn split_off() {
assert_eq!(hello, &b"hello"[..]);
assert_eq!(world, &b"world"[..]);
let mut hello = BytesMut::from_slice(b"helloworld");
let hello = BytesMut::from_slice(b"helloworld");
let world = hello.split_off(5);
assert_eq!(hello, &b"hello"[..]);
@@ -119,13 +119,13 @@ fn split_off_oob() {
#[test]
#[should_panic]
fn split_off_oob_mut() {
let mut hello = BytesMut::from_slice(b"helloworld");
let hello = BytesMut::from_slice(b"helloworld");
hello.split_off(25);
}
#[test]
fn split_off_uninitialized() {
let mut bytes = BytesMut::with_capacity(1024);
let bytes = BytesMut::with_capacity(1024);
let other = bytes.split_off(128);
assert_eq!(bytes.len(), 0);
@@ -168,13 +168,13 @@ fn drain_to_oob() {
#[test]
#[should_panic]
fn drain_to_oob_mut() {
let mut hello = BytesMut::from_slice(b"helloworld");
let hello = BytesMut::from_slice(b"helloworld");
hello.drain_to(30);
}
#[test]
fn drain_to_uninitialized() {
let mut bytes = BytesMut::with_capacity(1024);
let bytes = BytesMut::with_capacity(1024);
let other = bytes.drain_to(128);
assert_eq!(bytes.len(), 0);