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.