Group files as buf or byte str related

This commit is contained in:
Carl Lerche
2015-04-07 23:40:00 -07:00
parent c4f2e20eb1
commit ac42766535
13 changed files with 626 additions and 589 deletions
+269
View File
@@ -0,0 +1,269 @@
use {alloc, Bytes, SeqByteStr, MAX_CAPACITY};
use traits::{Buf, MutBuf, MutBufExt, ByteStr};
use std::{cmp, ptr};
/*
*
* ===== ByteBuf =====
*
*/
/// A `Buf` backed by a contiguous region of memory.
pub struct ByteBuf {
mem: alloc::MemRef,
cap: u32,
pos: u32,
lim: u32
}
impl ByteBuf {
/// Create a new `ByteBuf` by copying the contents of the given slice.
pub fn from_slice(bytes: &[u8]) -> ByteBuf {
let mut buf = ByteBuf::mut_with_capacity(bytes.len());
buf.write(bytes).ok().expect("unexpected failure");
buf.flip()
}
pub fn mut_with_capacity(capacity: usize) -> MutByteBuf {
assert!(capacity <= MAX_CAPACITY);
MutByteBuf { buf: ByteBuf::new(capacity as u32) }
}
pub fn none() -> ByteBuf {
ByteBuf {
mem: alloc::MemRef::none(),
cap: 0,
pos: 0,
lim: 0,
}
}
pub unsafe fn from_mem_ref(mem: alloc::MemRef, cap: u32, pos: u32, lim: u32) -> ByteBuf {
debug_assert!(pos <= lim && lim <= cap, "invalid arguments; cap={}; pos={}; lim={}", cap, pos, lim);
ByteBuf {
mem: mem,
cap: cap,
pos: pos,
lim: lim,
}
}
fn new(mut capacity: u32) -> ByteBuf {
// Handle 0 capacity case
if capacity == 0 {
return ByteBuf::none();
}
// Round the capacity to the closest power of 2
capacity = capacity.next_power_of_two();
// Allocate the memory
let mem = alloc::heap(capacity as usize);
// If the allocation failed, return a blank buf
if mem.is_none() {
return ByteBuf::none();
}
ByteBuf {
mem: mem,
cap: capacity,
pos: 0,
lim: capacity
}
}
pub fn capacity(&self) -> usize {
self.cap as usize
}
pub fn flip(self) -> MutByteBuf {
let mut buf = MutByteBuf { buf: self };
buf.clear();
buf
}
pub fn read_slice(&mut self, dst: &mut [u8]) -> usize {
let len = cmp::min(dst.len(), self.remaining());
let cnt = len as u32;
unsafe {
ptr::copy_nonoverlapping(
self.mem.ptr().offset(self.pos as isize),
dst.as_mut_ptr(),
len);
}
self.pos += cnt;
len
}
pub fn to_seq_byte_str(self) -> SeqByteStr {
unsafe {
let ByteBuf { mem, pos, lim, .. } = self;
SeqByteStr::from_mem_ref(
mem, pos, lim - pos)
}
}
#[inline]
pub fn to_bytes(self) -> Bytes {
Bytes::of(self.to_seq_byte_str())
}
#[inline]
fn pos(&self) -> usize {
self.pos as usize
}
#[inline]
fn lim(&self) -> usize {
self.lim as usize
}
#[inline]
fn remaining_u32(&self) -> u32 {
self.lim - self.pos
}
}
impl Buf for ByteBuf {
#[inline]
fn remaining(&self) -> usize {
self.remaining_u32() as usize
}
#[inline]
fn bytes<'a>(&'a self) -> &'a [u8] {
&self.mem.bytes()[self.pos()..self.lim()]
}
#[inline]
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.pos += cnt as u32;
}
#[inline]
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
ByteBuf::read_slice(self, dst)
}
}
/*
*
* ===== ROByteBuf =====
*
*/
/// Same as `ByteBuf` but cannot be flipped to a `MutByteBuf`.
pub struct ROByteBuf {
buf: ByteBuf,
}
impl ROByteBuf {
pub unsafe fn from_mem_ref(mem: alloc::MemRef, cap: u32, pos: u32, lim: u32) -> ROByteBuf {
ROByteBuf {
buf: ByteBuf::from_mem_ref(mem, cap, pos, lim)
}
}
pub fn to_seq_byte_str(self) -> SeqByteStr {
self.buf.to_seq_byte_str()
}
pub fn to_bytes(self) -> Bytes {
self.buf.to_bytes()
}
}
impl Buf for ROByteBuf {
fn remaining(&self) -> usize {
self.buf.remaining()
}
fn bytes<'a>(&'a self) -> &'a [u8] {
self.buf.bytes()
}
fn advance(&mut self, cnt: usize) {
self.buf.advance(cnt)
}
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
self.buf.read_slice(dst)
}
}
/*
*
* ===== MutByteBuf =====
*
*/
pub struct MutByteBuf {
buf: ByteBuf,
}
impl MutByteBuf {
pub fn capacity(&self) -> usize {
self.buf.capacity() as usize
}
pub fn flip(self) -> ByteBuf {
let mut buf = self.buf;
buf.lim = buf.pos;
buf.pos = 0;
buf
}
pub fn clear(&mut self) {
self.buf.pos = 0;
self.buf.lim = self.buf.cap;
}
#[inline]
pub fn write_slice(&mut self, src: &[u8]) -> usize {
let cnt = src.len() as u32;
let rem = self.buf.remaining_u32();
if rem < cnt {
self.write_ptr(src.as_ptr(), rem)
} else {
self.write_ptr(src.as_ptr(), cnt)
}
}
#[inline]
fn write_ptr(&mut self, src: *const u8, len: u32) -> usize {
unsafe {
ptr::copy_nonoverlapping(
src,
self.buf.mem.ptr().offset(self.buf.pos as isize),
len as usize);
self.buf.pos += len;
len as usize
}
}
}
impl MutBuf for MutByteBuf {
fn remaining(&self) -> usize {
self.buf.remaining()
}
fn advance(&mut self, cnt: usize) {
self.buf.advance(cnt)
}
fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
let pos = self.buf.pos();
let lim = self.buf.lim();
&mut self.buf.mem.bytes_mut()[pos..lim]
}
}
+364
View File
@@ -0,0 +1,364 @@
mod byte;
mod ring;
mod sink;
mod slice;
mod source;
pub use self::byte::{ByteBuf, MutByteBuf, ROByteBuf};
pub use self::ring::RingBuf;
pub use self::slice::{SliceBuf, MutSliceBuf};
use {BufError, RopeBuf};
use std::{cmp, fmt, io, ptr};
/// A trait for values that provide sequential read access to bytes.
pub trait Buf {
/// Returns the number of bytes that can be accessed from the Buf
fn remaining(&self) -> usize;
/// Returns a slice starting at the current Buf position and of length
/// between 0 and `Buf::remaining()`.
fn bytes<'a>(&'a self) -> &'a [u8];
/// Advance the internal cursor of the Buf
fn advance(&mut self, cnt: usize);
/// Returns true if there are any more bytes to consume
fn has_remaining(&self) -> bool {
self.remaining() > 0
}
/// Read bytes from the `Buf` into the given slice and advance the cursor by
/// the number of bytes read.
///
/// If there are fewer bytes remaining than is needed to satisfy the
/// request (aka `dst.len()` > self.remaining()`), then
/// `Err(BufError::Overflow)` is returned.
///
/// ```
/// use bytes::{SliceBuf, Buf};
///
/// let mut buf = SliceBuf::wrap(b"hello world");
/// let mut dst = [0; 5];
///
/// buf.read_slice(&mut dst);
/// assert_eq!(b"hello", &dst);
/// assert_eq!(6, buf.remaining());
/// ```
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
let mut off = 0;
let len = cmp::min(dst.len(), self.remaining());
while off < len {
let mut cnt;
unsafe {
let src = self.bytes();
cnt = cmp::min(src.len(), len - off);
ptr::copy_nonoverlapping(
src.as_ptr(), dst[off..].as_mut_ptr(), cnt);
off += src.len();
}
self.advance(cnt);
}
len
}
/// Read a single byte from the `Buf`
fn read_byte(&mut self) -> Option<u8> {
let mut dst = [0];
if self.read_slice(&mut dst) == 0 {
return None;
}
Some(dst[0])
}
}
/// An extension trait providing extra functions applicable to all `Buf` values.
pub trait BufExt {
/// Read bytes from this Buf into the given sink and advance the cursor by
/// the number of bytes read.
fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error>;
}
/// A trait for values that provide sequential write access to bytes.
pub trait MutBuf : Sized {
/// Returns the number of bytes that can be accessed from the Buf
fn remaining(&self) -> usize;
/// Advance the internal cursor of the Buf
fn advance(&mut self, cnt: usize);
/// Returns true if there are any more bytes to consume
fn has_remaining(&self) -> bool {
self.remaining() > 0
}
/// Returns a mutable slice starting at the current Buf position and of
/// length between 0 and `Buf::remaining()`.
fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8];
/// Read bytes from this Buf into the given slice and advance the cursor by
/// the number of bytes read.
///
/// If there are fewer bytes remaining than is needed to satisfy the
/// request (aka `dst.len()` > self.remaining()`), then
/// `Err(BufError::Overflow)` is returned.
///
/// ```
/// use bytes::{MutSliceBuf, Buf, MutBuf};
///
/// let mut dst = [0; 6];
///
/// {
/// let mut buf = MutSliceBuf::wrap(&mut dst);
/// buf.write_slice(b"hello");
///
/// assert_eq!(1, buf.remaining());
/// }
///
/// assert_eq!(b"hello\0", &dst);
/// ```
fn write_slice(&mut self, src: &[u8]) -> usize {
let mut off = 0;
let len = cmp::min(src.len(), self.remaining());
while off < len {
let mut cnt;
unsafe {
let dst = self.mut_bytes();
cnt = cmp::min(dst.len(), len - off);
ptr::copy_nonoverlapping(
src[off..].as_ptr(),
dst.as_mut_ptr(),
cnt);
off += cnt;
}
self.advance(cnt);
}
len
}
/// Write a single byte to the `MuBuf`
fn write_byte(&mut self, byte: u8) -> bool {
let src = [byte];
if self.write_slice(&src) == 0 {
return false;
}
true
}
}
/// An extension trait providing extra functions applicable to all `MutBuf` values.
pub trait MutBufExt {
/// Write bytes from the given source into the current `MutBuf` and advance
/// the cursor by the number of bytes written.
fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error>;
}
/*
*
* ===== *Ext impls =====
*
*/
impl<B: Buf> BufExt for B {
fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error> {
dst.sink(self)
}
}
impl<B: MutBuf> MutBufExt for B {
fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error> {
src.fill(self)
}
}
/*
*
* ===== Sink / Source =====
*
*/
/// A value that reads bytes from a Buf into itself
pub trait Sink {
type Error;
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}
/// A value that writes bytes from itself into a `MutBuf`.
pub trait Source {
type Error;
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}
impl<'a> Sink for &'a mut [u8] {
type Error = BufError;
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
Ok(buf.read_slice(self))
}
}
impl<'a> Sink for &'a mut Vec<u8> {
type Error = BufError;
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
use std::slice;
self.clear();
let rem = buf.remaining();
let cap = self.capacity();
// Ensure that the vec is big enough
if rem > self.capacity() {
self.reserve(rem - cap);
}
unsafe {
{
let dst = &mut self[..];
let cnt = buf.read_slice(slice::from_raw_parts_mut(dst.as_mut_ptr(), rem));
debug_assert!(cnt == rem);
}
self.set_len(rem);
}
Ok(rem)
}
}
impl<'a> Source for &'a [u8] {
type Error = BufError;
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
Ok(buf.write_slice(self))
}
}
impl<'a> Source for &'a Vec<u8> {
type Error = BufError;
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
Ok(buf.write_slice(self.as_ref()))
}
}
impl<'a, R: io::Read+'a> Source for &'a mut R {
type Error = io::Error;
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, io::Error> {
let mut cnt = 0;
while buf.has_remaining() {
let i = try!(self.read(buf.mut_bytes()));
if i == 0 {
break;
}
buf.advance(i);
cnt += i;
}
Ok(cnt)
}
}
/*
*
* ===== Buf impls =====
*
*/
impl Buf for Box<Buf+'static> {
fn remaining(&self) -> usize {
(**self).remaining()
}
fn bytes(&self) -> &[u8] {
(**self).bytes()
}
fn advance(&mut self, cnt: usize) {
(**self).advance(cnt);
}
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
(**self).read_slice(dst)
}
}
impl fmt::Debug for Box<Buf+'static> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Box<Buf> {{ remaining: {} }}", self.remaining())
}
}
/*
*
* ===== Read impls =====
*
*/
macro_rules! impl_read {
($ty:ty) => {
impl io::Read for $ty {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if !self.has_remaining() {
return Ok(0);
}
Ok(self.read_slice(buf))
}
}
}
}
impl_read!(ByteBuf);
impl_read!(ROByteBuf);
impl_read!(RopeBuf);
impl_read!(Box<Buf+'static>);
macro_rules! impl_write {
($ty:ty) => {
impl io::Write for $ty {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if !self.has_remaining() {
return Ok(0);
}
Ok(self.write_slice(buf))
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
}
}
impl_write!(MutByteBuf);
+187
View File
@@ -0,0 +1,187 @@
use {alloc, Buf, MutBuf};
use std::{cmp, fmt, io, ptr};
/// Buf backed by a continous chunk of memory. Maintains a read cursor and a
/// write cursor. When reads and writes reach the end of the allocated buffer,
/// wraps around to the start.
pub struct RingBuf {
ptr: alloc::MemRef, // Pointer to the memory
cap: usize, // Capacity of the buffer
pos: usize, // Offset of read cursor
len: usize // Number of bytes to read
}
// TODO: There are most likely many optimizations that can be made
impl RingBuf {
pub fn new(mut capacity: usize) -> RingBuf {
// Handle the 0 length buffer case
if capacity == 0 {
return RingBuf {
ptr: alloc::MemRef::none(),
cap: 0,
pos: 0,
len: 0
}
}
// Round to the next power of 2 for better alignment
capacity = capacity.next_power_of_two();
let mem = alloc::heap(capacity as usize);
RingBuf {
ptr: mem,
cap: capacity,
pos: 0,
len: 0
}
}
pub fn is_full(&self) -> bool {
self.cap == self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn capacity(&self) -> usize {
self.cap
}
fn read_remaining(&self) -> usize {
self.len
}
fn write_remaining(&self) -> usize {
self.cap - self.len
}
fn advance_reader(&mut self, mut cnt: usize) {
if self.cap == 0 {
return;
}
cnt = cmp::min(cnt, self.read_remaining());
self.pos += cnt;
self.pos %= self.cap;
self.len -= cnt;
}
fn advance_writer(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.write_remaining());
self.len += cnt;
}
}
impl Clone for RingBuf {
fn clone(&self) -> RingBuf {
use std::cmp;
let mut ret = RingBuf::new(self.cap);
ret.pos = self.pos;
ret.len = self.len;
unsafe {
let to = self.pos + self.len;
if to > self.cap {
ptr::copy(self.ptr.ptr() as *const u8, ret.ptr.ptr(), to % self.cap);
}
ptr::copy(
self.ptr.ptr().offset(self.pos as isize) as *const u8,
ret.ptr.ptr().offset(self.pos as isize),
cmp::min(self.len, self.cap - self.pos));
}
ret
}
// TODO: an improved version of clone_from is possible that potentially
// re-uses the buffer
}
impl fmt::Debug for RingBuf {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "RingBuf[.. {}]", self.len)
}
}
impl Buf for RingBuf {
fn remaining(&self) -> usize {
self.read_remaining()
}
fn bytes(&self) -> &[u8] {
let mut to = self.pos + self.len;
if to > self.cap {
to = self.cap
}
&self.ptr.bytes()[self.pos .. to]
}
fn advance(&mut self, cnt: usize) {
self.advance_reader(cnt)
}
}
impl MutBuf for RingBuf {
fn remaining(&self) -> usize {
self.write_remaining()
}
fn advance(&mut self, cnt: usize) {
self.advance_writer(cnt)
}
fn mut_bytes(&mut self) -> &mut [u8] {
if self.cap == 0 {
return self.ptr.bytes_mut();
}
let mut from;
let mut to;
from = self.pos + self.len;
from %= self.cap;
to = from + <Self as MutBuf>::remaining(&self);
if to >= self.cap {
to = self.cap;
}
&mut self.ptr.bytes_mut()[from..to]
}
}
impl io::Read for RingBuf {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if !MutBuf::has_remaining(self) {
return Ok(0);
}
Ok(self.read_slice(buf))
}
}
impl io::Write for RingBuf {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if !Buf::has_remaining(self) {
return Ok(0);
}
Ok(self.write_slice(buf))
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
unsafe impl Send for RingBuf { }
View File
+59
View File
@@ -0,0 +1,59 @@
use std::cmp;
use {Buf, MutBuf};
// TODO: Rename -> Cursor. Use as buf for various byte strings
pub struct SliceBuf<'a> {
bytes: &'a [u8],
pos: usize
}
impl<'a> SliceBuf<'a> {
pub fn wrap(bytes: &'a [u8]) -> SliceBuf<'a> {
SliceBuf { bytes: bytes, pos: 0 }
}
}
impl<'a> Buf for SliceBuf<'a> {
fn remaining(&self) -> usize {
self.bytes.len() - self.pos
}
fn bytes<'b>(&'b self) -> &'b [u8] {
&self.bytes[self.pos..]
}
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.pos += cnt;
}
}
pub struct MutSliceBuf<'a> {
bytes: &'a mut [u8],
pos: usize
}
impl<'a> MutSliceBuf<'a> {
pub fn wrap(bytes: &'a mut [u8]) -> MutSliceBuf<'a> {
MutSliceBuf {
bytes: bytes,
pos: 0
}
}
}
impl<'a> MutBuf for MutSliceBuf<'a> {
fn remaining(&self) -> usize {
self.bytes.len() - self.pos
}
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.pos += cnt;
}
fn mut_bytes<'b>(&'b mut self) -> &'b mut [u8] {
&mut self.bytes[self.pos..]
}
}
View File