From f54e65ee114ffe3b11f78da1fcddc6b00ab81971 Mon Sep 17 00:00:00 2001 From: Liam Perlaki Date: Mon, 24 Mar 2025 12:57:01 +0100 Subject: [PATCH 1/2] add get_array to Buf --- Cargo.toml | 2 +- src/buf/buf_impl.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7ef12eafc..b5f29f650 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ name = "bytes" # - Create "v1.x.y" git tag. version = "1.10.1" edition = "2018" -rust-version = "1.39" +rust-version = "1.51" license = "MIT" authors = [ "Carl Lerche ", diff --git a/src/buf/buf_impl.rs b/src/buf/buf_impl.rs index 192034fbe..c7b8b31c5 100644 --- a/src/buf/buf_impl.rs +++ b/src/buf/buf_impl.rs @@ -296,6 +296,30 @@ pub trait Buf { .unwrap_or_else(|error| panic_advance(&error)); } + /// Gets a const known number of bytes from `self` + /// + /// The current position is advanced by `N`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"hello world"[..]; + /// assert_eq!(*b"hello", buf.get_array::<5>()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_array(&mut self) -> [u8; N] + where + Self: Sized, + { + self.try_get_array() + .unwrap_or_else(|error| panic_advance(&error)) + } + /// Gets an unsigned 8 bit integer from `self`. /// /// The current position is advanced by 1. @@ -1178,6 +1202,61 @@ pub trait Buf { Ok(()) } + /// Gets a const known number of bytes from `self` + /// + /// The current position is advanced by `N`. + /// + /// Returns `Err(TryGetError)` when there are not enough + /// remaining bytes to read the value. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"hello world"[..]; + /// assert_eq!(Ok(*b"hello"), buf.try_get_array::<5>()); + /// assert_eq!(6, buf.remaining()); + /// ``` + /// ``` + /// use bytes::{Buf, TryGetError}; + /// + /// let mut buf = &b"hel"[..]; + /// assert_eq!(Err(TryGetError{requested: 5, available: 3}), buf.try_get_array::<5>()); + /// assert_eq!(3, buf.remaining()); + /// ``` + /// + fn try_get_array(&mut self) -> Result<[u8; N], TryGetError> + where + Self: Sized, + { + if self.remaining() < N { + return Err(TryGetError { + requested: N, + available: self.remaining(), + }); + } + + // try to convert directly from the bytes + // this Option trick is to avoid keeping a borrow on self + // when advance() is called (mut borrow) and to call bytes() only once + let ret = self + .chunk() + .get(..N) + .map(|src| unsafe { *(src as *const _ as *const [_; N]) }); + + if let Some(ret) = ret { + // if the direct conversion was possible, advance and return + self.advance(N); + return Ok(ret); + } else { + // if not we copy the bytes in a temp buffer then convert + let mut buf = [0; N]; + self.copy_to_slice(&mut buf); // (do the advance) + return Ok(buf); + } + } + /// Gets an unsigned 8 bit integer from `self`. /// /// The current position is advanced by 1. From 79e06c6211c5e3e1d2f6757e7b75b625af00d10a Mon Sep 17 00:00:00 2001 From: Liam Perlaki Date: Mon, 24 Mar 2025 13:16:39 +0100 Subject: [PATCH 2/2] implement buf_try_get_impl with try_get_array --- src/buf/buf_impl.rs | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/buf/buf_impl.rs b/src/buf/buf_impl.rs index c7b8b31c5..228fc2d97 100644 --- a/src/buf/buf_impl.rs +++ b/src/buf/buf_impl.rs @@ -12,33 +12,9 @@ use alloc::boxed::Box; macro_rules! buf_try_get_impl { ($this:ident, $typ:tt::$conv:tt) => {{ - const SIZE: usize = core::mem::size_of::<$typ>(); - - if $this.remaining() < SIZE { - return Err(TryGetError { - requested: SIZE, - available: $this.remaining(), - }); - } - - // try to convert directly from the bytes - // this Option trick is to avoid keeping a borrow on self - // when advance() is called (mut borrow) and to call bytes() only once - let ret = $this - .chunk() - .get(..SIZE) - .map(|src| unsafe { $typ::$conv(*(src as *const _ as *const [_; SIZE])) }); - - if let Some(ret) = ret { - // if the direct conversion was possible, advance and return - $this.advance(SIZE); - return Ok(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 Ok($typ::$conv(buf)); - } + // add indirection so self doesnot need to bee sized + let mut this = $this; + (&mut this).try_get_array().map($typ::$conv) }}; (le => $this:ident, $typ:tt, $len_to_read:expr) => {{ const SIZE: usize = core::mem::size_of::<$typ>(); @@ -1226,6 +1202,7 @@ pub trait Buf { /// assert_eq!(3, buf.remaining()); /// ``` /// + #[inline] // inline for better performance of buf_try_get_impl methods fn try_get_array(&mut self) -> Result<[u8; N], TryGetError> where Self: Sized,