safe_transmute/migration/v0_11.rs
1//! Migrating to `safe-transmute` v0.11
2//!
3//! This guide starts with a forewarning: `safe-transmute` had many safety issues before this version,
4//! which means that there is a chance of your dependent project facing undefined behavior. Migrating
5//! to version 0.11 is recommended as soon as possible, even if it might lead to a sub-optimal solution.
6//!
7//! ## Organization
8//!
9//! The crate is now organized with the following major categories:
10//! - `base` contains all baseline conversion functions. They are only protected against out of boundary
11//! access, like trying to create an 8-byte type from 7 bytes. However, they are still unsafe: any
12//! attempt of transmuting data to an invalid memory representation is still undefined behavior.
13//! Moreover, unaligned memory access is not prevented, and must be previously ensured by the caller.
14//! - The `trivial` module introduces the concept of being *trivially transmutable*, which
15//! statically ensures that any bit combination makes a valid value for a given type. Basically,
16//! if a type `T` can be filled with any arbitrary bits in its memory representation and still be
17//! valid, then `T` is trivially transmutable. Most primitive types implement the `TriviallyTransmutable`
18//! trait, as well as arrays of trivially transmutable types, but new types (such as repr-C structs)
19//! need to `unsafe impl` it manually. Functions in this module are therefore safer than the baseline,
20//! but are still unsafe because they do not check for memory alignment.
21//! - `to_bytes` enables the opposite operation of reintepreting values as bytes. They are usually safe
22//! unless when working with mutable slices, since they can break invariants of the source type.
23//! - The `bool` module ensures safe transmutation of bytes to boolean values.
24//! - That leaves the `full` functions at the crate root. These are transmutation functions with enough
25//! checks to be considered safe to use in any circumstance. The operation may still arbitrarily
26//! return (recoverable) errors due to unaligned data or incompatible vector transmutation targets,
27//! but it will not eat your laundry, and helper functions are available to assist the user in
28//! making some use cases work.
29//!
30//! Moreover, three utility modules have also been provided:
31//! - The `guard` module contains the **Guard API**, which imposes slice boundary restrictions in a conversion.
32//! - The `align` module is where alignment checks are implemented.
33//! - The `util` module provides some independent helper functions.
34//!
35//! Generally, you are strongly advised to *stick to the functions provided at the crate root*.
36//! These are re-exports from the `full`, `bool`, and `to_bytes` categories depending on their safety.
37//!
38//! ## Transmuting slices
39//!
40//! One of the major use cases of the crate is to grab a slice of bytes and reinterpret it as a slice of
41//! another type. This process is accompanied with a check for the source slice length, so that it
42//! makes some sense as the target type. If you expect any number of elements of the target type, use
43//! `transmute_many_permissive()`.
44//!
45//! ```rust
46//! # #[cfg(feature = "alloc")]
47//! # {
48//! use safe_transmute::{Error, transmute_many_permissive};
49//!
50//! let bytes = &[0x00, 0x01, 0x12, 0x24,
51//! 0x00]; // 1 spare byte
52//!
53//! match transmute_many_permissive::<u16>(bytes) {
54//! Ok(words) => {
55//! assert_eq!(words,
56//! [u16::from_be(0x0001), u16::from_be(0x1224)]);
57//! },
58//! Err(Error::Unaligned(e)) => {
59//! // Copy needed, would otherwise trap on some archs
60//! let words = e.copy();
61//! assert_eq!(*words,
62//! [u16::from_be(0x0001), u16::from_be(0x1224)]);
63//! },
64//! Err(e) => panic!("Unexpected error: {}", e),
65//! }
66//! # }
67//! ```
68//!
69//! `transmute_many_permissive()` is an alias for `transmute_many()` with `PermissiveGuard`
70//! as the guard type parameter. If you expect at least 1 element, use `transmute_many()` with the
71//! `SingleManyGuard` as the guard type. If you expect at least one element and no extraneous bytes, use
72//! `transmute_many_pedantic()`, or `transmute_many()` with `PedanticGuard`.
73//!
74//! As you can see, we had to manually handle the case where the slice of bytes is not well aligned for
75//! reading target data, such as from `u8` to `u16`. If the slice's first element is not aligned for
76//! reading `u16`s, the operation will just fail with `Error::Unaligned`. The only way to move on from
77//! here is to copy the data (provided by the `Error::copy()` method).
78//!
79//! The good news is that this boilerplate can be off-loaded to the `try_copy!` macro. Here's how you'll
80//! often be doing transmutations:
81//!
82//! ```rust
83//! # use safe_transmute::Error;
84//! # #[cfg(feature = "alloc")]
85//! # {
86//! use safe_transmute::{transmute_many_permissive, try_copy};
87//!
88//! let bytes = &[0x00, 0x01, 0x12, 0x24, 0x00];
89//! let words = try_copy!(transmute_many_permissive::<u16>(bytes));
90//!
91//! assert_eq!(&*words, &[u16::from_be(0x0001), u16::from_be(0x1224)]);
92//! # }
93//! # Ok::<(), Error<u8, u16>>(())
94//! ```
95//!
96//! You will also find `to_bytes`, `mut`, and `bool` variants of these functions. `transmute_to_bytes()` turns any slice into
97//! a slice of bytes. Functions from the `*_mut()` family work with mutable slices. `transmute_bool()` checks whether all bytes
98//! make valid boolean values beforehand.
99//!
100//! ## Transmuting vectors
101//!
102//! You might have used `safe-transmute`'s vector transmutation functions. Well, it turns out that they are
103//! **incredibly unsafe**, and hard to get right. This will be more complicated to migrate efficiently.
104//! The new `transmute_vec()` only works under very restricted conditions: the `mem::align_of()` and `mem::size_of()` between
105//! the source and target element types must match. Otherwise, a full copy of the vector must be made.
106//!
107//! ```rust
108//! # use safe_transmute::Error;
109//! # #[cfg(feature = "alloc")]
110//! # {
111//! use safe_transmute::{transmute_vec, try_copy};
112//!
113//! let bytes = vec![0x00, 0x01, 0x12, 0x24, 0x00];
114//! let words = try_copy!(transmute_vec::<_, u16>(bytes)); // !!! works, but will always copy
115//!
116//! assert_eq!(&*words, &[u16::from_be(0x0001), u16::from_be(0x1224)]);
117//! # }
118//! # Ok::<(), Error<u8, u16>>(())
119//! ```
120//!
121//! Oftentimes, you'll just be avoiding vector transmutation entirely.
122//!
123//! In order to avoid copies, you can allocate a vector of the target type `T`, transmute a mutable slice of the vector
124//! into the source data type `S`, and write the data in there directly. This still requires both `S` and `T` to be
125//! trivially transmutable in order to be within the compiler's safety guarantees, though.