Rust Convert Bytes to IntegerGet u8 values from a vector and convert them into a u32 integer. Use from_ne_bytes and transmute_copy.
From_ne_bytes. In Rust we have standard library functions to convert from bytes to integers and back again. The from_le_bytes, from_ne_bytes and from_be_bytes functions can be used.
To convert from an integer back into an array of bytes, we can use functions like to_ne_bytes. The correct Endianness must be selected.
Endianness note. What do the "le," "ne" and "be" terms mean in these functions? The second letter E refers to Endianness—this is the order bytes are represented in compute memory.
Tip If we do not care about other systems, the "ne" functions can be used for the system's native Endianness.
Endian table:
le: Little Endian (most modern computers use this) ne: Native Endian (same as "le" on modern computers) be: Big Endian
First example. Here we have a vector of 8 bytes. We call from_ne_bytes on a slice of the first 4 bytes. We use try_into and unwrap() to convert the slice into array so from_ne_bytes can be called.
Tip You can create an array on the stack, and pass that to from_ne_bytes, and this will be perform well also.
Result We call to_ne_bytes() to go from the u32 we created, back into an array of u8 values (bytes).
And We successfully round-tripped 4 bytes—this logic could be used to persist byte data in a file and read it back again as u32 values.
fn main() { // The raw data. let data: Vec<u8> = vec![1, 2, 3, 4, 10, 11, 12, 13]; println!("Data: {:?}", data); // Convert first 4 bytes into a u32. let first = u32::from_ne_bytes(data[0..4].try_into().unwrap()); println!("First: {}", first); // Convert back into u32. let original = u32::to_ne_bytes(first); println!("Original: {:?}", original); }
Data: [1, 2, 3, 4, 10, 11, 12, 13] First: 67305985 Original: [1, 2, 3, 4]
Benchmark, transmute_copy. Another function we can use in Rust is called transmute_copy—this directly casts byte data into a structure. Transmute_copy() is unsafe and should be avoided.
Version 1 We call from_ne_bytes() on 4 bytes in the vector of bytes. The starting position of the bytes varies based on the loop iteration.
Version 2 We call transmute_copy() on 4 bytes in the data. An unsafe code block is needed to call transmute_copy.
transmute copy
Result Both functions are fast, but transmute_copy() appears to be measurably faster in the Rust 2021 edition.
use std::time::*; use std::mem; fn main() { if let Ok(max) = "200000000".parse() { let data: Vec<u8> = vec![10, 0, 20, 0, 30, 0, 40, 0, 50, 0]; // Version 1: use from_ne_bytes. let t0 = Instant::now(); let mut count = 0; for i in 0..max { let start = i % 4; let first = u32::from_ne_bytes(data[start..start+4].try_into().unwrap()); if first == 0 { count += 1; } } println!("{} ms", t0.elapsed().as_millis()); // Version 2: use transmute_copy. let t0 = Instant::now(); for i in 0..max { unsafe { let start = i % 4; let first = mem::transmute_copy::<[u8; 4], u32>(data[start..start+4].try_into().unwrap()); if first == 0 { count += 1; } } } println!("{} ms", t0.elapsed().as_millis()); println!("{}", count); } }
83 ms from_ne_bytes 62 ms transmute_copy 0
A summary. With functions like from_ne_bytes() and to_ne_bytes() we can convert back and forth from bytes and integers. These functions are available on types like u32 and i32.
© 2007-2022 sam allen.
see site info on the changelog.