Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert a buffer of a slice of bytes (&[u8]) to an integer?

I am reading raw data from a file and I want to convert it to an integer:

fn main() {     let buf: &[u8] = &[0, 0, 0, 1];     let num = slice_to_i8(buf);     println!("1 == {}", num); }  pub fn slice_to_i8(buf: &[u8]) -> i32 {     unimplemented!("what should I do here?") } 

I would do a cast in C, but what do I do in Rust?

like image 962
xrl Avatar asked Mar 27 '15 18:03

xrl


People also ask

What is a buffer of bytes?

Like a byte is a group of 8 bits, a buffer is a group of a pre-defined number of bytes. If we have a group of 3 bytes, this could either represent 3 values between 0 and 255, but also one single value between 0 and 16777216 (2563).

What is a slice of byte?

Byte slices are a list of bytes that represent UTF-8 encodings of Unicode code points. Taking the information from above, we could create a byte slice that represents the word “Go”: bs := []byte{71, 111}

What is byte array in Go?

A byte in Go is an unsigned 8-bit integer. It has type uint8 . A byte has a limit of 0 – 255 in numerical range. It can represent an ASCII character.

What is Golang buffer?

In go language, the buffer belongs to the byte package of the Go language, and we can use these package to manipulate the byte of the string. For example, suppose we have a string. We can read the length of the string with the len function, which will return the numeric length, but what if the strings are too large.


2 Answers

I'd suggest using the byteorder crate (which also works in a no-std environment):

use byteorder::{BigEndian, ReadBytesExt}; // 1.2.7  fn main() {     let mut buf: &[u8] = &[0, 0, 0, 1];     let num = buf.read_u32::<BigEndian>().unwrap();      assert_eq!(1, num); } 

This handles oddly-sized slices and automatically advances the buffer so you can read multiple values.

As of Rust 1.32, you can also use the from_le_bytes / from_be_bytes / from_ne_bytes inherent methods on integers:

fn main() {     let buf = [0, 0, 0, 1];     let num = u32::from_be_bytes(buf);      assert_eq!(1, num); } 

These methods only handle fixed-length arrays to avoid dealing with the error when not enough data is present. If you have a slice, you will need to convert it into an array.

See also:

  • How to get a slice as an array in Rust?
  • How to convert a slice into an array reference?
like image 112
Shepmaster Avatar answered Sep 23 '22 06:09

Shepmaster


I'd like to give this answer here to commit the following additional details:

  1. A working code snippet which converts slice to integer (two ways to do it).
  2. A working solution in no_std environment.
  3. To keep everything in one place for the people getting here from the search engine.

Without external crates, the following methods are suitable to convert from slices to integer even for no_std build starting from Rust 1.32:

Method 1 (try_into + from_be_bytes)

use core::convert::TryInto;  let src = [1, 2, 3, 4, 5, 6, 7];  // 0x03040506 u32::from_be_bytes(src[2..6].try_into().unwrap()); 

use core::conver::TryInto is for no_std build. And the way to use the standard crate is the following: use std::convert::TryInto;.

(And about endians it has been already answered, but let me keep it here in one place: from_le_bytes, from_be_bytes, and from_ne_bytes - use them depending on how integer is represented in memory).

Method 2 (clone_from_slice + from_be_bytes)

let src = [1, 2, 3, 4, 5, 6, 7]; let mut dst = [0u8; 4];  dst.clone_from_slice(&src[2..6]);  // 0x03040506 u32::from_be_bytes(dst); 

Result

In both cases integer will be equal to 0x03040506.

like image 28
Alexander Fadeev Avatar answered Sep 25 '22 06:09

Alexander Fadeev