1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
//! 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:
//! - `base` contains 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 `trivial` module 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 type `T` can be filled with any arbitrary bits in its memory representation and still be
//! valid, then `T` is trivially transmutable. Most primitive types implement the `TriviallyTransmutable`
//! trait, as well as arrays of trivially transmutable types, but new types (such as repr-C structs)
//! need to `unsafe impl` it manually. Functions in this module are therefore safer than the baseline,
//! but are still unsafe because they do not check for memory alignment.
//! - `to_bytes` enables 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 `bool` module ensures safe transmutation of bytes to boolean values.
//! - That leaves the `full` functions 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 `guard` module contains the **Guard API**, which imposes slice boundary restrictions in a conversion.
//! - The `align` module is where alignment checks are implemented.
//! - The `util` module 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()`.
//!
//! ```rust
//! # #[cfg(feature = "alloc")]
//! # {
//! 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 `u16`s, 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:
//!
//! ```rust
//! # use safe_transmute::Error;
//! # #[cfg(feature = "alloc")]
//! # {
//! 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)]);
//! # }
//! # Ok::<(), Error<u8, u16>>(())
//! ```
//!
//! 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.
//!
//! ```rust
//! # use safe_transmute::Error;
//! # #[cfg(feature = "alloc")]
//! # {
//! 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)]);
//! # }
//! # Ok::<(), Error<u8, u16>>(())
//! ```
//!
//! 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.