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:
basecontains all baseline conversion functions. They are only protected against out of boundary access, like trying to create an 8-byte type from 7 bytes. However, they are still unsafe: any attempt of transmuting data to an invalid memory representation is still undefined behavior. Moreover, unaligned memory access is not prevented, and must be previously ensured by the caller.- The 
trivialmodule introduces the concept of being trivially transmutable, which statically ensures that any bit combination makes a valid value for a given type. Basically, if a typeTcan be filled with any arbitrary bits in its memory representation and still be valid, thenTis trivially transmutable. Most primitive types implement theTriviallyTransmutabletrait, as well as arrays of trivially transmutable types, but new types (such as repr-C structs) need tounsafe implit manually. Functions in this module are therefore safer than the baseline, but are still unsafe because they do not check for memory alignment. to_bytesenables the opposite operation of reintepreting values as bytes. They are usually safe unless when working with mutable slices, since they can break invariants of the source type.- The 
boolmodule ensures safe transmutation of bytes to boolean values. - That leaves the 
fullfunctions at the crate root. These are transmutation functions with enough checks to be considered safe to use in any circumstance. The operation may still arbitrarily return (recoverable) errors due to unaligned data or incompatible vector transmutation targets, but it will not eat your laundry, and helper functions are available to assist the user in making some use cases work. 
Moreover, three utility modules have also been provided:
- The 
guardmodule contains the Guard API, which imposes slice boundary restrictions in a conversion. - The 
alignmodule is where alignment checks are implemented. - The 
utilmodule provides some independent helper functions. 
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.