diff --git a/src/bytes.rs b/src/bytes.rs
index ef3f69f83d09eba40516c840666a9eace0d954c2..963fdb8135f55de811aa11f304308f5cce21e758 100644
--- a/src/bytes.rs
+++ b/src/bytes.rs
@@ -1,5 +1,5 @@
 use {Buf, ByteStr, ByteBuf, SmallByteStr};
-use std::{mem, ops, ptr};
+use std::{fmt, mem, ops, ptr};
 use std::any::{Any, TypeId};
 use std::raw::TraitObject;
 use core::nonzero::NonZero;
@@ -165,6 +165,12 @@ impl ops::Index<usize> for Bytes {
     }
 }
 
+impl fmt::Debug for Bytes {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        super::debug(self, "Bytes", fmt)
+    }
+}
+
 impl Clone for Bytes {
     fn clone(&self) -> Bytes {
         self.obj().clone()
diff --git a/src/lib.rs b/src/lib.rs
index 8d47884b31b1c767f805f73f66cf35a9f8e95112..d516a75d95ff3b3c229106626509599114f51ce5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -455,3 +455,43 @@ pub enum BufError {
     Underflow,
     Overflow,
 }
+
+/*
+ *
+ * ===== Internal utilities =====
+ *
+ */
+
+fn debug<B: ByteStr>(bytes: &B, name: &str, fmt: &mut fmt::Formatter) -> fmt::Result {
+    let mut buf = bytes.buf();
+
+    try!(write!(fmt, "{}[len={}; ", name, bytes.len()));
+
+    let mut rem = 128;
+
+    while let Some(byte) = buf.read_byte() {
+        if rem > 0 {
+            if is_ascii(byte) {
+                try!(write!(fmt, "{}", byte as char));
+            } else {
+                try!(write!(fmt, "\\x{:02X}", byte));
+            }
+
+            rem -= 1;
+        } else {
+            try!(write!(fmt, " ... "));
+            break;
+        }
+    }
+
+    try!(write!(fmt, "]"));
+
+    Ok(())
+}
+
+fn is_ascii(byte: u8) -> bool {
+    match byte {
+        10 | 13 | 32...126 => true,
+        _ => false,
+    }
+}
diff --git a/test/test.rs b/test/test.rs
index a9bf0eaa0b6a48bd82692804d15749761c746a23..1e7670e9505e6f7f503df09a89b4a7c2f9a1d40a 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -6,6 +6,7 @@ extern crate bytes;
 extern crate rand;
 
 mod test_byte_buf;
+mod test_bytes;
 mod test_rope;
 mod test_seq_byte_str;
 mod test_small_byte_str;
diff --git a/test/test_bytes.rs b/test/test_bytes.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cb7873b49babb389fd8df1c6b8bf94f88e601a19
--- /dev/null
+++ b/test/test_bytes.rs
@@ -0,0 +1,42 @@
+use bytes::*;
+
+#[test]
+pub fn test_debug_short_str_valid_ascii() {
+    let b = Bytes::from_slice(b"abcdefghij234");
+    let d = format!("{:?}", b);
+
+    assert_eq!(d.as_slice(), "Bytes[len=13; abcdefghij234]");
+}
+
+#[test]
+pub fn test_debug_long_str_valid_ascii() {
+    let s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. \
+             Duis volutpat eros in gravida malesuada. Phasellus lobortis \
+             maximus cursus. Praesent tristique orci non purus porta \
+             dapibus. Ut ut commodo risus, sed semper felis. Phasellus \
+             bibendum dui nunc, ac pharetra dui viverra a. Nunc imperdiet \
+             sed nulla ut condimentum. In hac habitasse platea dictumst. \
+             Interdum et malesuada fames ac ante ipsum primis in faucibus. \
+             Sed facilisis dictum malesuada. Sed tempor odio ullamcorper mi \
+             iaculis, eu tempus diam semper. Vivamus pulvinar metus ac erat \
+             aliquet aliquam.";
+
+    let b = Bytes::from_slice(s.as_bytes());
+
+    let d = format!("{:?}", b);
+
+    assert_eq!(d.as_slice(), "Bytes[len=556; Lorem ipsum dolor sit amet, \
+                              consectetur adipiscing elit. Duis volutpat \
+                              eros in gravida malesuada. Phasellus \
+                              lobortis maximus cur ... ]");
+}
+
+#[test]
+pub fn test_short_string_invalid_ascii() {
+    let b = Bytes::from_slice(b"foo\x00bar\xFFbaz");
+    let d = format!("{:?}", b);
+
+    println!("{:?}", b);
+
+    assert_eq!(d.as_slice(), "Bytes[len=11; foo\\x00bar\\xFFbaz]");
+}