From 4ee2a60d889e7d43fb8abdc7029970cce2414200 Mon Sep 17 00:00:00 2001
From: Nikolay Kim <fafhrd91@gmail.com>
Date: Mon, 23 Oct 2017 23:39:01 -0700
Subject: [PATCH] reuse BinaryBody for Frame::Payload

---
 CHANGES.md     |  4 +++
 src/body.rs    | 93 +++++++++++++++++++++++++++++++-------------------
 src/context.rs |  4 +--
 src/route.rs   |  5 +--
 src/task.rs    |  2 +-
 src/ws.rs      | 18 +++-------
 6 files changed, 73 insertions(+), 53 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 57f4090c..54c66adf 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -7,6 +7,10 @@
 
 * Refactor `RouteRecognizer` usability
 
+* Refactor `HttpContext::write`
+
+* Re-use `BinaryBody` for `Frame::Payload`
+
 
 ## 0.1.0 (2017-10-23)
 
diff --git a/src/body.rs b/src/body.rs
index 0a8b6b7f..adfb533a 100644
--- a/src/body.rs
+++ b/src/body.rs
@@ -1,6 +1,6 @@
 use std::rc::Rc;
 use std::sync::Arc;
-use bytes::Bytes;
+use bytes::{Bytes, BytesMut};
 
 
 /// Represents various types of http message body.
@@ -43,45 +43,15 @@ impl Body {
         }
     }
 
-    /// Create body from static string
+    /// Create body from slice (copy)
     pub fn from_slice<'a>(s: &'a [u8]) -> Body {
         Body::Binary(BinaryBody::Bytes(Bytes::from(s)))
     }
 }
 
