diff --git a/src/buf/buf.rs b/src/buf/buf.rs
index ad9f77b512cfb66f2b5b44b69ade25c23fd0635f..73baeeff373d0e9867ee6820a0a4b8435b2c17a7 100644
--- a/src/buf/buf.rs
+++ b/src/buf/buf.rs
@@ -4,6 +4,38 @@ use iovec::IoVec;
 
 use std::{cmp, io, ptr};
 
+macro_rules! buf_get_impl {
+    ($this:ident, $size:expr, $conv:path) => ({
+         // try to convert directly from the bytes
+        let ret = {
+            // this Option<ret> trick is to avoid keeping a borrow on self
+            // when advance() is called (mut borrow) and to call bytes() only once
+            if let Some(src) = $this.bytes().get(..($size)) {
+                Some($conv(src))
+            } else {
+                None
+            }
+        };
+        if let Some(ret) = ret {
+             // if the direct convertion was possible, advance and return
+            $this.advance($size);
+            return ret;
+        } else {
+            // if not we copy the bytes in a temp buffer then convert
+            let mut buf = [0; ($size)];
+            $this.copy_to_slice(&mut buf); // (do the advance)
+            return $conv(&buf);
+        }
+    });
+    ($this:ident, $buf_size:expr, $conv:path, $len_to_read:expr) => ({
+        // The same trick as above does not improve the best case speed.
+        // It seems to be linked to the way the method is optimised by the compiler
+        let mut buf = [0; ($buf_size)];
+        $this.copy_to_slice(&mut buf[..($len_to_read)]);
+        return $conv(&buf[..($len_to_read)], $len_to_read);
+    });
+}
+
 /// Read bytes from a buffer.
 ///
 /// A buffer stores bytes in memory such that read operations are infallible.
