17 releases (10 breaking)
Uses old Rust 2015
0.11.3 | May 21, 2024 |
---|---|
0.11.2 | May 31, 2021 |
0.11.1 | Feb 3, 2021 |
0.11.0 | Jun 20, 2020 |
0.3.0 | Nov 11, 2016 |
#142 in Rust patterns
33,391 downloads per month
Used in 128 crates
(22 directly)
95KB
690 lines
safe-transmute-rs
A safeguarded transmute()
for Rust.
Documentation
lib.rs
:
This crate contains checked implementations of transmutation procedures, some of which ensure memory safety.
Crate outline
The following modules are available:
- The functions in the
base
module are not inherently safe, but just protected against out of boundary access (like trying to create an 8-byte type from 7 bytes). These functions are as safe as the data passed to them: 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
guard
module contains the Guard API, which imposes slice boundary restrictions in a conversion. - The
trivial
module introduces theTriviallyTransmutable
trait, which statically ensures that any bit combination makes a valid value for a given type. The functions in this module are safer thanbase
, but still do not prevent unaligned memory access. to_bytes
enables the opposite operation of reintepreting values as bytes.- The
bool
module ensures safe transmutation of bytes to boolean values. - At the root of this crate, there 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 programmer in making some use cases work.
This crate can be used in a no-std
environment by disabling the std
feature through specifying default-features = false
on import.
However, std
is only used for integration with std::error::Error
.
Note, though, that functions operating on items from alloc
will also be disabled by this.
If your no-std
environment has an alloc
implementation, you will have to reenable them by using features = ["alloc"]
.
Migrating
If you've used safe-transmute
before v0.11,
we recommend the v0.11 migration guide to help get you going quickly.
Examples
View bytes as a series of u16
s, with a single-many boundary
guard (at least one value, extraneous bytes are allowed):
let bytes = &[0x00, 0x01, 0x12, 0x24,
0x00]; // 1 spare byte
match transmute_many::<u16, SingleManyGuard>(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),
}
Since one may not always be able to ensure that a slice of bytes is well
aligned for reading data of different constraints, such as from u8
to
u16
, the operation may fail without a trivial way of preventing it.
As a remedy, the data can instead be copied byte-for-byte to a new vector,
with the help of the try_copy!()
macro.
let bytes = &[0x00, 0x01, 0x12, 0x24, 0x00];
let words = try_copy!(transmute_many::<u16, SingleManyGuard>(bytes));
assert_eq!(*words,
[u16::from_be(0x0001), u16::from_be(0x1224)]);
View all bytes as a series of u16
s:
// Assuming little-endian
let bytes = &[0x00, 0x01, 0x12, 0x34];
let words = try_copy!(transmute_many_pedantic::<u16>(bytes));
assert_eq!(*words, [0x0100, 0x3412]);
View a byte slice as a single f64
:
assert_eq!(transmute_one::<f64>(
&[0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40])?,
2.0);
View a series of u16
s as bytes:
assert_eq!(transmute_to_bytes(&[0x0001u16,
0x1234u16]),
&[0x01, 0x00, 0x34, 0x12]);