-impl From<&'static str> for Body {
-    fn from(s: &'static str) -> Body {
-        Body::Binary(BinaryBody::Slice(s.as_ref()))
-    }
-}
-
-impl From<&'static [u8]> for Body {
-    fn from(s: &'static [u8]) -> Body {
-        Body::Binary(BinaryBody::Slice(s))
-    }
-}
-
-impl From<Vec<u8>> for Body {
-    fn from(vec: Vec<u8>) -> Body {
-        Body::Binary(BinaryBody::Bytes(Bytes::from(vec)))
-    }
-}
-
-impl From<String> for Body {
-    fn from(s: String) -> Body {
-        Body::Binary(BinaryBody::Bytes(Bytes::from(s)))
-    }
-}
-
-impl From<Rc<Bytes>> for Body {
-    fn from(body: Rc<Bytes>) -> Body {
-        Body::Binary(BinaryBody::SharedBytes(body))
-    }
-}
-
-impl From<Arc<Bytes>> for Body {
-    fn from(body: Arc<Bytes>) -> Body {
-        Body::Binary(BinaryBody::ArcSharedBytes(body))
+impl<T> From<T> for Body where T: Into<BinaryBody>{
+    fn from(b: T) -> Body {
+        Body::Binary(b.into())
     }
 }
 
@@ -94,6 +64,59 @@ impl BinaryBody {
             &BinaryBody::ArcSharedBytes(ref bytes) => bytes.len(),
         }
     }
+
+    /// Create binary body from slice
+    pub fn from_slice<'a>(s: &'a [u8]) -> BinaryBody {
+        BinaryBody::Bytes(Bytes::from(s))
+    }
+}
+
+impl From<&'static str> for BinaryBody {
+    fn from(s: &'static str) -> BinaryBody {
+        BinaryBody::Slice(s.as_ref())
+    }
+}
+
+impl From<&'static [u8]> for BinaryBody {
+    fn from(s: &'static [u8]) -> BinaryBody {
+        BinaryBody::Slice(s)
+    }
+}
+
+impl From<Vec<u8>> for BinaryBody {
+    fn from(vec: Vec<u8>) -> BinaryBody {
+        BinaryBody::Bytes(Bytes::from(vec))
+    }
+}
+
+impl From<String> for BinaryBody {
+    fn from(s: String) -> BinaryBody {
+        BinaryBody::Bytes(Bytes::from(s))
+    }
+}
+
+impl From<Bytes> for BinaryBody {
+    fn from(s: Bytes) -> BinaryBody {
+        BinaryBody::Bytes(s)
+    }
+}
+
+impl From<BytesMut> for BinaryBody {
+    fn from(s: BytesMut) -> BinaryBody {
+        BinaryBody::Bytes(s.freeze())
+    }
+}
+
+impl From<Rc<Bytes>> for BinaryBody {
+    fn from(body: Rc<Bytes>) -> BinaryBody {
+        BinaryBody::SharedBytes(body)
+    }
+}
+
+impl From<Arc<Bytes>> for BinaryBody {
+    fn from(body: Arc<Bytes>) -> BinaryBody {
+        BinaryBody::ArcSharedBytes(body)
+    }
 }
 
 impl AsRef<[u8]> for BinaryBody {
diff --git a/src/context.rs b/src/context.rs
index 9172f77e..a2d67227 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -4,13 +4,13 @@ use std::collections::VecDeque;
 use futures::{Async, Stream, Poll};
 use futures::sync::oneshot::Sender;
 
-use bytes::Bytes;
 use actix::{Actor, ActorState, ActorContext, AsyncContext,
             Handler, Subscriber, ResponseType};
 use actix::fut::ActorFuture;
 use actix::dev::{AsyncContextApi, ActorAddressCell, ActorItemsCell, ActorWaitCell, SpawnHandle,
                  Envelope, ToEnvelope, RemoteEnvelope};
 
+use body::BinaryBody;
 use route::{Route, Frame};
 use httpresponse::HttpResponse;
 
@@ -116,7 +116,7 @@ impl<A> HttpContext<A> where A: Actor<Context=Self> + Route {
     }
 
     /// Write payload
-    pub fn write<B: Into<Bytes>>(&mut self, data: B) {
+    pub fn write<B: Into<BinaryBody>>(&mut self, data: B) {
         self.stream.push_back(Frame::Payload(Some(data.into())))
     }
 
diff --git a/src/route.rs b/src/route.rs
index 3a7cc204..f6f4e7bc 100644
--- a/src/route.rs
+++ b/src/route.rs
@@ -3,11 +3,11 @@ use std::rc::Rc;
 use std::marker::PhantomData;
 
 use actix::Actor;
-use bytes::Bytes;
 use http::{header, Version};
 use futures::Stream;
 
 use task::Task;
+use body::BinaryBody;
 use context::HttpContext;
 use resource::Reply;
 use payload::Payload;
@@ -20,9 +20,10 @@ use httpcodes::HTTPExpectationFailed;
 #[cfg_attr(feature="cargo-clippy", allow(large_enum_variant))]
 pub enum Frame {
     Message(HttpResponse),
-    Payload(Option<Bytes>),
+    Payload(Option<BinaryBody>),
 }
 
+
 /// Trait defines object that could be regestered as resource route
 #[allow(unused_variables)]
 pub trait RouteHandler<S>: 'static {
diff --git a/src/task.rs b/src/task.rs
index 29a570ff..7e29cbf5 100644
--- a/src/task.rs
+++ b/src/task.rs
@@ -260,7 +260,7 @@ impl Task {
                             self.encoder.encode(&mut self.buffer, chunk.as_ref());
                         } else {
                             // might be response for EXCEPT
-                            self.buffer.extend(chunk)
+                            self.buffer.extend_from_slice(chunk.as_ref())
                         }
                     },
                     Frame::Payload(None) => {
diff --git a/src/ws.rs b/src/ws.rs
index 345bf1ec..ba3fe59b 100644
--- a/src/ws.rs
+++ b/src/ws.rs
@@ -62,7 +62,7 @@
 //! ```
 use std::vec::Vec;
 use http::{Method, StatusCode, header};
-use bytes::{Bytes, BytesMut};
+use bytes::BytesMut;
 use futures::{Async, Poll, Stream};
 
 use actix::{Actor, ResponseType};
@@ -284,9 +284,7 @@ impl WsWriter {
         let mut buf = Vec::new();
         frame.format(&mut buf).unwrap();
 
-        ctx.write(
-            Bytes::from(buf.as_slice())
-        );
+        ctx.write(buf);
     }
 
     /// Send binary frame
@@ -297,9 +295,7 @@ impl WsWriter {
         let mut buf = Vec::new();
         frame.format(&mut buf).unwrap();
 
-        ctx.write(
-            Bytes::from(buf.as_slice())
-        );
+        ctx.write(buf);
     }
 
     /// Send ping frame
@@ -311,9 +307,7 @@ impl WsWriter {
         let mut buf = Vec::new();
         frame.format(&mut buf).unwrap();
 
-        ctx.write(
-            Bytes::from(buf.as_slice())
-        )
+        ctx.write(buf);
     }
 
     /// Send pong frame
@@ -325,9 +319,7 @@ impl WsWriter {
         let mut buf = Vec::new();
         frame.format(&mut buf).unwrap();
 
-        ctx.write(
-            Bytes::from(buf.as_slice())
-        )
+        ctx.write(buf);
     }
 }