Module safe_transmute::migration::v0_11[][src]

Migrating to safe-transmute v0.11

This guide starts with a forewarning: safe-transmute had many safety issues before this version, which means that there is a chance of your dependent project facing undefined behavior. Migrating to version 0.11 is recommended as soon as possible, even if it might lead to a sub-optimal solution.

Organization

The crate is now organized with the following major categories:

Moreover, three utility modules have also been provided:

Generally, you are strongly advised to stick to the functions provided at the crate root. These are re-exports from the full, bool, and to_bytes categories depending on their safety.

Transmuting slices

One of the major use cases of the crate is to grab a slice of bytes and reinterpret it as a slice of another type. This process is accompanied with a check for the source slice length, so that it makes some sense as the target type. If you expect any number of elements of the target type, use transmute_many_permissive().

use safe_transmute::{Error, transmute_many_permissive};

let bytes = &[0x00, 0x01, 0x12, 0x24,
              0x00]; // 1 spare byte

match transmute_many_permissive::<u16>(bytes) {
    Ok(words) => {
        assert_eq!(words,
                   [u16::from_be(0x0001), u16::from_be(0x1224)]);
    },
    Err(Error::Unaligned(e)) => {
        // Copy needed, would otherwise trap on some archs
        let words = e.copy();
        assert_eq!(*words,
                   [u16::from_be(0x0001), u16::from_be(0x1224)]);
    },
    Err(e) => panic!("Unexpected error: {}", e),
}

transmute_many_permissive() is an alias for transmute_many() with PermissiveGuard as the guard type parameter. If you expect at least 1 element, use transmute_many() with the SingleManyGuard as the guard type. If you expect at least one element and no extraneous bytes, use transmute_many_pedantic(), or transmute_many() with PedanticGuard.

As you can see, we had to manually handle the case where the slice of bytes is not well aligned for reading target data, such as from u8 to u16. If the slice’s first element is not aligned for reading u16s, the operation will just fail with Error::Unaligned. The only way to move on from here is to copy the data (provided by the Error::copy() method).

The good news is that this boilerplate can be off-loaded to the try_copy! macro. Here’s how you’ll often be doing transmutations:

use safe_transmute::{transmute_many_permissive, try_copy};

let bytes = &[0x00, 0x01, 0x12, 0x24, 0x00];
let words = try_copy!(transmute_many_permissive::<u16>(bytes));

assert_eq!(&*words, &[u16::from_be(0x0001), u16::from_be(0x1224)]);

You will also find to_bytes, mut, and bool variants of these functions. transmute_to_bytes() turns any slice into a slice of bytes. Functions from the *_mut() family work with mutable slices. transmute_bool() checks whether all bytes make valid boolean values beforehand.

Transmuting vectors

You might have used safe-transmute’s vector transmutation functions. Well, it turns out that they are incredibly unsafe, and hard to get right. This will be more complicated to migrate efficiently. The new transmute_vec() only works under very restricted conditions: the mem::align_of() and mem::size_of() between the source and target element types must match. Otherwise, a full copy of the vector must be made.

use safe_transmute::{transmute_vec, try_copy};

let bytes = vec![0x00, 0x01, 0x12, 0x24, 0x00];
let words = try_copy!(transmute_vec::<_, u16>(bytes)); // !!! works, but will always copy

assert_eq!(&*words, &[u16::from_be(0x0001), u16::from_be(0x1224)]);

Oftentimes, you’ll just be avoiding vector transmutation entirely.

In order to avoid copies, you can allocate a vector of the target type T, transmute a mutable slice of the vector into the source data type S, and write the data in there directly. This still requires both S and T to be trivially transmutable in order to be within the compiler’s safety guarantees, though.