@@ -243,9 +275,10 @@ pub trait Buf {
     ///
     /// This function panics if there is no more remaining data in `self`.
     fn get_u8(&mut self) -> u8 {
-        let mut buf = [0; 1];
-        self.copy_to_slice(&mut buf);
-        buf[0]
+        assert!(self.remaining() >= 1);
+        let ret = self.bytes()[0];
+        self.advance(1);
+        ret
     }
 
     /// Gets a signed 8 bit integer from `self`.
@@ -266,9 +299,10 @@ pub trait Buf {
     ///
     /// This function panics if there is no more remaining data in `self`.
     fn get_i8(&mut self) -> i8 {
-        let mut buf = [0; 1];
-        self.copy_to_slice(&mut buf);
-        buf[0] as i8
+        assert!(self.remaining() >= 1);
+        let ret = self.bytes()[0] as i8;
+        self.advance(1);
+        ret
     }
 
     #[doc(hidden)]
@@ -297,9 +331,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u16_be(&mut self) -> u16 {
-        let mut buf = [0; 2];
-        self.copy_to_slice(&mut buf);
-        BigEndian::read_u16(&buf)
+        buf_get_impl!(self, 2, BigEndian::read_u16);
     }
 
     /// Gets an unsigned 16 bit integer from `self` in little-endian byte order.
@@ -320,9 +352,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u16_le(&mut self) -> u16 {
-        let mut buf = [0; 2];
-        self.copy_to_slice(&mut buf);
-        LittleEndian::read_u16(&buf)
+        buf_get_impl!(self, 2, LittleEndian::read_u16);
     }
 
     #[doc(hidden)]
@@ -351,9 +381,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i16_be(&mut self) -> i16 {
-        let mut buf = [0; 2];
-        self.copy_to_slice(&mut buf);
-        BigEndian::read_i16(&buf)
+        buf_get_impl!(self, 2, BigEndian::read_i16);
     }
 
     /// Gets a signed 16 bit integer from `self` in little-endian byte order.
@@ -374,9 +402,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i16_le(&mut self) -> i16 {
-        let mut buf = [0; 2];
-        self.copy_to_slice(&mut buf);
-        LittleEndian::read_i16(&buf)
+        buf_get_impl!(self, 2, LittleEndian::read_i16);
     }
 
     #[doc(hidden)]
@@ -405,9 +431,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u32_be(&mut self) -> u32 {
-        let mut buf = [0; 4];
-        self.copy_to_slice(&mut buf);
-        BigEndian::read_u32(&buf)
+        buf_get_impl!(self, 4, BigEndian::read_u32);
     }
 
     /// Gets an unsigned 32 bit integer from `self` in the little-endian byte order.
@@ -428,9 +452,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u32_le(&mut self) -> u32 {
-        let mut buf = [0; 4];
-        self.copy_to_slice(&mut buf);
-        LittleEndian::read_u32(&buf)
+        buf_get_impl!(self, 4, LittleEndian::read_u32);
     }
 
     #[doc(hidden)]
@@ -459,9 +481,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i32_be(&mut self) -> i32 {
-        let mut buf = [0; 4];
-        self.copy_to_slice(&mut buf);
-        BigEndian::read_i32(&buf)
+        buf_get_impl!(self, 4, BigEndian::read_i32);
     }
 
     /// Gets a signed 32 bit integer from `self` in little-endian byte order.
@@ -482,9 +502,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i32_le(&mut self) -> i32 {
-        let mut buf = [0; 4];
-        self.copy_to_slice(&mut buf);
-        LittleEndian::read_i32(&buf)
+        buf_get_impl!(self, 4, LittleEndian::read_i32);
     }
 
     #[doc(hidden)]
@@ -513,9 +531,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u64_be(&mut self) -> u64 {
-        let mut buf = [0; 8];
-        self.copy_to_slice(&mut buf);
-        BigEndian::read_u64(&buf)
+        buf_get_impl!(self, 8, BigEndian::read_u64);
     }
 
     /// Gets an unsigned 64 bit integer from `self` in little-endian byte order.
@@ -536,9 +552,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u64_le(&mut self) -> u64 {
-        let mut buf = [0; 8];
-        self.copy_to_slice(&mut buf);
-        LittleEndian::read_u64(&buf)
+        buf_get_impl!(self, 8, LittleEndian::read_u64);
     }
 
     #[doc(hidden)]
@@ -567,9 +581,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i64_be(&mut self) -> i64 {
-        let mut buf = [0; 8];
-        self.copy_to_slice(&mut buf);
-        BigEndian::read_i64(&buf)
+        buf_get_impl!(self, 8, BigEndian::read_i64);
     }
 
     /// Gets a signed 64 bit integer from `self` in little-endian byte order.
@@ -590,9 +602,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i64_le(&mut self) -> i64 {
-        let mut buf = [0; 8];
-        self.copy_to_slice(&mut buf);
-        LittleEndian::read_i64(&buf)
+        buf_get_impl!(self, 8, LittleEndian::read_i64);
     }
 
     #[doc(hidden)]
@@ -621,9 +631,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_uint_be(&mut self, nbytes: usize) -> u64 {
-        let mut buf = [0; 8];
-        self.copy_to_slice(&mut buf[..nbytes]);
-        BigEndian::read_uint(&buf[..nbytes], nbytes)
+        buf_get_impl!(self, 8, BigEndian::read_uint, nbytes);
     }
 
     /// Gets an unsigned n-byte integer from `self` in little-endian byte order.
@@ -644,9 +652,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_uint_le(&mut self, nbytes: usize) -> u64 {
-        let mut buf = [0; 8];
-        self.copy_to_slice(&mut buf[..nbytes]);
-        LittleEndian::read_uint(&buf[..nbytes], nbytes)
+        buf_get_impl!(self, 8, LittleEndian::read_uint, nbytes);
     }
 
     #[doc(hidden)]
@@ -675,9 +681,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_int_be(&mut self, nbytes: usize) -> i64 {
-        let mut buf = [0; 8];
-        self.copy_to_slice(&mut buf[..nbytes]);
-        BigEndian::read_int(&buf[..nbytes], nbytes)
+        buf_get_impl!(self, 8, BigEndian::read_int, nbytes);
     }
 
     /// Gets a signed n-byte integer from `self` in little-endian byte order.
@@ -698,9 +702,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_int_le(&mut self, nbytes: usize) -> i64 {
-        let mut buf = [0; 8];
-        self.copy_to_slice(&mut buf[..nbytes]);
-        LittleEndian::read_int(&buf[..nbytes], nbytes)
+        buf_get_impl!(self, 8, LittleEndian::read_int, nbytes);
     }
 
     #[doc(hidden)]
@@ -730,9 +732,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_f32_be(&mut self) -> f32 {
-        let mut buf = [0; 4];
-        self.copy_to_slice(&mut buf);
-        BigEndian::read_f32(&buf)
+        buf_get_impl!(self, 4, BigEndian::read_f32);
     }
 
     /// Gets an IEEE754 single-precision (4 bytes) floating point number from
@@ -754,9 +754,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_f32_le(&mut self) -> f32 {
-        let mut buf = [0; 4];
-        self.copy_to_slice(&mut buf);
-        LittleEndian::read_f32(&buf)
+        buf_get_impl!(self, 4, LittleEndian::read_f32);
     }
 
     #[doc(hidden)]
@@ -786,9 +784,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_f64_be(&mut self) -> f64 {
-        let mut buf = [0; 8];
-        self.copy_to_slice(&mut buf);
-        BigEndian::read_f64(&buf)
+        buf_get_impl!(self, 8, BigEndian::read_f64);
     }
 
     /// Gets an IEEE754 double-precision (8 bytes) floating point number from
@@ -810,9 +806,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_f64_le(&mut self) -> f64 {
-        let mut buf = [0; 8];
-        self.copy_to_slice(&mut buf);
-        LittleEndian::read_f64(&buf)
+        buf_get_impl!(self, 8, LittleEndian::read_f64);
     }
 
     /// Transforms a `Buf` into a concrete buffer.