Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Buf::get_int() implementation for Bytes returns positive number instead of negative when nbytes < 8. #730

Closed
petriek opened this issue Aug 17, 2024 · 4 comments · Fixed by #732

Comments

@petriek
Copy link

petriek commented Aug 17, 2024

Steps to reproduce:

Run the following program, using bytes version 1.7.1

use bytes::{BytesMut, Buf, BufMut};

fn main() {
    const SOME_NEG_NUMBER: i64 = -42;
    let mut buffer = BytesMut::with_capacity(8);

    buffer.put_int(SOME_NEG_NUMBER, 1);
    println!("buffer = {:?}", &buffer);
    assert_eq!(buffer.freeze().get_int(1), SOME_NEG_NUMBER);
}

Expected outcome:
Assertion passes and program terminates successfully, due to the symmetry of the put_int and get_int calls.

Actual outcome:
Assertion fails:

buffer = b"\xd6"
thread 'main' panicked at src/main.rs:9:5:
assertion `left == right` failed
  left: 214
 right: -42
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Additional information:

  1. Only happens with negative numbers; positive numbers are always OK.
  2. Only happens when nbytes parameter is < 8.
  3. Other combos like put_i8()/get_i8() or put_i16()/get_i16() work as intended.
@paolobarbolini
Copy link
Contributor

paolobarbolini commented Aug 19, 2024

It looks like this has been caused by 234d814 / #280, as demonstrated by the revert:

See the revert
From 4a9b9a4ea0538dff7d9ae57070c98f6ad4afd708 Mon Sep 17 00:00:00 2001
From: Paolo Barbolini <[email protected]>
Date: Mon, 19 Aug 2024 06:08:47 +0200
Subject: [PATCH] Revert "Remove byteorder dependency (#280)"

This reverts commit 234d814122d6445bdfb15f635290bfc4dd36c2eb.
---
 Cargo.toml          |   1 +
 src/buf/buf_impl.rs | 126 ++++++++++++++++++--------------------------
 src/buf/buf_mut.rs  | 119 +++++++++++++++++++++++++----------------
 3 files changed, 127 insertions(+), 119 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index e072539..a49d681 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,6 +24,7 @@ std = []
 
 [dependencies]
 serde = { version = "1.0.60", optional = true, default-features = false, features = ["alloc"] }
+byteorder = "1.3"
 
 [dev-dependencies]
 serde_test = "1.0"
diff --git a/src/buf/buf_impl.rs b/src/buf/buf_impl.rs
index c44d4fb..5817f41 100644
--- a/src/buf/buf_impl.rs
+++ b/src/buf/buf_impl.rs
@@ -1,68 +1,46 @@
 #[cfg(feature = "std")]
 use crate::buf::{reader, Reader};
 use crate::buf::{take, Chain, Take};
+use crate::panic_advance;
 #[cfg(feature = "std")]
 use crate::{min_u64_usize, saturating_sub_usize_u64};
-use crate::{panic_advance, panic_does_not_fit};
 
 #[cfg(feature = "std")]
 use std::io::IoSlice;
 
 use alloc::boxed::Box;
 
