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?
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:
I'd like to give this answer here to commit the following additional details:
no_std
environment. Without external crates, the following methods are suitable to convert from slices to integer even for no_std
build starting from Rust 1.32:
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).
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);
In both cases integer will be equal to 0x03040506
.
This custom serialize_deserialize_u8_i32 library will safely convert back and forth between u8 array and i32 array ie 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
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.