From 5048eec14330c47561c9bf4d9ce7f9aa4bbf4ff1 Mon Sep 17 00:00:00 2001 From: Carl Lerche <me@carllerche.com> Date: Thu, 16 Feb 2017 22:15:17 -0800 Subject: [PATCH] Docs & polish for Buf --- src/buf.rs | 461 +++++++++++++++++++++++++++++++++++++++++----- src/lib.rs | 3 +- tests/test_buf.rs | 12 +- 3 files changed, 422 insertions(+), 54 deletions(-) diff --git a/src/buf.rs b/src/buf.rs index a45ed60..495478e 100644 --- a/src/buf.rs +++ b/src/buf.rs @@ -20,43 +20,113 @@ use std::{cmp, io, ptr, usize}; /// assert_eq!(b'e', buf.get_u8()); /// assert_eq!(b'l', buf.get_u8()); /// -/// let mut rest = vec![]; -/// buf.copy_to(&mut rest); +/// let mut rest = [0; 8]; +/// buf.copy_to_slice(&mut rest); /// /// assert_eq!(&rest[..], b"lo world"); /// ``` pub trait Buf { - /// Returns the number of bytes that can be accessed from the Buf + /// Returns the number of bytes between the current position and the end of + /// the buffer. + /// + /// This value is greater than or equal to the length of the slice returned + /// by `bytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, Buf, IntoBuf}; + /// + /// let bytes = Bytes::from("hello world"); + /// let mut buf = bytes.into_buf(); + /// + /// assert_eq!(buf.remaining(), 11); + /// + /// buf.get_u8(); + /// + /// assert_eq!(buf.remaining(), 10); + /// ``` fn remaining(&self) -> usize; - /// Returns a slice starting at the current Buf position and of length - /// between 0 and `Buf::remaining()`. + /// Returns a slice starting at the current position and of length between 0 + /// and `Buf::remaining()`. + /// + /// This is a lower level function. Most operations are done with other + /// functions. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, Buf, IntoBuf}; + /// + /// let bytes = Bytes::from("hello world"); + /// let mut buf = bytes.into_buf(); + /// + /// assert_eq!(buf.bytes(), b"hello world"); + /// + /// buf.advance(6); + /// + /// assert_eq!(buf.bytes(), b"world"); + /// ``` fn bytes(&self) -> &[u8]; /// Advance the internal cursor of the Buf + /// + /// The next call to `bytes` will return a slice starting `cnt` bytes + /// further into the underlying buffer. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, Buf, IntoBuf}; + /// + /// let bytes = Bytes::from("hello world"); + /// let mut buf = bytes.into_buf(); + /// + /// assert_eq!(buf.bytes(), b"hello world"); + /// + /// buf.advance(6); + /// + /// assert_eq!(buf.bytes(), b"world"); + /// ``` + /// + /// # Panics + /// + /// This function can panic if `cnt > self.remaining()`. fn advance(&mut self, cnt: usize); /// Returns true if there are any more bytes to consume + /// + /// This is equivalent to `self.remaining() == 0`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, Buf, IntoBuf}; + /// + /// let bytes = Bytes::from("a"); + /// let mut buf = bytes.into_buf(); + /// + /// assert!(buf.has_remaining()); + /// + /// buf.get_u8(); + /// + /// assert!(!buf.has_remaining()); + /// ``` fn has_remaining(&self) -> bool { self.remaining() > 0 } - /// Copies bytes from `self` into `dst` + /// Copies bytes from `self` into `dst`. /// - /// # Panics + /// The cursor is advanced by the number of bytes copied. `self` must have + /// enough remaining bytes to fill `dst`. /// - /// The function panics if `self` does not contain enough bytes to fill - /// `dst`. - fn copy_to<S: Sink + ?Sized>(&mut self, dst: &mut S) where Self: Sized { - dst.sink(self); - } - - /// Copies bytes from the `Buf` into the given slice and advance the cursor by - /// the number of bytes copied. + /// # Examples /// /// ``` - /// use std::io::Cursor; /// use bytes::Buf; + /// use std::io::Cursor; /// /// let mut buf = Cursor::new(b"hello world"); /// let mut dst = [0; 5]; @@ -91,70 +161,230 @@ pub trait Buf { } } - /// Gets an unsigned 8 bit integer from the `Buf`. + /// Gets an unsigned 8 bit integer from `self`. + /// + /// The current position is advanced by 1. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08 hello"); + /// assert_eq!(8, buf.get_u8()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is no more remaining data in `self`. fn get_u8(&mut self) -> u8 { let mut buf = [0; 1]; self.copy_to_slice(&mut buf); buf[0] } - /// Gets a signed 8 bit integer from the `Buf`. + /// Gets a signed 8 bit integer from `self`. + /// + /// The current position is advanced by 1. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08 hello"); + /// assert_eq!(8, buf.get_i8()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is no more remaining data in `self`. fn get_i8(&mut self) -> i8 { let mut buf = [0; 1]; self.copy_to_slice(&mut buf); buf[0] as i8 } - /// Gets an unsigned 16 bit integer from the `Buf` + /// Gets an unsigned 16 bit integer from `self` in the specified byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BigEndian}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08\x09 hello"); + /// assert_eq!(0x0809, buf.get_u16::<BigEndian>()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. fn get_u16<T: ByteOrder>(&mut self) -> u16 { let mut buf = [0; 2]; self.copy_to_slice(&mut buf); T::read_u16(&buf) } - /// Gets a signed 16 bit integer from the `Buf` + /// Gets a signed 16 bit integer from `self` in the specified byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BigEndian}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08\x09 hello"); + /// assert_eq!(0x0809, buf.get_i16::<BigEndian>()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. fn get_i16<T: ByteOrder>(&mut self) -> i16 { let mut buf = [0; 2]; self.copy_to_slice(&mut buf); T::read_i16(&buf) } - /// Gets an unsigned 32 bit integer from the `Buf` + /// Gets an unsigned 32 bit integer from `self` in the specified byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BigEndian}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08\x09\xA0\xA1 hello"); + /// assert_eq!(0x0809A0A1, buf.get_u32::<BigEndian>()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. fn get_u32<T: ByteOrder>(&mut self) -> u32 { let mut buf = [0; 4]; self.copy_to_slice(&mut buf); T::read_u32(&buf) } - /// Gets a signed 32 bit integer from the `Buf` + /// Gets a signed 32 bit integer from `self` in the specified byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BigEndian}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08\x09\xA0\xA1 hello"); + /// assert_eq!(0x0809A0A1, buf.get_i32::<BigEndian>()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. fn get_i32<T: ByteOrder>(&mut self) -> i32 { let mut buf = [0; 4]; self.copy_to_slice(&mut buf); T::read_i32(&buf) } - /// Gets an unsigned 64 bit integer from the `Buf` + /// Gets an unsigned 64 bit integer from `self` in the specified byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BigEndian}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08 hello"); + /// assert_eq!(0x0102030405060708, buf.get_u64::<BigEndian>()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. fn get_u64<T: ByteOrder>(&mut self) -> u64 { let mut buf = [0; 8]; self.copy_to_slice(&mut buf); T::read_u64(&buf) } - /// Gets a signed 64 bit integer from the `Buf` + /// Gets a signed 64 bit integer from `self` in the specified byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BigEndian}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08 hello"); + /// assert_eq!(0x0102030405060708, buf.get_i64::<BigEndian>()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. fn get_i64<T: ByteOrder>(&mut self) -> i64 { let mut buf = [0; 8]; self.copy_to_slice(&mut buf); T::read_i64(&buf) } - /// Gets an unsigned n-bytes integer from the `Buf` + /// Gets an unsigned n-byte integer from `self` in the specified byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BigEndian}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x01\x02\x03 hello"); + /// assert_eq!(0x010203, buf.get_uint::<BigEndian>(3)); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. fn get_uint<T: ByteOrder>(&mut self, nbytes: usize) -> u64 { let mut buf = [0; 8]; self.copy_to_slice(&mut buf[..nbytes]); T::read_uint(&buf[..nbytes], nbytes) } - /// Gets a signed n-bytes integer from the `Buf` + /// Gets a signed n-byte integer from `self` in the specified byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BigEndian}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x01\x02\x03 hello"); + /// assert_eq!(0x010203, buf.get_int::<BigEndian>(3)); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. fn get_int<T: ByteOrder>(&mut self, nbytes: usize) -> i64 { let mut buf = [0; 8]; self.copy_to_slice(&mut buf[..nbytes]); @@ -162,27 +392,132 @@ pub trait Buf { } /// Gets a IEEE754 single-precision (4 bytes) floating point number from - /// the `Buf` + /// `self` in the specified byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BigEndian}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x3F\x99\x99\x9A hello"); + /// assert_eq!(1.2f32, buf.get_f32::<BigEndian>()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. fn get_f32<T: ByteOrder>(&mut self) -> f32 { let mut buf = [0; 4]; self.copy_to_slice(&mut buf); T::read_f32(&buf) } - /// Gets a IEEE754 double-precision (8 bytes) floating point number from - /// the `Buf` + /// Gets a IEEE754 doublee-precision (8 bytes) floating point number from + /// `self` in the specified byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BigEndian}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x3F\xF3\x33\x33\x33\x33\x33\x33 hello"); + /// assert_eq!(1.2f64, buf.get_f64::<BigEndian>()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. fn get_f64<T: ByteOrder>(&mut self) -> f64 { let mut buf = [0; 8]; self.copy_to_slice(&mut buf); T::read_f64(&buf) } + /// Creates an adaptor which will read at most `limit` bytes from `self`. + /// + /// This function returns a new instance of `Buf` which will read at most + /// `limit` bytes. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BufMut}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new("hello world").take(5); + /// let mut dst = vec![]; + /// + /// dst.put(&mut buf); + /// assert_eq!(dst, b"hello"); + /// + /// let mut buf = buf.into_inner(); + /// dst.clear(); + /// dst.put(&mut buf); + /// assert_eq!(dst, b" world"); + /// ``` + fn take(self, limit: usize) -> Take<Self> + where Self: Sized + { + Take { + inner: self, + limit: limit, + } + } + /// Creates a "by reference" adaptor for this instance of Buf + /// + /// The returned adaptor also implements `Buf` and will simply borrow `self`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BufMut}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new("hello world"); + /// let mut dst = vec![]; + /// + /// { + /// let mut reference = buf.by_ref(); + /// dst.put(&mut reference.take(5)); + /// assert_eq!(dst, b"hello"); + /// } // drop our &mut reference so we can use `buf` again + /// + /// dst.clear(); + /// dst.put(&mut buf); + /// assert_eq!(dst, b" world"); + /// ``` fn by_ref(&mut self) -> &mut Self where Self: Sized { self } - /// Return a `Reader` for the value. Allows using a `Buf` as an `io::Read` + /// Creates an adaptor which implements the `Read` trait for `self`. + /// + /// This function returns a new value which implements `Read` by adapting + /// the `Read` trait functions to the `Buf` trait functions. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, IntoBuf, Bytes}; + /// use std::io::Read; + /// + /// let buf = Bytes::from("hello world").into_buf(); + /// + /// let mut reader = buf.reader(); + /// let mut dst = [0; 1024]; + /// + /// let num = reader.read(&mut dst).unwrap(); + /// + /// assert_eq!(11, num); + /// assert_eq!(&dst[..11], b"hello world"); + /// ``` fn reader(self) -> Reader<Self> where Self: Sized { Reader::new(self) } @@ -424,7 +759,7 @@ impl<'a> IntoBuf for &'a () { /* * - * ===== Sink / Source ===== + * ===== Source ===== * */ @@ -496,21 +831,63 @@ impl<'a, T: Buf> Source for &'a mut T { } } -/// A value that copies bytes from a `Buf` into itself -pub trait Sink { - /// Copy bytes from `buf` into `self` - fn sink<B: Buf>(&mut self, buf: &mut B); +/* + * + * ===== Take ===== + * + */ + +/// A `Buf` adapter which limits the bytes read from an underlying buffer. +/// +/// This struct is generally created by calling `take()` on `Buf`. [More +/// detail](trait.Buf.html#method.take). +pub struct Take<T> { + inner: T, + limit: usize, } -impl Sink for [u8] { - fn sink<B: Buf>(&mut self, buf: &mut B) { - buf.copy_to_slice(self); +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: BufMut> Sink for T { - fn sink<B: Buf>(&mut self, buf: &mut B) { - Source::source(buf, self) +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); } } @@ -551,7 +928,7 @@ impl<B: Buf + Sized> io::Read for Reader<B> { fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> { let len = cmp::min(self.buf.remaining(), dst.len()); - Buf::copy_to(&mut self.buf, &mut dst[0..len]); + Buf::copy_to_slice(&mut self.buf, &mut dst[0..len]); Ok(len) } } diff --git a/src/lib.rs b/src/lib.rs index 834f5b0..1637637 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,8 +75,9 @@ pub use buf::{ BufMut, IntoBuf, Source, - Sink, Reader, Writer, + Take, }; pub use bytes::{Bytes, BytesMut}; +pub use byteorder::{ByteOrder, BigEndian, LittleEndian}; diff --git a/tests/test_buf.rs b/tests/test_buf.rs index 1e3d1f6..27229e8 100644 --- a/tests/test_buf.rs +++ b/tests/test_buf.rs @@ -1,7 +1,7 @@ extern crate bytes; extern crate byteorder; -use bytes::{Buf, Sink}; +use bytes::Buf; use std::io::Cursor; #[test] @@ -46,13 +46,3 @@ fn test_get_u16_buffer_underflow() { let mut buf = Cursor::new(b"\x21"); buf.get_u16::<byteorder::BigEndian>(); } - -#[test] -fn test_vec_sink_capacity() { - let mut sink: Vec<u8> = Vec::new(); - sink.reserve(16); - assert!(sink.capacity() >= 16, "Capacity {} must be at least 16", sink.capacity()); - let mut source = Cursor::new(b"0123456789abcdef0123456789abcdef"); - sink.sink(&mut source); - assert!(sink.len() <= sink.capacity(), "Length {} must be less than or equal to capacity {}", sink.len(), sink.capacity()); -} -- GitLab