53

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?

4 Answers 4

66

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:

Sign up to request clarification or add additional context in comments.

10 Comments

You can also use BigEndian::read_i32(&bytes[..]), if you're only reading a single item.
What if buf is a vec<8>?
@user2284570 you don't have to do anything special for a Vec<u8>. See also How do I get a slice of a Vec<T> in Rust?. You have to care about the endianness of the data. It's the difference between 12345 and 54321. So long as both the writer and the reader agree on the endianness of the data, you are fine. If you are writing it, then pick one and use it consistently. Most people would pick little endian, probably.
@Shepmaster it s rather that I need to preserve the existing byte ordering and that the code will run on cpu supportting unaligned memory access. So how to do the same without from_be_bytes since it seems there s no from_ptr() function? It also seems Vec has no read_u32.
|
30

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.

7 Comments

This doesn't really add anything to the existing answer, which already discusses from_le_bytes / from_be_bytes / from_ne_bytes and links to a question showing how to get fixed-size arrays from slices.
@Shepmaster Sad you think so. I don't really agree because I collected all this info across all stackoverflow answers and decided to put it here for convenience. In this answer I add a couple of points: 1. What to do in no_std environment. 2. What to do with slices as original question stated (without jumping to links). 3. What to do without byteorder.
byteorder works in a no-std environment, clicking links isn't a burden on the internet, the existing answer talks about avoiding byteorder.
@Shepmaster By the way, I didn't notice that this is your answer/question party. ;) But you should know that "See also" note is not really noticeable in your answer, also it is pretty confusing to see a code snippet about how to convert array to integer in your answer instead of converting a slice to integer. You may think differently, I just tell how it looks like. Anyways you just can improve your own answer, right? (P.S.: "clicking links isn't a burden on the internet" - this is your subjective point of view which differs from mine)
As a novice, I really appreciated this answer because it showed how to read from the middle of a slice
|
0

This custom serialize_deserialize_u8_i32 library will safely convert back and forth between u8 array and i32 array i.e. the serialise function will take all of your u8 values and pack them into i32 values and the deserialise function will take this library’s custom i32 values and convert them back to the original u8 values that you started with.

This was built for a specific purpose, however it may come in handy for other uses; depending on whether you want/need a fast/custom converter like this.

https://github.com/second-state/serialize_deserialize_u8_i32

Comments

0

Here’s my implementation (for a different use case) that discards any additional bytes beyond 8 (and therefore doesn’t need to panic if not exact):

pub fn u64_from_slice(slice: &[u8]) -> u64 {
    u64::from_ne_bytes(slice.split_at(8).0.try_into().unwrap())
}

The split_at() method returns a tuple of two slices: one from index 0 until the specified index and the other from the specified index until the end. So by using .0 to access the first member of the tuple returned by .split_at(8), it ensures that only the first 8 bytes are passed to u64::to_ne_bytes(), discarding the leftovers. Then, of course, it calls the try_into method on that .0 tuple member, and .unwrap() since split_at does all the custom panicking for you.

1 Comment

I'd suggest slice[..8] instead of slice.split_at(8).0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.