diff --git a/Cargo.toml b/Cargo.toml index 58eea9e..4c415ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,8 +13,9 @@ edition = "2021" [features] -[dependencies] -bytes = { version = "0.5", optional = true } +[dependencies.bytes] +version = "1.1.0" +optional = true [dev-dependencies] vecio = "0.1.0" diff --git a/src/bytes.rs b/src/bytes.rs new file mode 100755 index 0000000..1795f73 --- /dev/null +++ b/src/bytes.rs @@ -0,0 +1,158 @@ +use std::io::IoSlice; + +use crate::CircBuf; + +use bytes::{buf::UninitSlice, Buf, BufMut}; + +impl Buf for CircBuf { + fn advance(&mut self, count: usize) { + assert!(count == 0 || count <= self.remaining()); + self.advance_read(count); + } + + fn chunk(&self) -> &[u8] { + let [left, right] = self.get_bytes(); + match (left.is_empty(), right.is_empty()) { + (true, true) => left, + (true, false) => right, + (false, true) => left, + (false, false) => left, + } + } + + fn remaining(&self) -> usize { + self.len() + } + + fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize { + let [left, right] = self.get_bytes(); + let mut count = 0; + if let Some(slice) = dst.get_mut(0) { + count += 1; + *slice = IoSlice::new(left); + } + if let Some(slice) = dst.get_mut(1) { + count += 1; + *slice = IoSlice::new(right); + } + count + } +} + +unsafe impl BufMut for CircBuf { + unsafe fn advance_mut(&mut self, count: usize) { + assert!(count == 0 || count <= self.remaining_mut()); + self.advance_write(count); + } + + fn chunk_mut<'this>(&'this mut self) -> &'this mut UninitSlice { + let [left, right] = self.get_avail(); + let slice = match (left.is_empty(), right.is_empty()) { + (true, true) => left, + (true, false) => right, + (false, true) => left, + (false, false) => left, + }; + // https://docs.rs/bytes/latest/bytes/buf/struct.UninitSlice.html#method.from_raw_parts_mut + unsafe { UninitSlice::from_raw_parts_mut(slice.as_mut_ptr(), slice.len()) } + } + + fn remaining_mut(&self) -> usize { + self.avail() + } +} + +#[cfg(test)] +mod tests { + use crate::CircBuf; + use bytes::{Buf, BufMut}; + use std::io::IoSlice; + + #[test] + fn bytes_buf_and_bufmut() { + let mut c = CircBuf::with_capacity(4).unwrap(); + + assert_eq!(c.remaining(), 0); + assert_eq!(c.remaining_mut(), 3); + unsafe { + c.advance_mut(2); + } + assert_eq!(c.remaining(), 2); + assert_eq!(c.remaining_mut(), 1); + c.advance(1); + assert_eq!(c.remaining(), 1); + assert_eq!(c.remaining_mut(), 2); + unsafe { + c.advance_mut(1); + } + assert_eq!(c.remaining(), 2); + assert_eq!(c.remaining_mut(), 1); + + assert_eq!(::chunk(&c).len(), 2); + assert_eq!(c.chunk_mut().len(), 1); + + let mut dst = [IoSlice::new(&[]); 2]; + assert_eq!(c.chunks_vectored(&mut dst[..]), 2); + + assert_eq!(dst[0].len(), 2); + assert_eq!(dst[1].len(), 0); + } + + #[test] + fn bytes_buf_remaining() { + use bytes::{Buf, BufMut}; + + let mut c = CircBuf::with_capacity(4).unwrap(); + + assert_eq!(c.remaining(), 0); + assert_eq!(c.remaining_mut(), 3); + assert!(!c.has_remaining()); + assert!(c.has_remaining_mut()); + + unsafe { + c.advance_mut(3); + } + + assert_eq!(c.remaining(), 3); + assert_eq!(c.remaining_mut(), 0); + assert!(c.has_remaining()); + assert!(!c.has_remaining_mut()); + + c.advance(2); + + assert_eq!(c.remaining(), 1); + assert_eq!(c.remaining_mut(), 2); + assert!(c.has_remaining()); + assert!(c.has_remaining_mut()); + + c.advance(1); + + assert_eq!(c.remaining(), 0); + assert_eq!(c.remaining_mut(), 3); + assert!(!c.has_remaining()); + assert!(c.has_remaining_mut()); + } + + #[cfg(feature = "bytes")] + #[test] + fn bytes_bufmut_hello() { + use bytes::BufMut; + + let mut c = CircBuf::with_capacity(16).unwrap(); + + unsafe { + c.chunk_mut().write_byte(0, b'h'); + c.chunk_mut().write_byte(1, b'e'); + + c.advance_mut(2); + + c.chunk_mut().write_byte(0, b'l'); + c.chunk_mut().write_byte(1, b'l'); + c.chunk_mut().write_byte(2, b'o'); + + c.advance_mut(3); + } + + assert_eq!(c.get_bytes()[0], b"hello"); + } +} diff --git a/src/lib.rs b/src/lib.rs index bec5a6f..c35f4d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,6 +114,9 @@ //! } //! ``` +#[cfg(feature = "bytes")] +mod bytes; + use std::boxed::Box; use std::error; use std::fmt; @@ -547,82 +550,6 @@ impl io::Write for CircBuf { } } -#[cfg(feature = "bytes")] -impl bytes::Buf for CircBuf { - fn remaining(&self) -> usize { - self.len() - } - - fn advance(&mut self, count: usize) { - assert!(count == 0 || count <= self.remaining()); - self.advance_read(count); - } - - fn bytes(&self) -> &[u8] { - let [left, right] = self.get_bytes(); - match (left.is_empty(), right.is_empty()) { - (true, true) => left, - (true, false) => right, - (false, true) => left, - (false, false) => left, - } - } - - fn bytes_vectored<'a>(&'a self, dst: &mut [io::IoSlice<'a>]) -> usize { - let [left, right] = self.get_bytes(); - let mut count = 0; - if let Some(slice) = dst.get_mut(0) { - count += 1; - *slice = io::IoSlice::new(left); - } - if let Some(slice) = dst.get_mut(1) { - count += 1; - *slice = io::IoSlice::new(right); - } - count - } -} - -#[cfg(feature = "bytes")] -impl bytes::BufMut for CircBuf { - fn remaining_mut(&self) -> usize { - self.avail() - } - - unsafe fn advance_mut(&mut self, count: usize) { - assert!(count == 0 || count <= self.remaining_mut()); - self.advance_write(count); - } - - fn bytes_mut<'this>(&'this mut self) -> &'this mut [std::mem::MaybeUninit] { - let [left, right] = self.get_avail(); - let slice = match (left.is_empty(), right.is_empty()) { - (true, true) => left, - (true, false) => right, - (false, true) => left, - (false, false) => left, - }; - // As far as I can tell it is perfectly safe to convert from u8 to MaybeUninit. - unsafe { - std::mem::transmute::<&'this mut [u8], &'this mut [std::mem::MaybeUninit]>(slice) - } - } - - fn bytes_vectored_mut<'a>(&'a mut self, dst: &mut [bytes::buf::IoSliceMut<'a>]) -> usize { - let [left, right] = self.get_avail(); - let mut count = 0; - if let Some(slice) = dst.get_mut(0) { - count += 1; - *slice = bytes::buf::IoSliceMut::from(left); - } - if let Some(slice) = dst.get_mut(1) { - count += 1; - *slice = bytes::buf::IoSliceMut::from(right); - } - count - } -} - #[cfg(test)] mod tests { use super::{CircBuf, CircBufError, DEFAULT_CAPACITY}; @@ -932,108 +859,4 @@ mod tests { assert_eq!(c.read_to_string(&mut s).unwrap(), 8); assert_eq!(s, "fizzbuzz"); } - - #[cfg(feature = "bytes")] - #[test] - fn bytes_buf_and_bufmut() { - use bytes::{Buf, BufMut}; - - let mut c = CircBuf::with_capacity(4).unwrap(); - - assert_eq!(c.remaining(), 0); - assert_eq!(c.remaining_mut(), 3); - unsafe { - c.advance_mut(2); - } - assert_eq!(c.remaining(), 2); - assert_eq!(c.remaining_mut(), 1); - c.advance(1); - assert_eq!(c.remaining(), 1); - assert_eq!(c.remaining_mut(), 2); - unsafe { - c.advance_mut(1); - } - assert_eq!(c.remaining(), 2); - assert_eq!(c.remaining_mut(), 1); - - assert_eq!(::bytes(&c).len(), 2); - assert_eq!(c.bytes_mut().len(), 1); - - let mut dst = [std::io::IoSlice::new(&[]); 2]; - assert_eq!(c.bytes_vectored(&mut dst[..]), 2); - - assert_eq!(dst[0].len(), 2); - assert_eq!(dst[1].len(), 0); - - let b1: &mut [u8] = &mut []; - let b2: &mut [u8] = &mut []; - let mut dst_mut = [ - bytes::buf::IoSliceMut::from(b1), - bytes::buf::IoSliceMut::from(b2), - ]; - - assert_eq!(c.bytes_vectored_mut(&mut dst_mut[..]), 2); - - assert!(c.has_remaining()); - assert!(c.has_remaining_mut()); - } - - #[cfg(feature = "bytes")] - #[test] - fn bytes_buf_remaining() { - use bytes::{Buf, BufMut}; - - let mut c = CircBuf::with_capacity(4).unwrap(); - - assert_eq!(c.remaining(), 0); - assert_eq!(c.remaining_mut(), 3); - assert!(!c.has_remaining()); - assert!(c.has_remaining_mut()); - - unsafe { - c.advance_mut(3); - } - - assert_eq!(c.remaining(), 3); - assert_eq!(c.remaining_mut(), 0); - assert!(c.has_remaining()); - assert!(!c.has_remaining_mut()); - - c.advance(2); - - assert_eq!(c.remaining(), 1); - assert_eq!(c.remaining_mut(), 2); - assert!(c.has_remaining()); - assert!(c.has_remaining_mut()); - - c.advance(1); - - assert_eq!(c.remaining(), 0); - assert_eq!(c.remaining_mut(), 3); - assert!(!c.has_remaining()); - assert!(c.has_remaining_mut()); - } - - #[cfg(feature = "bytes")] - #[test] - fn bytes_bufmut_hello() { - use bytes::BufMut; - - let mut c = CircBuf::with_capacity(16).unwrap(); - - unsafe { - c.bytes_mut()[0].as_mut_ptr().write(b'h'); - c.bytes_mut()[1].as_mut_ptr().write(b'e'); - - c.advance_mut(2); - - c.bytes_mut()[0].as_mut_ptr().write(b'l'); - c.bytes_mut()[1].as_mut_ptr().write(b'l'); - c.bytes_mut()[2].as_mut_ptr().write(b'o'); - - c.advance_mut(3); - } - - assert_eq!(c.get_bytes()[0], b"hello"); - } }