Merge pull request #1123 from hyperium/body-concat
feat(chunk): implement Extend and IntoIterator for Chunk
This commit is contained in:
		| @@ -96,3 +96,18 @@ fn _assert_send_sync() { | |||||||
|     _assert_send::<Chunk>(); |     _assert_send::<Chunk>(); | ||||||
|     _assert_sync::<Chunk>(); |     _assert_sync::<Chunk>(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[test] | ||||||
|  | fn test_body_stream_concat() { | ||||||
|  |     use futures::{Sink, Stream, Future}; | ||||||
|  |     let (tx, body) = Body::pair(); | ||||||
|  |  | ||||||
|  |     ::std::thread::spawn(move || { | ||||||
|  |         let tx = tx.send(Ok("hello ".into())).wait().unwrap(); | ||||||
|  |         tx.send(Ok("world".into())).wait().unwrap(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     let total = body.concat().wait().unwrap(); | ||||||
|  |     assert_eq!(total.as_ref(), b"hello world"); | ||||||
|  |  | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,12 +1,41 @@ | |||||||
| use std::fmt; | use std::fmt; | ||||||
|  | use std::mem; | ||||||
|  |  | ||||||
| use bytes::Bytes; | use bytes::{Bytes, BytesMut, BufMut}; | ||||||
|  |  | ||||||
| /// A piece of a message body. | /// A piece of a message body. | ||||||
| pub struct Chunk(Inner); | pub struct Chunk(Inner); | ||||||
|  |  | ||||||
| enum Inner { | enum Inner { | ||||||
|  |     Mut(BytesMut), | ||||||
|     Shared(Bytes), |     Shared(Bytes), | ||||||
|  |     Swapping, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Inner { | ||||||
|  |     fn as_bytes_mut(&mut self, reserve: usize) -> &mut BytesMut { | ||||||
|  |         match *self { | ||||||
|  |             Inner::Mut(ref mut bytes) => return bytes, | ||||||
|  |             _ => () | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let bytes = match mem::replace(self, Inner::Swapping) { | ||||||
|  |             Inner::Shared(bytes) => bytes, | ||||||
|  |             _ => unreachable!(), | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         let bytes_mut = bytes.try_mut().unwrap_or_else(|bytes| { | ||||||
|  |             let mut bytes_mut = BytesMut::with_capacity(reserve + bytes.len()); | ||||||
|  |             bytes_mut.put_slice(bytes.as_ref()); | ||||||
|  |             bytes_mut | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         *self = Inner::Mut(bytes_mut); | ||||||
|  |         match *self { | ||||||
|  |             Inner::Mut(ref mut bytes) => bytes, | ||||||
|  |             _ => unreachable!(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<Vec<u8>> for Chunk { | impl From<Vec<u8>> for Chunk { | ||||||
| @@ -46,7 +75,9 @@ impl From<Bytes> for Chunk { | |||||||
| impl From<Chunk> for Bytes { | impl From<Chunk> for Bytes { | ||||||
|     fn from(chunk: Chunk) -> Bytes { |     fn from(chunk: Chunk) -> Bytes { | ||||||
|         match chunk.0 { |         match chunk.0 { | ||||||
|  |             Inner::Mut(bytes_mut) => bytes_mut.freeze(), | ||||||
|             Inner::Shared(bytes) => bytes, |             Inner::Shared(bytes) => bytes, | ||||||
|  |             Inner::Swapping => unreachable!(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -64,7 +95,9 @@ impl AsRef<[u8]> for Chunk { | |||||||
|     #[inline] |     #[inline] | ||||||
|     fn as_ref(&self) -> &[u8] { |     fn as_ref(&self) -> &[u8] { | ||||||
|         match self.0 { |         match self.0 { | ||||||
|  |             Inner::Mut(ref slice) => slice, | ||||||
|             Inner::Shared(ref slice) => slice, |             Inner::Shared(ref slice) => slice, | ||||||
|  |             Inner::Swapping => unreachable!(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -75,3 +108,24 @@ impl fmt::Debug for Chunk { | |||||||
|         fmt::Debug::fmt(self.as_ref(), f) |         fmt::Debug::fmt(self.as_ref(), f) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl IntoIterator for Chunk { | ||||||
|  |     type Item = u8; | ||||||
|  |     type IntoIter = <Bytes as IntoIterator>::IntoIter; | ||||||
|  |  | ||||||
|  |     fn into_iter(self) -> Self::IntoIter { | ||||||
|  |         match self.0 { | ||||||
|  |             Inner::Mut(bytes) => bytes.freeze().into_iter(), | ||||||
|  |             Inner::Shared(bytes) => bytes.into_iter(), | ||||||
|  |             Inner::Swapping => unreachable!(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Extend<u8> for Chunk { | ||||||
|  |     fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> { | ||||||
|  |         let iter = iter.into_iter(); | ||||||
|  |  | ||||||
|  |         self.0.as_bytes_mut(iter.size_hint().0).extend(iter); | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user