diff --git a/Cargo.toml b/Cargo.toml index b8735422b69b35a03b018f0c84fcdcf4062a5e06..217319a0ede036453bbf2db057ada5f486b034e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ categories = ["network-programming", "data-structures"] [dependencies] byteorder = "1.0.0" +iovec = { git = "https://github.com/carllerche/iovec" } [dev-dependencies] tokio-core = "0.1.0" diff --git a/src/buf/buf.rs b/src/buf/buf.rs index 3f3dbb6e8ba5207475daec0a0580f103472f8230..0732aff145ea6f7759f854a3b4fe77eac67171c2 100644 --- a/src/buf/buf.rs +++ b/src/buf/buf.rs @@ -1,5 +1,6 @@ use super::{Take, Reader, Iter, FromBuf}; use byteorder::ByteOrder; +use iovec::IoVec; use std::{cmp, io, ptr}; @@ -72,6 +73,34 @@ pub trait Buf { /// ``` fn bytes(&self) -> &[u8]; + /// Fills `dst` with potentially multiple slices starting at `self`'s + /// current position. + /// + /// If the `Buf` is backed by disjoint slices of bytes, `bytes_vec` enables + /// fetching more than one slice at once. `dst` is a slice of `IoVec` + /// references, enabling the slice to be directly used with [`writev`] + /// without any further conversion. The sum of the lengths of all the + /// buffers in `dst` will be less than or equal to `Buf::remaining()`. + /// + /// The entries in `dst` will be overwritten, but the data **contained** by + /// the slices **will not** be modified. If `bytes_vec` does not fill every + /// entry in `dst`, then `dst` is guaranteed to contain all remaining slices + /// in `self. + /// + /// This is a lower level function. Most operations are done with other + /// functions. + /// + /// [`writev`]: http://man7.org/linux/man-pages/man2/readv.2.html + fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize { + if dst.is_empty() { + return 0; + } + + dst[0] = self.bytes().into(); + + 1 + } + /// Advance the internal cursor of the Buf /// /// The next call to `bytes` will return a slice starting `cnt` bytes @@ -576,6 +605,10 @@ impl<'a, T: Buf + ?Sized> Buf for &'a mut T { (**self).bytes() } + fn bytes_vec<'b>(&'b self, dst: &mut [&'b IoVec]) -> usize { + (**self).bytes_vec(dst) + } + fn advance(&mut self, cnt: usize) { (**self).advance(cnt) } @@ -590,6 +623,10 @@ impl<T: Buf + ?Sized> Buf for Box<T> { (**self).bytes() } + fn bytes_vec<'b>(&'b self, dst: &mut [&'b IoVec]) -> usize { + (**self).bytes_vec(dst) + } + fn advance(&mut self, cnt: usize) { (**self).advance(cnt) } diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs index 2e3c141b91da260ae5ee20a16302babef87a3df1..7ecc8b2d4e92141948c450b5dd23fb28aabb9217 100644 --- a/src/buf/buf_mut.rs +++ b/src/buf/buf_mut.rs @@ -1,5 +1,6 @@ use super::{Source, Writer}; use byteorder::ByteOrder; +use iovec::IoVec; use std::{cmp, io, ptr, usize}; @@ -137,6 +138,35 @@ pub trait BufMut { /// ``` unsafe fn bytes_mut(&mut self) -> &mut [u8]; + /// Fills `dst` with potentially multiple mutable slices starting at `self`'s + /// current position. + /// + /// If the `BufMut` is backed by disjoint slices of bytes, `bytes_vec_mut` + /// enables fetching more than one slice at once. `dst` is a slice of + /// mutable `IoVec` references, enabling the slice to be directly used with + /// [`readv`] without any further conversion. The sum of the lengths of all + /// the buffers in `dst` will be less than or equal to + /// `Buf::remaining_mut()`. + /// + /// The entries in `dst` will be overwritten, but the data **contained** by + /// the slices **will not** be modified. If `bytes_vec_mut` does not fill every + /// entry in `dst`, then `dst` is guaranteed to contain all remaining slices + /// in `self. + /// + /// This is a lower level function. Most operations are done with other + /// functions. + /// + /// [`readv`]: http://man7.org/linux/man-pages/man2/readv.2.html + unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize { + if dst.is_empty() { + return 0; + } + + dst[0] = self.bytes_mut().into(); + + 1 + } + /// Transfer bytes into `self` from `src` and advance the cursor by the /// number of bytes written. /// @@ -513,6 +543,10 @@ impl<'a, T: BufMut + ?Sized> BufMut for &'a mut T { (**self).bytes_mut() } + unsafe fn bytes_vec_mut<'b>(&'b mut self, dst: &mut [&'b mut IoVec]) -> usize { + (**self).bytes_vec_mut(dst) + } + unsafe fn advance_mut(&mut self, cnt: usize) { (**self).advance_mut(cnt) } @@ -527,6 +561,10 @@ impl<T: BufMut + ?Sized> BufMut for Box<T> { (**self).bytes_mut() } + unsafe fn bytes_vec_mut<'b>(&'b mut self, dst: &mut [&'b mut IoVec]) -> usize { + (**self).bytes_vec_mut(dst) + } + unsafe fn advance_mut(&mut self, cnt: usize) { (**self).advance_mut(cnt) } diff --git a/src/bytes.rs b/src/bytes.rs index 1ebcff19bad19340d0e05357a9a96bcfbc146114..fb70101b56cd54a3b47c9bd3ebdda00beff47a6f 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -1229,7 +1229,8 @@ impl<'a> From<&'a [u8]> for BytesMut { } } else { let mut buf = BytesMut::with_capacity(src.len()); - buf.put(src.as_ref()); + let src: &[u8] = src.as_ref(); + buf.put(src); buf } } diff --git a/src/lib.rs b/src/lib.rs index 521f80c560ca2418bdbe4d7dbee44be28bce09a9..d62db78f97b2d1946ed1350d5a137c13c2fb7453 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,6 +72,7 @@ #![doc(html_root_url = "https://docs.rs/bytes/0.4")] extern crate byteorder; +extern crate iovec; pub mod buf; pub use buf::{ diff --git a/tests/test_buf.rs b/tests/test_buf.rs index 27229e816857d9fb7f99a8cc3a7159f77fcc7b1d..5c989c34af096735834cf77d8f2c24bd02b8c834 100644 --- a/tests/test_buf.rs +++ b/tests/test_buf.rs @@ -1,7 +1,9 @@ extern crate bytes; extern crate byteorder; +extern crate iovec; use bytes::Buf; +use iovec::IoVec; use std::io::Cursor; #[test] @@ -46,3 +48,11 @@ fn test_get_u16_buffer_underflow() { let mut buf = Cursor::new(b"\x21"); buf.get_u16::<byteorder::BigEndian>(); } + +#[test] +fn test_bufs_vec() { + let buf = Cursor::new(b"hello world"); + let mut dst: [&IoVec; 2] = Default::default(); + + assert_eq!(1, buf.bytes_vec(&mut dst[..])); +} diff --git a/tests/test_buf_mut.rs b/tests/test_buf_mut.rs index d15a9209c7a12c2a4c4196eb959b49d5d737337b..fe2e9c8b96e8b811b6f160bf2d5fded4dd039355 100644 --- a/tests/test_buf_mut.rs +++ b/tests/test_buf_mut.rs @@ -1,7 +1,9 @@ extern crate bytes; extern crate byteorder; +extern crate iovec; use bytes::{BufMut, BytesMut}; +use iovec::IoVec; use std::usize; use std::fmt::Write; @@ -56,3 +58,15 @@ fn test_clone() { buf.write_str(" of our emergecy broadcast system").unwrap(); assert!(buf != buf2); } + +#[test] +fn test_bufs_vec_mut() { + use std::mem; + + let mut buf = BytesMut::from(&b"hello world"[..]); + + unsafe { + let mut dst: [&mut IoVec; 2] = mem::zeroed(); + assert_eq!(1, buf.bytes_vec_mut(&mut dst[..])); + } +}