From 7e8373da8d7e4553bbf9793c664fc200f2f61046 Mon Sep 17 00:00:00 2001
From: Sean McArthur <sean.monstar@gmail.com>
Date: Thu, 15 Jun 2017 10:55:02 -0700
Subject: [PATCH] Faster From<[u8]> for BytesMut, remove panic in fmt::Write
 (#133)

* use slice.to_vec instead of buf.put in From<[u8]>

* don't panic in fmt::Write for BytesMut
---
 benches/bytes.rs    | 24 ++++++++++++++++++++++++
 src/bytes.rs        | 15 +++++++++------
 tests/test_bytes.rs | 22 ++++++++++++++++++++++
 3 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/benches/bytes.rs b/benches/bytes.rs
index ff07395..86eb9c4 100644
--- a/benches/bytes.rs
+++ b/benches/bytes.rs
@@ -127,6 +127,30 @@ fn drain_write_drain(b: &mut Bencher) {
     })
 }
 
+#[bench]
+fn fmt_write(b: &mut Bencher) {
+    use std::fmt::Write;
+    let mut buf = BytesMut::with_capacity(128);
+    let s = "foo bar baz quux lorem ipsum dolor et";
+
+    b.bytes = s.len() as u64;
+    b.iter(|| {
+        let _ = write!(buf, "{}", s);
+        test::black_box(&buf);
+        unsafe { buf.set_len(0); }
+    })
+}
+
+#[bench]
+fn from_long_slice(b: &mut Bencher) {
+    let data = [0u8; 128];
+    b.bytes = data.len() as u64;
+    b.iter(|| {
+        let buf = BytesMut::from(&data[..]);
+        test::black_box(buf);
+    })
+}
+
 #[bench]
 fn slice_empty(b: &mut Bencher) {
     b.iter(|| {
diff --git a/src/bytes.rs b/src/bytes.rs
index fd0317d..5945f3d 100644
--- a/src/bytes.rs
+++ b/src/bytes.rs
@@ -1418,10 +1418,7 @@ impl<'a> From<&'a [u8]> for BytesMut {
                 }
             }
         } else {
-            let mut buf = BytesMut::with_capacity(src.len());
-            let src: &[u8] = src.as_ref();
-            buf.put(src);
-            buf
+            BytesMut::from(src.to_vec())
         }
     }
 }
@@ -1487,11 +1484,17 @@ impl Borrow<[u8]> for BytesMut {
 }
 
 impl fmt::Write for BytesMut {
+    #[inline]
     fn write_str(&mut self, s: &str) -> fmt::Result {
-        BufMut::put(self, s);
-        Ok(())
+        if self.remaining_mut() >= s.len() {
+            self.put_slice(s.as_bytes());
+            Ok(())
+        } else {
+            Err(fmt::Error)
+        }
     }
 
+    #[inline]
     fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
         fmt::write(self, args)
     }
diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs
index c8d23d3..b966fe0 100644
--- a/tests/test_bytes.rs
+++ b/tests/test_bytes.rs
@@ -51,6 +51,28 @@ fn fmt() {
     assert_eq!(a, b);
 }
 
+#[test]
+fn fmt_write() {
+    use std::fmt::Write;
+    use std::iter::FromIterator;
+    let s = String::from_iter((0..10).map(|_| "abcdefg"));
+
+    let mut a = BytesMut::with_capacity(64);
+    write!(a, "{}", &s[..64]).unwrap();
+    assert_eq!(a, s[..64].as_bytes());
+
+
+    let mut b = BytesMut::with_capacity(64);
+    write!(b, "{}", &s[..32]).unwrap();
+    write!(b, "{}", &s[32..64]).unwrap();
+    assert_eq!(b, s[..64].as_bytes());
+
+
+    let mut c = BytesMut::with_capacity(64);
+    write!(c, "{}", s).unwrap_err();
+    assert!(c.is_empty());
+}
+
 #[test]
 fn len() {
     let a = Bytes::from(&b"abcdefg"[..]);
-- 
GitLab