diff --git a/src/buf/mod.rs b/src/buf/mod.rs
index 07de5f8b772237fb882e1fcd9662152171df6510..2498b195f5c68b3dd5a32df9f9385e5eae269e6b 100644
--- a/src/buf/mod.rs
+++ b/src/buf/mod.rs
@@ -3,10 +3,12 @@ mod ring;
 mod sink;
 mod slice;
 mod source;
+mod take;
 
 pub use self::byte::{ByteBuf, MutByteBuf, ROByteBuf};
 pub use self::ring::RingBuf;
 pub use self::slice::{SliceBuf, MutSliceBuf};
+pub use self::take::Take;
 
 use {BufError, RopeBuf};
 use std::{cmp, fmt, io, ptr, usize};
diff --git a/src/buf/take.rs b/src/buf/take.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9995152871e43971e05f8be5fa74c79c96c9148e
--- /dev/null
+++ b/src/buf/take.rs
@@ -0,0 +1,79 @@
+use buf::{Buf, MutBuf};
+use std::{cmp, io};
+
+#[derive(Debug)]
+pub struct Take<T> {
+    inner: T,
+    limit: usize,
+}
+
+impl<T> Take<T> {
+    pub fn new(inner: T, limit: usize) -> Take<T> {
+        Take {
+            inner: inner,
+            limit: limit,
+        }
+    }
+
+    pub fn into_inner(self) -> T {
+        self.inner
+    }
+
+    pub fn get_ref(&self) -> &T {
+        &self.inner
+    }
+
+    pub fn get_mut(&mut self) -> &mut T {
+        &mut self.inner
+    }
+
+    pub fn limit(&self) -> usize {
+        self.limit
+    }
+
+    pub fn set_limit(&mut self, lim: usize) {
+        self.limit = lim
+    }
+}
+
+impl<T: Buf> Buf for Take<T> {
+    fn remaining(&self) -> usize {
+        cmp::min(self.inner.remaining(), self.limit)
+    }
+
+    fn bytes<'a>(&'a self) -> &'a [u8] {
+        &self.inner.bytes()[..self.limit]
+    }
+
+    fn advance(&mut self, cnt: usize) {
+        let cnt = cmp::min(cnt, self.limit);
+        self.limit -= cnt;
+        self.inner.advance(cnt);
+    }
+}
+
+impl<T: Buf> io::Read for Take<T> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        if !self.has_remaining() {
+            return Ok(0);
+        }
+
+        Ok(self.read_slice(buf))
+    }
+}
+
+impl<T: MutBuf> MutBuf for Take<T> {
+    fn remaining(&self) -> usize {
+        cmp::min(self.inner.remaining(), self.limit)
+    }
+
+    fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
+        &mut self.inner.mut_bytes()[..self.limit]
+    }
+
+    fn advance(&mut self, cnt: usize) {
+        let cnt = cmp::min(cnt, self.limit);
+        self.limit -= cnt;
+        self.inner.advance(cnt);
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 42a9eab41bbc45e2ccd25f781768729b8ada2246..820f49bf9b675a386c85d06a9696b57a4bc9176d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -17,7 +17,8 @@ pub use buf::{
     SliceBuf,
     MutSliceBuf,
     Source,
-    Sink
+    Sink,
+    Take,
 };
 pub use str::{
     ByteStr,
diff --git a/test/test.rs b/test/test.rs
index 283685f1d691564cc34c16de205cdcfcbcab7bda..77fcd57f74ea68ef6b94ed1cb11c5ab51c857924 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -5,6 +5,7 @@ extern crate rand;
 
 mod test_buf;
 mod test_buf_fill;
+mod test_buf_take;
 mod test_byte_buf;
 mod test_bytes;
 mod test_ring;
diff --git a/test/test_buf_take.rs b/test/test_buf_take.rs
new file mode 100644
index 0000000000000000000000000000000000000000..b2300c11c0e300abd6d7a7f3d2cba99522f62580
--- /dev/null
+++ b/test/test_buf_take.rs
@@ -0,0 +1,12 @@
+use bytes::*;
+use std::io::{Cursor, Read};
+
+#[test]
+pub fn test_take_from_buf() {
+    let mut buf = Take::new(Cursor::new(b"hello world".to_vec()), 5);
+    let mut res = vec![];
+
+    buf.read_to_end(&mut res);
+
+    assert_eq!(&res, b"hello");
+}