-macro_rules! buf_get_impl {
-    ($this:ident, $typ:tt::$conv:tt) => {{
-        const SIZE: usize = core::mem::size_of::<$typ>();
-
-        if $this.remaining() < SIZE {
-            panic_advance(SIZE, $this.remaining());
-        }
+use byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian};
 
+macro_rules! buf_get_impl {
+    ($this:ident, $size:expr, $conv:path) => {{
         // try to convert directly from the bytes
-        // this Option<ret> 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])) });
-
+        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.chunk().get(..($size)) {
+                Some($conv(src))
+            } else {
+                None
+            }
+        };
         if let Some(ret) = ret {
             // if the direct conversion was possible, advance and return
-            $this.advance(SIZE);
+            $this.advance($size);
             return ret;
         } else {
             // if not we copy the bytes in a temp buffer then convert
-            let mut buf = [0; SIZE];
+            let mut buf = [0; ($size)];
             $this.copy_to_slice(&mut buf); // (do the advance)
-            return $typ::$conv(buf);
+            return $conv(&buf);
         }
     }};
-    (le => $this:ident, $typ:tt, $len_to_read:expr) => {{
-        const SIZE: usize = core::mem::size_of::<$typ>();
-
+    ($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; SIZE];
-
-        let subslice = match buf.get_mut(..$len_to_read) {
-            Some(subslice) => subslice,
-            None => panic_does_not_fit(SIZE, $len_to_read),
-        };
-
-        $this.copy_to_slice(subslice);
-        return $typ::from_le_bytes(buf);
-    }};
-    (be => $this:ident, $typ:tt, $len_to_read:expr) => {{
-        const SIZE: usize = core::mem::size_of::<$typ>();
-
-        let slice_at = match SIZE.checked_sub($len_to_read) {
-            Some(slice_at) => slice_at,
-            None => panic_does_not_fit(SIZE, $len_to_read),
-        };
-
-        let mut buf = [0; SIZE];
-        $this.copy_to_slice(&mut buf[slice_at..]);
-        return $typ::from_be_bytes(buf);
+        let mut buf = [0; ($buf_size)];
+        $this.copy_to_slice(&mut buf[..($len_to_read)]);
+        return $conv(&buf[..($len_to_read)], $len_to_read);
     }};
 }
 
@@ -350,7 +328,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u16(&mut self) -> u16 {
-        buf_get_impl!(self, u16::from_be_bytes);
+        buf_get_impl!(self, 2, BigEndian::read_u16);
     }
 
     /// Gets an unsigned 16 bit integer from `self` in little-endian byte order.
@@ -370,7 +348,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u16_le(&mut self) -> u16 {
-        buf_get_impl!(self, u16::from_le_bytes);
+        buf_get_impl!(self, 2, LittleEndian::read_u16);
     }
 
     /// Gets an unsigned 16 bit integer from `self` in native-endian byte order.
@@ -393,7 +371,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u16_ne(&mut self) -> u16 {
-        buf_get_impl!(self, u16::from_ne_bytes);
+        buf_get_impl!(self, 2, NativeEndian::read_u16);
     }
 
     /// Gets a signed 16 bit integer from `self` in big-endian byte order.
@@ -413,7 +391,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i16(&mut self) -> i16 {
-        buf_get_impl!(self, i16::from_be_bytes);
+        buf_get_impl!(self, 2, BigEndian::read_i16);
     }
 
     /// Gets a signed 16 bit integer from `self` in little-endian byte order.
@@ -433,7 +411,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i16_le(&mut self) -> i16 {
-        buf_get_impl!(self, i16::from_le_bytes);
+        buf_get_impl!(self, 2, LittleEndian::read_i16);
     }
 
     /// Gets a signed 16 bit integer from `self` in native-endian byte order.
@@ -456,7 +434,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i16_ne(&mut self) -> i16 {
-        buf_get_impl!(self, i16::from_ne_bytes);
+        buf_get_impl!(self, 2, NativeEndian::read_i16);
     }
 
     /// Gets an unsigned 32 bit integer from `self` in the big-endian byte order.
@@ -476,7 +454,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u32(&mut self) -> u32 {
-        buf_get_impl!(self, u32::from_be_bytes);
+        buf_get_impl!(self, 4, BigEndian::read_u32);
     }
 
     /// Gets an unsigned 32 bit integer from `self` in the little-endian byte order.
@@ -496,7 +474,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u32_le(&mut self) -> u32 {
-        buf_get_impl!(self, u32::from_le_bytes);
+        buf_get_impl!(self, 4, LittleEndian::read_u32);
     }
 
     /// Gets an unsigned 32 bit integer from `self` in native-endian byte order.
@@ -519,7 +497,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u32_ne(&mut self) -> u32 {
-        buf_get_impl!(self, u32::from_ne_bytes);
+        buf_get_impl!(self, 4, NativeEndian::read_u32);
     }
 
     /// Gets a signed 32 bit integer from `self` in big-endian byte order.
@@ -539,7 +517,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i32(&mut self) -> i32 {
-        buf_get_impl!(self, i32::from_be_bytes);
+        buf_get_impl!(self, 4, BigEndian::read_i32);
     }
 
     /// Gets a signed 32 bit integer from `self` in little-endian byte order.
@@ -559,7 +537,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i32_le(&mut self) -> i32 {
-        buf_get_impl!(self, i32::from_le_bytes);
+        buf_get_impl!(self, 4, LittleEndian::read_i32);
     }
 
     /// Gets a signed 32 bit integer from `self` in native-endian byte order.
@@ -582,7 +560,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i32_ne(&mut self) -> i32 {
-        buf_get_impl!(self, i32::from_ne_bytes);
+        buf_get_impl!(self, 4, NativeEndian::read_i32);
     }
 
     /// Gets an unsigned 64 bit integer from `self` in big-endian byte order.
@@ -602,7 +580,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u64(&mut self) -> u64 {
-        buf_get_impl!(self, u64::from_be_bytes);
+        buf_get_impl!(self, 8, BigEndian::read_u64);
     }
 
     /// Gets an unsigned 64 bit integer from `self` in little-endian byte order.
@@ -622,7 +600,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u64_le(&mut self) -> u64 {
-        buf_get_impl!(self, u64::from_le_bytes);
+        buf_get_impl!(self, 8, LittleEndian::read_u64);
     }
 
     /// Gets an unsigned 64 bit integer from `self` in native-endian byte order.
@@ -645,7 +623,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u64_ne(&mut self) -> u64 {
-        buf_get_impl!(self, u64::from_ne_bytes);
+        buf_get_impl!(self, 8, NativeEndian::read_u64);
     }
 
     /// Gets a signed 64 bit integer from `self` in big-endian byte order.
@@ -665,7 +643,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i64(&mut self) -> i64 {
-        buf_get_impl!(self, i64::from_be_bytes);
+        buf_get_impl!(self, 8, BigEndian::read_i64);
     }
 
     /// Gets a signed 64 bit integer from `self` in little-endian byte order.
@@ -685,7 +663,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i64_le(&mut self) -> i64 {
-        buf_get_impl!(self, i64::from_le_bytes);
+        buf_get_impl!(self, 8, LittleEndian::read_i64);
     }
 
     /// Gets a signed 64 bit integer from `self` in native-endian byte order.
@@ -708,7 +686,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i64_ne(&mut self) -> i64 {
-        buf_get_impl!(self, i64::from_ne_bytes);
+        buf_get_impl!(self, 8, NativeEndian::read_i64);
     }
 
     /// Gets an unsigned 128 bit integer from `self` in big-endian byte order.
@@ -728,7 +706,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u128(&mut self) -> u128 {
-        buf_get_impl!(self, u128::from_be_bytes);
+        buf_get_impl!(self, 16, BigEndian::read_u128);
     }
 
     /// Gets an unsigned 128 bit integer from `self` in little-endian byte order.
@@ -748,7 +726,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u128_le(&mut self) -> u128 {
-        buf_get_impl!(self, u128::from_le_bytes);
+        buf_get_impl!(self, 16, LittleEndian::read_u128);
     }
 
     /// Gets an unsigned 128 bit integer from `self` in native-endian byte order.
@@ -771,7 +749,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_u128_ne(&mut self) -> u128 {
-        buf_get_impl!(self, u128::from_ne_bytes);
+        buf_get_impl!(self, 16, NativeEndian::read_u128);
     }
 
     /// Gets a signed 128 bit integer from `self` in big-endian byte order.
@@ -791,7 +769,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i128(&mut self) -> i128 {
-        buf_get_impl!(self, i128::from_be_bytes);
+        buf_get_impl!(self, 16, BigEndian::read_i128);
     }
 
     /// Gets a signed 128 bit integer from `self` in little-endian byte order.
@@ -811,7 +789,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i128_le(&mut self) -> i128 {
-        buf_get_impl!(self, i128::from_le_bytes);
+        buf_get_impl!(self, 16, LittleEndian::read_i128);
     }
 
     /// Gets a signed 128 bit integer from `self` in native-endian byte order.
@@ -834,7 +812,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_i128_ne(&mut self) -> i128 {
-        buf_get_impl!(self, i128::from_ne_bytes);
+        buf_get_impl!(self, 16, NativeEndian::read_i128);
     }
 
     /// Gets an unsigned n-byte integer from `self` in big-endian byte order.
@@ -854,7 +832,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_uint(&mut self, nbytes: usize) -> u64 {
-        buf_get_impl!(be => self, u64, nbytes);
+        buf_get_impl!(self, 8, BigEndian::read_uint, nbytes);
     }
 
     /// Gets an unsigned n-byte integer from `self` in little-endian byte order.
@@ -874,7 +852,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 {
-        buf_get_impl!(le => self, u64, nbytes);
+        buf_get_impl!(self, 8, LittleEndian::read_uint, nbytes);
     }
 
     /// Gets an unsigned n-byte integer from `self` in native-endian byte order.
@@ -923,7 +901,7 @@ pub trait Buf {
     /// This function panics if there is not enough remaining data in `self`, or
     /// if `nbytes` is greater than 8.
     fn get_int(&mut self, nbytes: usize) -> i64 {
-        buf_get_impl!(be => self, i64, nbytes);
+        buf_get_impl!(self, 8, BigEndian::read_int, nbytes);
     }
 
     /// Gets a signed n-byte integer from `self` in little-endian byte order.
@@ -944,7 +922,7 @@ pub trait Buf {
     /// This function panics if there is not enough remaining data in `self`, or
     /// if `nbytes` is greater than 8.
     fn get_int_le(&mut self, nbytes: usize) -> i64 {
-        buf_get_impl!(le => self, i64, nbytes);
+        buf_get_impl!(self, 8, LittleEndian::read_int, nbytes);
     }
 
     /// Gets a signed n-byte integer from `self` in native-endian byte order.
@@ -993,7 +971,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_f32(&mut self) -> f32 {
-        f32::from_bits(self.get_u32())
+        buf_get_impl!(self, 4, BigEndian::read_f32);
     }
 
     /// Gets an IEEE754 single-precision (4 bytes) floating point number from
@@ -1038,7 +1016,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_f32_ne(&mut self) -> f32 {
-        f32::from_bits(self.get_u32_ne())
+        buf_get_impl!(self, 4, LittleEndian::read_f32);
     }
 
     /// Gets an IEEE754 double-precision (8 bytes) floating point number from
@@ -1059,7 +1037,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_f64(&mut self) -> f64 {
-        f64::from_bits(self.get_u64())
+        buf_get_impl!(self, 8, BigEndian::read_f64);
     }
 
     /// Gets an IEEE754 double-precision (8 bytes) floating point number from
@@ -1080,7 +1058,7 @@ pub trait Buf {
     ///
     /// This function panics if there is not enough remaining data in `self`.
     fn get_f64_le(&mut self) -> f64 {
-        f64::from_bits(self.get_u64_le())
+        buf_get_impl!(self, 8, LittleEndian::read_f64);
     }
 
     /// Gets an IEEE754 double-precision (8 bytes) floating point number from
diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs
index e13278d..73baa1e 100644
--- a/src/buf/buf_mut.rs
+++ b/src/buf/buf_mut.rs
@@ -3,9 +3,10 @@ use crate::buf::{limit, Chain, Limit, UninitSlice};
 use crate::buf::{writer, Writer};
 use crate::{panic_advance, panic_does_not_fit};
 
-use core::{mem, ptr, usize};
+use core::{ptr, usize};
 
 use alloc::{boxed::Box, vec::Vec};
+use byteorder::{BigEndian, ByteOrder, LittleEndian};
 
 /// A trait for values that provide sequential write access to bytes.
 ///
@@ -367,7 +368,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_u16(&mut self, n: u16) {
-        self.put_slice(&n.to_be_bytes())
+        let mut buf = [0; 2];
+        BigEndian::write_u16(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes an unsigned 16 bit integer to `self` in little-endian byte order.
@@ -390,7 +393,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_u16_le(&mut self, n: u16) {
-        self.put_slice(&n.to_le_bytes())
+        let mut buf = [0; 2];
+        LittleEndian::write_u16(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes an unsigned 16 bit integer to `self` in native-endian byte order.
@@ -440,7 +445,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_i16(&mut self, n: i16) {
-        self.put_slice(&n.to_be_bytes())
+        let mut buf = [0; 2];
+        BigEndian::write_i16(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes a signed 16 bit integer to `self` in little-endian byte order.
@@ -463,7 +470,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_i16_le(&mut self, n: i16) {
-        self.put_slice(&n.to_le_bytes())
+        let mut buf = [0; 2];
+        LittleEndian::write_i16(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes a signed 16 bit integer to `self` in native-endian byte order.
@@ -513,7 +522,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_u32(&mut self, n: u32) {
-        self.put_slice(&n.to_be_bytes())
+        let mut buf = [0; 4];
+        BigEndian::write_u32(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes an unsigned 32 bit integer to `self` in little-endian byte order.
@@ -536,7 +547,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_u32_le(&mut self, n: u32) {
-        self.put_slice(&n.to_le_bytes())
+        let mut buf = [0; 4];
+        LittleEndian::write_u32(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes an unsigned 32 bit integer to `self` in native-endian byte order.
@@ -586,7 +599,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_i32(&mut self, n: i32) {
-        self.put_slice(&n.to_be_bytes())
+        let mut buf = [0; 4];
+        BigEndian::write_i32(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes a signed 32 bit integer to `self` in little-endian byte order.
@@ -609,7 +624,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_i32_le(&mut self, n: i32) {
-        self.put_slice(&n.to_le_bytes())
+        let mut buf = [0; 4];
+        LittleEndian::write_i32(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes a signed 32 bit integer to `self` in native-endian byte order.
@@ -659,7 +676,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_u64(&mut self, n: u64) {
-        self.put_slice(&n.to_be_bytes())
+        let mut buf = [0; 8];
+        BigEndian::write_u64(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes an unsigned 64 bit integer to `self` in little-endian byte order.
@@ -682,7 +701,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_u64_le(&mut self, n: u64) {
-        self.put_slice(&n.to_le_bytes())
+        let mut buf = [0; 8];
+        LittleEndian::write_u64(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes an unsigned 64 bit integer to `self` in native-endian byte order.
@@ -732,7 +753,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_i64(&mut self, n: i64) {
-        self.put_slice(&n.to_be_bytes())
+        let mut buf = [0; 8];
+        BigEndian::write_i64(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes a signed 64 bit integer to `self` in little-endian byte order.
@@ -755,7 +778,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_i64_le(&mut self, n: i64) {
-        self.put_slice(&n.to_le_bytes())
+        let mut buf = [0; 8];
+        LittleEndian::write_i64(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes a signed 64 bit integer to `self` in native-endian byte order.
@@ -805,7 +830,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_u128(&mut self, n: u128) {
-        self.put_slice(&n.to_be_bytes())
+        let mut buf = [0; 16];
+        BigEndian::write_u128(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes an unsigned 128 bit integer to `self` in little-endian byte order.
@@ -828,7 +855,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_u128_le(&mut self, n: u128) {
-        self.put_slice(&n.to_le_bytes())
+        let mut buf = [0; 16];
+        LittleEndian::write_u128(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes an unsigned 128 bit integer to `self` in native-endian byte order.
@@ -878,7 +907,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_i128(&mut self, n: i128) {
-        self.put_slice(&n.to_be_bytes())
+        let mut buf = [0; 16];
+        BigEndian::write_i128(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes a signed 128 bit integer to `self` in little-endian byte order.
@@ -901,7 +932,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_i128_le(&mut self, n: i128) {
-        self.put_slice(&n.to_le_bytes())
+        let mut buf = [0; 16];
+        LittleEndian::write_i128(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes a signed 128 bit integer to `self` in native-endian byte order.
@@ -951,12 +984,9 @@ pub unsafe trait BufMut {
     /// `self` or if `nbytes` is greater than 8.
     #[inline]
     fn put_uint(&mut self, n: u64, nbytes: usize) {
-        let start = match mem::size_of_val(&n).checked_sub(nbytes) {
-            Some(start) => start,
-            None => panic_does_not_fit(nbytes, mem::size_of_val(&n)),
-        };
-
-        self.put_slice(&n.to_be_bytes()[start..]);
+        let mut buf = [0; 8];
+        BigEndian::write_uint(&mut buf, n, nbytes);
+        self.put_slice(&buf[0..nbytes])
     }
 
     /// Writes an unsigned n-byte integer to `self` in the little-endian byte order.
@@ -979,13 +1009,9 @@ pub unsafe trait BufMut {
     /// `self` or if `nbytes` is greater than 8.
     #[inline]
     fn put_uint_le(&mut self, n: u64, nbytes: usize) {
-        let slice = n.to_le_bytes();
-        let slice = match slice.get(..nbytes) {
-            Some(slice) => slice,
-            None => panic_does_not_fit(nbytes, slice.len()),
-        };
-
-        self.put_slice(slice);
+        let mut buf = [0; 8];
+        LittleEndian::write_uint(&mut buf, n, nbytes);
+        self.put_slice(&buf[0..nbytes])
     }
 
     /// Writes an unsigned n-byte integer to `self` in the native-endian byte order.
@@ -1039,12 +1065,9 @@ pub unsafe trait BufMut {
     /// `self` or if `nbytes` is greater than 8.
     #[inline]
     fn put_int(&mut self, n: i64, nbytes: usize) {
-        let start = match mem::size_of_val(&n).checked_sub(nbytes) {
-            Some(start) => start,
-            None => panic_does_not_fit(nbytes, mem::size_of_val(&n)),
-        };
-
-        self.put_slice(&n.to_be_bytes()[start..]);
+        let mut buf = [0; 8];
+        BigEndian::write_int(&mut buf, n, nbytes);
+        self.put_slice(&buf[0..nbytes])
     }
 
     /// Writes low `nbytes` of a signed integer to `self` in little-endian byte order.
@@ -1100,11 +1123,9 @@ pub unsafe trait BufMut {
     /// `self` or if `nbytes` is greater than 8.
     #[inline]
     fn put_int_ne(&mut self, n: i64, nbytes: usize) {
-        if cfg!(target_endian = "big") {
-            self.put_int(n, nbytes)
-        } else {
-            self.put_int_le(n, nbytes)
-        }
+        let mut buf = [0; 8];
+        LittleEndian::write_int(&mut buf, n, nbytes);
+        self.put_slice(&buf[0..nbytes])
     }
 
     /// Writes  an IEEE754 single-precision (4 bytes) floating point number to
@@ -1128,7 +1149,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_f32(&mut self, n: f32) {
-        self.put_u32(n.to_bits());
+        let mut buf = [0; 4];
+        BigEndian::write_f32(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes  an IEEE754 single-precision (4 bytes) floating point number to
@@ -1152,7 +1175,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_f32_le(&mut self, n: f32) {
-        self.put_u32_le(n.to_bits());
+        let mut buf = [0; 4];
+        LittleEndian::write_f32(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes an IEEE754 single-precision (4 bytes) floating point number to
@@ -1204,7 +1229,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_f64(&mut self, n: f64) {
-        self.put_u64(n.to_bits());
+        let mut buf = [0; 8];
+        BigEndian::write_f64(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes  an IEEE754 double-precision (8 bytes) floating point number to
@@ -1228,7 +1255,9 @@ pub unsafe trait BufMut {
     /// `self`.
     #[inline]
     fn put_f64_le(&mut self, n: f64) {
-        self.put_u64_le(n.to_bits());
+        let mut buf = [0; 8];
+        LittleEndian::write_f64(&mut buf, n);
+        self.put_slice(&buf)
     }
 
     /// Writes  an IEEE754 double-precision (8 bytes) floating point number to
-- 
2.46.0

@Darksonn
Copy link
Contributor

Thank you, we should fix this. Anyone willing to submit a PR?

@paolobarbolini
Copy link
Contributor

I'm looking into it

@paolobarbolini
Copy link
Contributor

Should be fixed in #732

paolobarbolini added a commit to paolobarbolini/bytes that referenced this issue Aug 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants