17

And convert a number to a byte array?

I'd like to avoid using transmute, but it's most important to reach maximum performance.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Walking.In.The.Air
  • 682
  • 2
  • 5
  • 13

2 Answers2

22

A u32 being 4 bytes, you may be able to use std::mem::transmute to interpret a [u8; 4] as a u32 however:

  • beware of alignment
  • beware of endianness

A no-dependency solution is simply to perform the maths, following in Rob Pike's steps:

fn as_u32_be(array: &[u8; 4]) -> u32 {
    ((array[0] as u32) << 24) +
    ((array[1] as u32) << 16) +
    ((array[2] as u32) <<  8) +
    ((array[3] as u32) <<  0)
}

fn as_u32_le(array: &[u8; 4]) -> u32 {
    ((array[0] as u32) <<  0) +
    ((array[1] as u32) <<  8) +
    ((array[2] as u32) << 16) +
    ((array[3] as u32) << 24)
}

It compiles down to reasonably efficient code.

If dependencies are an option though, using the byteorder crate is just simpler.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
17

There is T::from_str_radix to convert from a string (you can choose the base and T can be any integer type).

To convert an integer to a String you can use format!:

format!("{:x}", 42) == "2a"
format!("{:X}", 42) == "2A"

To reinterpret an integer as bytes, just use the byte_order crate.


Old answer, I don't advise this any more:

If you want to convert between u32 and [u8; 4] (for example) you can use transmute, it’s what it is for.

Note also that Rust has to_be and to_le functions to deal with endianess:

unsafe { std::mem::transmute::<u32, [u8; 4]>(42u32.to_le()) } == [42, 0, 0, 0]
unsafe { std::mem::transmute::<u32, [u8; 4]>(42u32.to_be()) } == [0, 0, 0, 42]
unsafe { std::mem::transmute::<[u8; 4], u32>([0, 0, 0, 42]) }.to_le() == 0x2a000000
unsafe { std::mem::transmute::<[u8; 4], u32>([0, 0, 0, 42]) }.to_be() == 0x0000002a
mcarton
  • 27,633
  • 5
  • 85
  • 95