25.5 Casting and std::mem::transmute

Safe Rust allows only a limited set of casts (for instance, certain integer-to-integer conversions). However, if you need to reinterpret a type's bits as another type, you must employ unsafe features.

Two key mechanisms are:

  1. The as operator, which covers some conversions but not all.
  2. std::mem::transmute, which reinterprets the bits of a value as a different type with no runtime checks.

transmute is effectively a bitwise copy between types. You must specify the source and destination types, and they must match in size. If they do not, the compiler will reject the code (unless you use nightly features to override this, which is highly unsafe).

25.5.1 Example: Reinterpreting Bits with transmute

fn float_to_bits(f: f32) -> u32 {
    unsafe { std::mem::transmute::<f32, u32>(f) }
}

fn bits_to_float(bits: u32) -> f32 {
    unsafe { std::mem::transmute::<u32, f32>(bits) }
}

fn main() {
    let f = 3.14f32;
    let bits = float_to_bits(f);
    println!("Float: {}, bits: 0x{:X}", f, bits);

    let f2 = bits_to_float(bits);
    println!("Back to float: {}", f2);
}

Because transmute reinterprets bits without checking types, incorrect usage can quickly lead to undefined behavior. Often, safer options (like the built-in to_bits method for floats) are more appropriate.