safe_transmute/lib.rs
1//! This crate contains checked implementations of transmutation procedures, some of which
2//! ensure memory safety.
3//!
4//! ## Crate outline
5//!
6//! The following modules are available:
7//!
8//! - The functions in the [`base`](base/index.html) module are not inherently
9//! safe, but just protected against out of boundary access (like trying to
10//! create an 8-byte type from 7 bytes). These functions are as safe as
11//! the data passed to them: any attempt of transmuting data to an invalid
12//! memory representation is still undefined behavior. Moreover, unaligned
13//! memory access is not prevented, and must be previously ensured by the
14//! caller.
15//! - The [`guard`](guard/index.html) module contains the **Guard API**, which
16//! imposes slice boundary restrictions in a conversion.
17//! - The [`trivial`](trivial/index.html) module introduces the
18//! [`TriviallyTransmutable`](trivial/trait.TriviallyTransmutable.html)
19//! trait, which statically ensures that any bit combination makes a valid
20//! value for a given type. The functions in this module are safer than
21//! [`base`](base/index.html), but still do not prevent unaligned memory access.
22//! - [`to_bytes`](to_bytes/index.html) enables the opposite operation of
23//! reintepreting values as bytes.
24//! - The [`bool`](bool/index.html) module ensures safe transmutation of bytes
25//! to boolean values.
26//! - At the root of this crate, there are transmutation functions with enough
27//! checks to be considered safe to use in any circumstance. The operation may
28//! still arbitrarily return (recoverable) errors due to unaligned data or
29//! incompatible vector transmutation targets, but it will not eat your
30//! laundry, and helper functions are available to assist the programmer in
31//! making some use cases work.
32//!
33//! This crate can be used in a no-`std` environment by disabling the `std`
34//! feature through specifying `default-features = false` on import.
35//! However, `std` is only used for integration with `std::error::Error`.
36//!
37//! Note, though, that functions operating on items from `alloc` will also be disabled by this.
38//! If your no-`std` environment has an `alloc` implementation, you will have to reenable them by using `features = ["alloc"]`.
39//!
40//! # Migrating
41//!
42//! If you've used `safe-transmute` before v0.11,
43//! we recommend [the v0.11 migration guide](migration/v0_11/index.html) to help get you going quickly.
44//!
45//! # Examples
46//!
47//! View bytes as a series of `u16`s, with a single-many boundary
48//! guard (at least one value, extraneous bytes are allowed):
49//!
50//! ```
51//! # use safe_transmute::{SingleManyGuard, Error, transmute_many};
52//! # #[cfg(feature = "std")]
53//! # fn main() -> Result<(), Box<std::error::Error>> {
54//! let bytes = &[0x00, 0x01, 0x12, 0x24,
55//! 0x00]; // 1 spare byte
56//! match transmute_many::<u16, SingleManyGuard>(bytes) {
57//! Ok(words) => {
58//! assert_eq!(words,
59//! [u16::from_be(0x0001), u16::from_be(0x1224)]);
60//! },
61//! Err(Error::Unaligned(e)) => {
62//! // Copy needed, would otherwise trap on some archs
63//! let words = e.copy();
64//! assert_eq!(*words,
65//! [u16::from_be(0x0001), u16::from_be(0x1224)]);
66//! },
67//! Err(e) => panic!("Unexpected error: {}", e),
68//! }
69//! # Ok(())
70//! # }
71//! # #[cfg(not(feature = "std"))]
72//! # fn main() {}
73//! ```
74//!
75//! Since one may not always be able to ensure that a slice of bytes is well
76//! aligned for reading data of different constraints, such as from `u8` to
77//! `u16`, the operation may fail without a trivial way of preventing it.
78//!
79//! As a remedy, the data can instead be copied byte-for-byte to a new vector,
80//! with the help of the [`try_copy!()`](macro.try_copy.html) macro.
81//!
82//! ```
83//! # #[macro_use]
84//! # extern crate safe_transmute;
85//! # use safe_transmute::{SingleManyGuard, Error, transmute_many};
86//! # #[cfg(feature = "std")]
87//! # fn main() -> Result<(), Box<std::error::Error>> {
88//! let bytes = &[0x00, 0x01, 0x12, 0x24, 0x00];
89//! let words = try_copy!(transmute_many::<u16, SingleManyGuard>(bytes));
90//!
91//! assert_eq!(*words,
92//! [u16::from_be(0x0001), u16::from_be(0x1224)]);
93//! # Ok(())
94//! # }
95//! # #[cfg(not(feature = "std"))]
96//! # fn main() {}
97//! ```
98//!
99//! View all bytes as a series of `u16`s:
100//!
101//! ```
102//! # #[macro_use]
103//! # extern crate safe_transmute;
104//! # use safe_transmute::{Error, transmute_many_pedantic};
105//! # include!("../tests/test_util/le_to_native.rs");
106//! # #[cfg(feature = "std")]
107//! # fn main() -> Result<(), Box<std::error::Error>> {
108//! # let bytes = &Le2NAl4([0x00, 0x01, 0x12, 0x34]).le_to_native::<u16>();
109//! # let words = try_copy!(transmute_many_pedantic::<u16>(bytes).map_err(Error::without_src));
110//! # /*
111//! // Assuming little-endian
112//! let bytes = &[0x00, 0x01, 0x12, 0x34];
113//! let words = try_copy!(transmute_many_pedantic::<u16>(bytes));
114//! # */
115//!
116//! assert_eq!(*words, [0x0100, 0x3412]);
117//! # Ok(())
118//! # }
119//! # #[cfg(not(feature = "std"))]
120//! # fn main() {}
121//! ```
122//!
123//! View a byte slice as a single `f64`:
124//!
125//! ```
126//! # use safe_transmute::transmute_one;
127//! # include!("../tests/test_util/le_to_native.rs");
128//! # fn main() {
129//! assert_eq!(transmute_one::<f64>(
130//! # /*
131//! &[0x00, 0x00, 0x00, 0x00,
132//! 0x00, 0x00, 0x00, 0x40])?,
133//! # */
134//! # &*Le2NAl8([0x00, 0x00, 0x00, 0x00,
135//! # 0x00, 0x00, 0x00, 0x40]).le_to_native::<f64>()).unwrap(),
136//! 2.0);
137//! # }
138//! ```
139//!
140//! View a series of `u16`s as bytes:
141//!
142//! ```
143//! # use safe_transmute::transmute_to_bytes;
144//! # include!("../tests/test_util/le_to_native.rs");
145//! # fn main() {
146//! assert_eq!(transmute_to_bytes(&[0x0001u16,
147//! 0x1234u16]),
148//! # /*
149//! &[0x01, 0x00, 0x34, 0x12]);
150//! # */
151//! # &*Le2NAl4([0x01, 0x00, 0x34, 0x12]).le_to_native::<u16>());
152//! # }
153//! ```
154
155
156#![cfg_attr(not(feature = "std"), no_std)]
157
158
159#[cfg(feature = "std")]
160extern crate core;
161#[cfg(feature = "alloc")]
162#[doc(hidden)]
163pub extern crate alloc;
164
165mod full;
166
167pub mod base;
168pub mod bool;
169pub mod util;
170pub mod align;
171pub mod error;
172pub mod guard;
173pub mod trivial;
174pub mod to_bytes;
175pub mod migration;
176
177pub use self::full::{transmute_many_permissive_mut, transmute_many_pedantic_mut, transmute_many_permissive, transmute_many_pedantic, transmute_one_pedantic,
178 transmute_many, transmute_many_mut, transmute_one};
179#[cfg(feature = "alloc")]
180pub use self::full::transmute_vec;
181
182
183pub use self::guard::{SingleValueGuard, PermissiveGuard, SingleManyGuard, PedanticGuard, Guard};
184pub use self::error::{UnalignedError, ErrorReason, GuardError, Error};
185#[cfg(feature = "alloc")]
186pub use self::error::IncompatibleVecTargetError;
187pub use self::trivial::{TriviallyTransmutable, align_to_mut, align_to};
188
189pub use self::to_bytes::{transmute_one_to_bytes_mut, transmute_one_to_bytes, transmute_to_bytes_mut, transmute_to_bytes};
190#[cfg(feature = "alloc")]
191pub use self::to_bytes::transmute_to_bytes_vec;
192
193#[cfg(feature = "alloc")]
194pub use self::bool::{transmute_bool_vec_permissive, transmute_bool_vec_pedantic};
195pub use self::bool::{transmute_bool_permissive, transmute_bool_pedantic};