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.
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.
le: Little Endian (most modern computers use this) ne: Native Endian (same as "le" on modern computers) be: Big Endian
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.
from_ne_bytes
, and this will be perform well also.to_ne_bytes()
to go from the u32
we created, back into an array of u8
values (bytes).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]
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.
from_ne_bytes()
on 4 bytes in the vector of bytes. The starting position of the bytes varies based on the loop iteration.transmute_copy()
on 4 bytes in the data. An unsafe code block is needed to call transmute_copy
.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
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
.