├── tests ├── error │ ├── mod.rs │ └── unaligned.rs ├── guard │ ├── mod.rs │ └── zero_sized.rs ├── bool │ ├── mod.rs │ ├── permissive.rs │ ├── vec_permissive.rs │ ├── pedantic.rs │ └── vec_pedantic.rs ├── full │ ├── mod.rs │ ├── many_permissive.rs │ ├── vec.rs │ ├── one_pedantic.rs │ ├── one.rs │ ├── many.rs │ └── many_pedantic.rs ├── lib.rs ├── base │ ├── mod.rs │ ├── from_bytes_pedantic.rs │ ├── transmute_many_permissive.rs │ ├── from_bytes.rs │ ├── transmute_many_pedantic.rs │ └── transmute_many.rs ├── test_util │ ├── aligned_vec.rs │ └── le_to_native.rs └── util │ └── mod.rs ├── src ├── migration │ ├── mod.rs │ └── v0_11.rs ├── align.rs ├── util.rs ├── bool.rs ├── guard.rs ├── lib.rs ├── base.rs ├── full.rs ├── to_bytes.rs ├── error.rs └── trivial.rs ├── gh_rsa.enc ├── .gitignore ├── rustfmt.toml ├── README.md ├── Cargo.toml ├── LICENSE ├── appveyor.yml ├── safe-transmute-rs.sublime-project └── .travis.yml /tests/error/mod.rs: -------------------------------------------------------------------------------- 1 | mod unaligned; 2 | -------------------------------------------------------------------------------- /tests/guard/mod.rs: -------------------------------------------------------------------------------- 1 | mod zero_sized; 2 | -------------------------------------------------------------------------------- /src/migration/mod.rs: -------------------------------------------------------------------------------- 1 | //! Migration guides. 2 | 3 | pub mod v0_11; 4 | -------------------------------------------------------------------------------- /gh_rsa.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nabijaczleweli/safe-transmute-rs/HEAD/gh_rsa.enc -------------------------------------------------------------------------------- /tests/bool/mod.rs: -------------------------------------------------------------------------------- 1 | mod vec_permissive; 2 | mod vec_pedantic; 3 | mod permissive; 4 | mod pedantic; 5 | -------------------------------------------------------------------------------- /tests/full/mod.rs: -------------------------------------------------------------------------------- 1 | mod many_permissive; 2 | mod many_pedantic; 3 | mod one_pedantic; 4 | mod many; 5 | mod one; 6 | mod vec; 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !.travis.yml 4 | !gh_rsa.enc 5 | !appveyor.yml 6 | !LICENSE 7 | !Cargo.toml 8 | !rustfmt.toml 9 | !*.sublime-project 10 | !*.md 11 | !src 12 | !src/** 13 | !tests 14 | !tests/** 15 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 160 2 | ideal_width = 128 3 | fn_call_width = 96 4 | fn_args_paren_newline = false 5 | fn_args_density = "Compressed" 6 | struct_trailing_comma = "Always" 7 | wrap_comments = true 8 | -------------------------------------------------------------------------------- /tests/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | 4 | #[cfg(feature = "std")] 5 | extern crate core; 6 | 7 | #[macro_use] 8 | #[cfg(feature = "alloc")] 9 | extern crate alloc; 10 | 11 | #[cfg_attr(feature = "alloc", macro_use)] 12 | extern crate safe_transmute; 13 | 14 | 15 | mod guard; 16 | mod error; 17 | mod base; 18 | mod bool; 19 | mod full; 20 | mod util; 21 | 22 | 23 | include!("test_util/le_to_native.rs"); 24 | include!("test_util/aligned_vec.rs"); 25 | -------------------------------------------------------------------------------- /tests/base/mod.rs: -------------------------------------------------------------------------------- 1 | mod transmute_many_permissive; 2 | mod transmute_many_pedantic; 3 | mod from_bytes_pedantic; 4 | mod transmute_many; 5 | mod from_bytes; 6 | 7 | 8 | #[cfg(feature = "alloc")] 9 | use safe_transmute::base; 10 | 11 | 12 | #[cfg(feature = "alloc")] 13 | #[test] 14 | fn transmute_vec() { 15 | unsafe { 16 | assert_eq!(base::transmute_vec::(vec![0x0100u16]), vec![0x0100i16]); 17 | assert_eq!(base::transmute_vec::(vec![0x0100u16, 0x0200u16]), vec![0x0100i16, 0x0200i16]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # safe-transmute-rs [![TravisCI build status](https://travis-ci.org/nabijaczleweli/safe-transmute-rs.svg?branch=master)](https://travis-ci.org/nabijaczleweli/safe-transmute-rs) [![AppVeyorCI build status](https://ci.appveyor.com/api/projects/status/cspjknvfow5gfro0/branch/master?svg=true)](https://ci.appveyor.com/project/nabijaczleweli/safe-transmute-rs/branch/master) [![Licence](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE) [![Crates.io version](https://meritbadge.herokuapp.com/safe-transmute)](https://crates.io/crates/safe-transmute) 2 | A safeguarded `transmute()` for Rust. 3 | 4 | ## [Documentation](https://rawcdn.githack.com/nabijaczleweli/safe-transmute-rs/doc/safe_transmute/index.html) 5 | -------------------------------------------------------------------------------- /tests/bool/permissive.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{Error, transmute_bool_permissive}; 2 | 3 | 4 | #[test] 5 | fn too_short() { 6 | assert_eq!(transmute_bool_permissive([].as_ref()), Ok([].as_ref())); 7 | } 8 | 9 | #[test] 10 | fn just_enough() { 11 | assert_eq!(transmute_bool_permissive([0x00, 0x01].as_ref()), Ok([false, true].as_ref())); 12 | assert_eq!(transmute_bool_permissive([0x00, 0x01, 0x00, 0x01].as_ref()), 13 | Ok([false, true, false, true].as_ref())); 14 | } 15 | 16 | #[test] 17 | fn invalid_bytes() { 18 | assert_eq!(transmute_bool_permissive([0x00, 0x01, 0x02].as_ref()), Err(Error::InvalidValue)); 19 | assert_eq!(transmute_bool_permissive([0x05, 0x01, 0x00].as_ref()), Err(Error::InvalidValue)); 20 | assert_eq!(transmute_bool_permissive([0xFF].as_ref()), Err(Error::InvalidValue)); 21 | } 22 | -------------------------------------------------------------------------------- /tests/bool/vec_permissive.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "alloc")] 2 | 3 | 4 | use safe_transmute::{Error, transmute_bool_vec_permissive}; 5 | 6 | 7 | #[test] 8 | fn too_short() { 9 | assert_eq!(transmute_bool_vec_permissive(vec![]), Ok(vec![])); 10 | } 11 | 12 | #[test] 13 | fn just_enough() { 14 | assert_eq!(transmute_bool_vec_permissive(vec![0x00, 0x01]), Ok(vec![false, true])); 15 | assert_eq!(transmute_bool_vec_permissive(vec![0x00, 0x01, 0x00, 0x01]), 16 | Ok(vec![false, true, false, true])); 17 | } 18 | 19 | #[test] 20 | fn invalid_bytes() { 21 | assert_eq!(transmute_bool_vec_permissive(vec![0x00, 0x01, 0x02]), Err(Error::InvalidValue)); 22 | assert_eq!(transmute_bool_vec_permissive(vec![0x05, 0x01, 0x00]), Err(Error::InvalidValue)); 23 | assert_eq!(transmute_bool_vec_permissive(vec![0xFF]), Err(Error::InvalidValue)); 24 | } 25 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "safe-transmute" 3 | description = "A safeguarded transmute() for Rust" 4 | documentation = "https://rawcdn.githack.com/nabijaczleweli/safe-transmute-rs/doc/safe_transmute/index.html" 5 | repository = "https://github.com/nabijaczleweli/safe-transmute-rs" 6 | readme = "README.md" 7 | keywords = ["safe", "transmute", "checked"] 8 | categories = ["rust-patterns", "memory-management", "no-std"] 9 | license = "MIT" 10 | # Remember to also update in appveyor.yml 11 | version = "0.11.3" 12 | authors = ["наб ", 13 | "Eduardo Pinho ", 14 | "Lukas Kalbertodt ", 15 | "Philipp Tessenow ", 16 | "Marijn Suijten "] 17 | exclude = ["*.enc"] 18 | 19 | [features] 20 | default = ["std"] 21 | "std" = ["alloc"] 22 | "alloc" = [] 23 | # Use const generics for array trait implementations 24 | "const_generics" = [] 25 | -------------------------------------------------------------------------------- /tests/bool/pedantic.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{ErrorReason, GuardError, Error, transmute_bool_pedantic}; 2 | 3 | 4 | #[test] 5 | fn too_short() { 6 | assert_eq!(transmute_bool_pedantic([].as_ref()), 7 | Err(Error::Guard(GuardError { 8 | required: 1, 9 | actual: 0, 10 | reason: ErrorReason::NotEnoughBytes, 11 | }))); 12 | } 13 | 14 | #[test] 15 | fn just_enough() { 16 | assert_eq!(transmute_bool_pedantic([0x00, 0x01].as_ref()), Ok(&[false, true][..])); 17 | assert_eq!(transmute_bool_pedantic([0x01, 0x01, 0x00, 0x01].as_ref()), 18 | Ok(&[true, true, false, true][..])); 19 | } 20 | 21 | #[test] 22 | fn invalid_bytes() { 23 | assert_eq!(transmute_bool_pedantic([0x00, 0x01, 0x02].as_ref()), Err(Error::InvalidValue)); 24 | assert_eq!(transmute_bool_pedantic([0x05, 0x01, 0x00].as_ref()), Err(Error::InvalidValue)); 25 | assert_eq!(transmute_bool_pedantic([0xFF].as_ref()), Err(Error::InvalidValue)); 26 | } 27 | -------------------------------------------------------------------------------- /tests/bool/vec_pedantic.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "alloc")] 2 | 3 | 4 | use safe_transmute::{ErrorReason, GuardError, Error, transmute_bool_vec_pedantic}; 5 | 6 | 7 | #[test] 8 | fn too_short() { 9 | assert_eq!(transmute_bool_vec_pedantic(vec![]), 10 | Err(Error::Guard(GuardError { 11 | required: 1, 12 | actual: 0, 13 | reason: ErrorReason::NotEnoughBytes, 14 | }))); 15 | } 16 | 17 | #[test] 18 | fn just_enough() { 19 | assert_eq!(transmute_bool_vec_pedantic(vec![0x00, 0x01]), Ok(vec![false, true])); 20 | assert_eq!(transmute_bool_vec_pedantic(vec![0x00, 0x01, 0x00, 0x01]), 21 | Ok(vec![false, true, false, true])); 22 | } 23 | 24 | #[test] 25 | fn invalid_bytes() { 26 | assert_eq!(transmute_bool_vec_pedantic(vec![0x00, 0x01, 0x02]), Err(Error::InvalidValue)); 27 | assert_eq!(transmute_bool_vec_pedantic(vec![0x05, 0x01, 0x00]), Err(Error::InvalidValue)); 28 | assert_eq!(transmute_bool_vec_pedantic(vec![0xFF]), Err(Error::InvalidValue)); 29 | } 30 | -------------------------------------------------------------------------------- /tests/full/many_permissive.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{transmute_many_permissive, transmute_to_bytes}; 2 | 3 | 4 | #[test] 5 | fn too_short() { 6 | assert_eq!(transmute_many_permissive::(transmute_to_bytes::(&[])), Ok([].as_ref())); 7 | assert_eq!(transmute_many_permissive::(&transmute_to_bytes::(&[0])[..1]), 8 | Ok([].as_ref())); 9 | } 10 | 11 | #[test] 12 | fn just_enough() { 13 | let words: &[u16] = &[0x0100u16, 0x0200u16]; 14 | let bytes = transmute_to_bytes(words); 15 | assert_eq!(transmute_many_permissive::(&bytes[..2]), Ok(&words[..1])); 16 | assert_eq!(transmute_many_permissive::(bytes), Ok(words)); 17 | } 18 | 19 | #[test] 20 | fn too_much() { 21 | let words: &[u16] = &[0x0100, 0x0200, 0x0300, 0]; 22 | let bytes = transmute_to_bytes(words); 23 | assert_eq!(transmute_many_permissive::(&bytes[..3]), Ok(&words[..1])); 24 | assert_eq!(transmute_many_permissive::(&bytes[..5]), Ok(&words[..2])); 25 | assert_eq!(transmute_many_permissive::(&bytes[..7]), Ok(&words[..3])); 26 | } 27 | -------------------------------------------------------------------------------- /tests/full/vec.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "alloc")] 2 | 3 | 4 | use safe_transmute::error::IncompatibleVecTargetError; 5 | use safe_transmute::{transmute_vec, Error}; 6 | 7 | 8 | #[test] 9 | fn bad_size() { 10 | assert_eq!(transmute_vec::(vec![]), 11 | Err(Error::IncompatibleVecTarget(IncompatibleVecTargetError::new(vec![])))); 12 | assert_eq!(transmute_vec::(vec![1, 2, 3]), 13 | Err(Error::IncompatibleVecTarget(IncompatibleVecTargetError::new(vec![1, 2, 3])))); 14 | } 15 | 16 | #[test] 17 | fn just_enough() { 18 | assert_eq!(transmute_vec::(vec![0x00, 0x01]), Ok(vec![0x00i8, 0x01i8])); 19 | assert_eq!(transmute_vec::(vec![0x0100u16, 0x0200u16]), Ok(vec![0x0100i16, 0x0200i16])); 20 | } 21 | 22 | #[test] 23 | fn bad_alignment() { 24 | assert_eq!(transmute_vec::(vec![8, 8, 8]), 25 | Err(Error::IncompatibleVecTarget(IncompatibleVecTargetError::new(vec![8, 8, 8])))); 26 | assert_eq!(transmute_vec::(vec![3, 2, 1]), 27 | Err(Error::IncompatibleVecTarget(IncompatibleVecTargetError::new(vec![3, 2, 1])))); 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 nabijaczleweli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: 2 | - Visual Studio 2022 3 | 4 | version: 0.11.2-{build} 5 | 6 | skip_tags: false 7 | 8 | platform: x64 9 | configuration: Release 10 | 11 | clone_folder: C:\safe-transmute-rs 12 | 13 | install: 14 | - set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%;C:\Users\appveyor\.cargo\bin 15 | # Double upgrade required here 16 | - bash -lc "pacman --noconfirm -Syyu" 17 | - bash -lc "pacman --noconfirm -Syyu" 18 | - bash -lc "pacman --noconfirm -S mingw-w64-x86_64-toolchain" 19 | - 20 | - curl -SL https://win.rustup.rs/ -oC:\rustup-init.exe 21 | - C:\rustup-init.exe -y --default-host="x86_64-pc-windows-gnu" 22 | 23 | build: off 24 | build_script: 25 | - cargo build --verbose --release 26 | - cargo build --verbose --release --no-default-features 27 | - cargo build --verbose --release --no-default-features --features alloc 28 | 29 | test: off 30 | test_script: 31 | - cargo test --verbose --release 32 | - cargo test --verbose --release --no-default-features 33 | - cargo test --verbose --release --no-default-features --features alloc 34 | 35 | notifications: 36 | - provider: Email 37 | to: 38 | - nabijaczleweli@gmail.com 39 | on_build_status_changed: true 40 | -------------------------------------------------------------------------------- /tests/full/one_pedantic.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{ErrorReason, GuardError, Error, transmute_one_pedantic, transmute_to_bytes}; 2 | 3 | 4 | #[test] 5 | fn too_short() { 6 | assert_eq!(transmute_one_pedantic::(transmute_to_bytes::(&[])), 7 | Err(Error::Guard(GuardError { 8 | required: 32 / 8, 9 | actual: 0, 10 | reason: ErrorReason::InexactByteCount, 11 | }))); 12 | assert_eq!(transmute_one_pedantic::(&transmute_to_bytes::(&[0])[..1]), 13 | Err(Error::Guard(GuardError { 14 | required: 32 / 8, 15 | actual: 1, 16 | reason: ErrorReason::InexactByteCount, 17 | }))); 18 | } 19 | 20 | #[test] 21 | fn just_enough() { 22 | assert_eq!(transmute_one_pedantic::(&transmute_to_bytes::(&[0x0100_0000])), 23 | Ok(0x0100_0000)); 24 | } 25 | 26 | #[test] 27 | fn too_much() { 28 | assert_eq!(transmute_one_pedantic::(&transmute_to_bytes::(&[0x0100_0000, 0])[..5]), 29 | Err(Error::Guard(GuardError { 30 | required: 32 / 8, 31 | actual: 5, 32 | reason: ErrorReason::InexactByteCount, 33 | }))); 34 | } 35 | -------------------------------------------------------------------------------- /tests/full/one.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{ErrorReason, GuardError, Error, transmute_to_bytes, transmute_one}; 2 | 3 | 4 | #[test] 5 | fn too_short() { 6 | assert_eq!(transmute_one::(transmute_to_bytes::(&[])), 7 | Err(Error::Guard(GuardError { 8 | required: 32 / 8, 9 | actual: 0, 10 | reason: ErrorReason::NotEnoughBytes, 11 | }))); 12 | assert_eq!(transmute_one::(&transmute_to_bytes::(&[0])[..1]), 13 | Err(Error::Guard(GuardError { 14 | required: 32 / 8, 15 | actual: 1, 16 | reason: ErrorReason::NotEnoughBytes, 17 | }))); 18 | } 19 | 20 | #[test] 21 | fn just_enough() { 22 | let words: &[u32] = &[0x1234_5678]; 23 | assert_eq!(transmute_one::(transmute_to_bytes(words)), Ok(words[0])); 24 | } 25 | 26 | #[test] 27 | fn too_much() { 28 | let words: &[u32] = &[0x0100_0000, 0, 0]; 29 | let bytes = transmute_to_bytes(words); 30 | assert_eq!(transmute_one::(&bytes[..5]), Ok(0x0100_0000)); 31 | assert_eq!(transmute_one::(&bytes[..6]), Ok(0x0100_0000)); 32 | assert_eq!(transmute_one::(&bytes[..7]), Ok(0x0100_0000)); 33 | assert_eq!(transmute_one::(&bytes[..8]), Ok(0x0100_0000)); 34 | assert_eq!(transmute_one::(&bytes[..9]), Ok(0x0100_0000)); 35 | } 36 | -------------------------------------------------------------------------------- /tests/base/from_bytes_pedantic.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{ErrorReason, GuardError, Error, transmute_to_bytes}; 2 | use safe_transmute::base::from_bytes_pedantic; 3 | 4 | 5 | #[test] 6 | fn too_short() { 7 | unsafe { 8 | assert_eq!(from_bytes_pedantic::(&[]), 9 | Err(Error::Guard(GuardError { 10 | required: 32 / 8, 11 | actual: 0, 12 | reason: ErrorReason::InexactByteCount, 13 | }))); 14 | assert_eq!(from_bytes_pedantic::(&[0x00]), 15 | Err(Error::Guard(GuardError { 16 | required: 32 / 8, 17 | actual: 1, 18 | reason: ErrorReason::InexactByteCount, 19 | }))); 20 | } 21 | } 22 | 23 | #[test] 24 | fn just_enough() { 25 | let word = [0x0100_0020]; 26 | let bytes = transmute_to_bytes(&word); 27 | 28 | unsafe { 29 | assert_eq!(from_bytes_pedantic::(bytes), Ok(0x0100_0020)); 30 | } 31 | } 32 | 33 | #[test] 34 | fn too_much() { 35 | unsafe { 36 | assert_eq!(from_bytes_pedantic::(&[0x00, 0x00, 0x00, 0x01, 0x00]), 37 | Err(Error::Guard(GuardError { 38 | required: 32 / 8, 39 | actual: 5, 40 | reason: ErrorReason::InexactByteCount, 41 | }))); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/base/transmute_many_permissive.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{PermissiveGuard, transmute_to_bytes}; 2 | use safe_transmute::base::transmute_many; 3 | 4 | 5 | #[test] 6 | fn too_short() { 7 | let words: &[u16] = &[0x0100, 0x0200, 0x0300]; 8 | let bytes = transmute_to_bytes(words); 9 | 10 | unsafe { 11 | assert_eq!(transmute_many::(&bytes[..0]), Ok(&[][..])); 12 | assert_eq!(transmute_many::(&bytes[..1]), Ok(&[][..])); 13 | } 14 | } 15 | 16 | #[test] 17 | fn just_enough() { 18 | let words: &[u16] = &[0x0100, 0x0200, 0x0300]; 19 | let bytes = transmute_to_bytes(words); 20 | 21 | unsafe { 22 | assert_eq!(transmute_many::(&bytes[..2]), 23 | Ok(&words[..1])); 24 | assert_eq!(transmute_many::(bytes), 25 | Ok(words)); 26 | } 27 | } 28 | 29 | #[test] 30 | fn too_much() { 31 | let words: &[u16] = &[0x0100, 0x0200, 0x0300, 0]; 32 | let bytes = transmute_to_bytes(words); 33 | 34 | unsafe { 35 | assert_eq!(transmute_many::(&bytes[..3]), 36 | Ok(&words[..1])); 37 | assert_eq!(transmute_many::(&bytes[..5]), 38 | Ok(&words[..2])); 39 | assert_eq!(transmute_many::(&bytes[..7]), 40 | Ok(&words[..3])); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/full/many.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{SingleManyGuard, ErrorReason, GuardError, Error, transmute_to_bytes, transmute_many}; 2 | 3 | 4 | #[test] 5 | fn too_short() { 6 | assert_eq!(transmute_many::(transmute_to_bytes::(&[])), 7 | Err(Error::Guard(GuardError { 8 | required: 16 / 8, 9 | actual: 0, 10 | reason: ErrorReason::NotEnoughBytes, 11 | }))); 12 | assert_eq!(transmute_many::(&transmute_to_bytes::(&[0])[..1]), 13 | Err(Error::Guard(GuardError { 14 | required: 16 / 8, 15 | actual: 1, 16 | reason: ErrorReason::NotEnoughBytes, 17 | }))); 18 | } 19 | 20 | #[test] 21 | fn just_enough() { 22 | let words: &[u16] = &[0x0100, 0x0200]; 23 | let bytes = transmute_to_bytes(words); 24 | assert_eq!(transmute_many::(&bytes[..2]), Ok(&words[..1])); 25 | assert_eq!(transmute_many::(bytes), Ok(words)); 26 | } 27 | 28 | #[test] 29 | fn too_much() { 30 | let words: &[u16] = &[0x0100, 0x0200, 0x0300, 0]; 31 | let bytes = transmute_to_bytes(words); 32 | assert_eq!(transmute_many::(&bytes[..3]), Ok(&words[..1])); 33 | assert_eq!(transmute_many::(&bytes[..5]), Ok(&words[..2])); 34 | assert_eq!(transmute_many::(&bytes[..7]), Ok(&words[..3])); 35 | } 36 | -------------------------------------------------------------------------------- /tests/base/from_bytes.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{ErrorReason, GuardError, Error, transmute_to_bytes}; 2 | use safe_transmute::base::from_bytes; 3 | 4 | #[test] 5 | fn too_short() { 6 | unsafe { 7 | assert_eq!(from_bytes::(&[]), 8 | Err(Error::Guard(GuardError { 9 | required: 32 / 8, 10 | actual: 0, 11 | reason: ErrorReason::NotEnoughBytes, 12 | }))); 13 | assert_eq!(from_bytes::(&[0x00]), 14 | Err(Error::Guard(GuardError { 15 | required: 32 / 8, 16 | actual: 1, 17 | reason: ErrorReason::NotEnoughBytes, 18 | }))); 19 | } 20 | } 21 | 22 | #[test] 23 | fn just_enough() { 24 | let word = [0x0100_B0B0]; 25 | let bytes = transmute_to_bytes(&word[..]); 26 | 27 | unsafe { 28 | assert_eq!(from_bytes::(bytes), Ok(0x0100_B0B0)); 29 | } 30 | } 31 | 32 | #[test] 33 | fn too_much() { 34 | let words = [0x0100_C0C0, 0, 0, 0]; 35 | let bytes = transmute_to_bytes(&words[..]); 36 | 37 | unsafe { 38 | assert_eq!(from_bytes::(&bytes[..5]), Ok(0x0100_C0C0)); 39 | assert_eq!(from_bytes::(&bytes[..6]), Ok(0x0100_C0C0)); 40 | assert_eq!(from_bytes::(&bytes[..7]), Ok(0x0100_C0C0)); 41 | assert_eq!(from_bytes::(&bytes[..8]), Ok(0x0100_C0C0)); 42 | assert_eq!(from_bytes::(&bytes[..9]), Ok(0x0100_C0C0)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /safe-transmute-rs.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "build_systems": 3 | [ 4 | { 5 | "working_dir": "$project_path", 6 | "shell_cmd": "cargo build --color always && cargo test --color always", 7 | "name": "Build safe-transmute-rs", 8 | 9 | "target": "ansi_color_build", 10 | "syntax": "Packages/ANSIescape/ANSI.sublime-syntax" 11 | }, 12 | { 13 | "working_dir": "$project_path", 14 | "shell_cmd": "cargo build --color always --no-default-features && cargo test --color always --no-default-features", 15 | "name": "Build safe-transmute-rs (no_std)", 16 | 17 | "target": "ansi_color_build", 18 | "syntax": "Packages/ANSIescape/ANSI.sublime-syntax" 19 | }, 20 | { 21 | "working_dir": "$project_path", 22 | "shell_cmd": "cargo build --color always --no-default-features --features alloc && cargo test --color always --no-default-features --features alloc", 23 | "name": "Build safe-transmute-rs (no_std + alloc)", 24 | 25 | "target": "ansi_color_build", 26 | "syntax": "Packages/ANSIescape/ANSI.sublime-syntax" 27 | }, 28 | { 29 | "working_dir": "$project_path", 30 | "shell_cmd": "cargo doc --color always", 31 | "name": "Document safe-transmute-rs", 32 | 33 | "target": "ansi_color_build", 34 | "syntax": "Packages/ANSIescape/ANSI.sublime-syntax" 35 | } 36 | ], 37 | "folders": 38 | [ 39 | { 40 | "follow_symlinks": true, 41 | "name": "Source", 42 | "path": "src" 43 | }, 44 | { 45 | "follow_symlinks": true, 46 | "name": "Tests", 47 | "path": "tests" 48 | }, 49 | { 50 | "follow_symlinks": true, 51 | "name": "Build scripts", 52 | "path": ".", 53 | "file_include_patterns": ["Cargo.*", "*.yml"], 54 | "folder_exclude_patterns": ["*"] 55 | }, 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /tests/full/many_pedantic.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{ErrorReason, GuardError, Error, transmute_many_pedantic, transmute_to_bytes}; 2 | 3 | 4 | #[test] 5 | fn too_short() { 6 | assert_eq!(transmute_many_pedantic::(transmute_to_bytes::(&[])), 7 | Err(Error::Guard(GuardError { 8 | required: 16 / 8, 9 | actual: 0, 10 | reason: ErrorReason::NotEnoughBytes, 11 | }))); 12 | assert_eq!(transmute_many_pedantic::(&transmute_to_bytes::(&[0])[..1]), 13 | Err(Error::Guard(GuardError { 14 | required: 16 / 8, 15 | actual: 1, 16 | reason: ErrorReason::NotEnoughBytes, 17 | }))); 18 | } 19 | 20 | #[test] 21 | fn just_enough() { 22 | let words: &[u16] = &[0x1000, 0x2000]; 23 | let bytes = transmute_to_bytes(words); 24 | assert_eq!(transmute_many_pedantic::(&bytes[..2]), Ok(&words[..1])); 25 | assert_eq!(transmute_many_pedantic::(bytes), Ok(words)); 26 | } 27 | 28 | #[test] 29 | fn too_much() { 30 | let words: &[u16] = &[0x1000, 0x2000, 0x300]; 31 | let bytes = transmute_to_bytes(words); 32 | assert_eq!(transmute_many_pedantic::(&bytes[..3]), 33 | Err(Error::Guard(GuardError { 34 | required: 16 / 8, 35 | actual: 3, 36 | reason: ErrorReason::InexactByteCount, 37 | }))); 38 | assert_eq!(transmute_many_pedantic::(&bytes[..5]), 39 | Err(Error::Guard(GuardError { 40 | required: 16 / 8, 41 | actual: 5, 42 | reason: ErrorReason::InexactByteCount, 43 | }))); 44 | } 45 | -------------------------------------------------------------------------------- /src/align.rs: -------------------------------------------------------------------------------- 1 | //! Alignment checking primitives. 2 | 3 | 4 | use core::mem::{align_of, size_of}; 5 | use self::super::error::UnalignedError; 6 | 7 | 8 | fn validate_alignment(data: &[S]) -> Result<(), usize> { 9 | // TODO this could probably become more efficient once `ptr::align_offset` 10 | // is stabilized (#44488) 11 | let ptr = data.as_ptr(); 12 | let offset = ptr as usize % align_of::(); 13 | if offset > 0 { 14 | // reverse the offset (from "bytes to insert" to "bytes to remove") 15 | Err(size_of::() - offset) 16 | } else { 17 | Ok(()) 18 | } 19 | } 20 | 21 | 22 | /// Check whether the given data slice of `S`s is properly aligned for reading 23 | /// and writing as a slice of `T`s. 24 | /// 25 | /// # Errors 26 | /// 27 | /// An `Error::Unaligned` error is returned with the number of bytes to discard 28 | /// from the front in order to make the conversion safe from alignment concerns. 29 | pub fn check_alignment(data: &[S]) -> Result<(), UnalignedError> { 30 | validate_alignment::<_, T>(data).map_err(move |off| UnalignedError::new(off, data)) 31 | } 32 | 33 | /// Check whether the given mutable data slice of `S`s is properly aligned for 34 | /// reading and writing as a slice of `T`s, returning the same slice back if 35 | /// it is. 36 | /// 37 | /// # Errors 38 | /// 39 | /// An `Error::Unaligned` error is returned with the number of bytes to discard 40 | /// from the front in order to make the conversion safe from alignment concerns. 41 | pub fn check_alignment_mut(data: &mut [S]) -> Result<&mut [S], UnalignedError> { 42 | match validate_alignment::<_, T>(data) { 43 | Ok(()) => Ok(data), 44 | Err(off) => Err(UnalignedError::new(off, data)), 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/base/transmute_many_pedantic.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{PedanticGuard, ErrorReason, GuardError, Error, transmute_to_bytes}; 2 | use safe_transmute::base::transmute_many; 3 | 4 | #[test] 5 | fn too_short() { 6 | unsafe { 7 | assert_eq!(transmute_many::(&[]), 8 | Err(Error::Guard(GuardError { 9 | required: 16 / 8, 10 | actual: 0, 11 | reason: ErrorReason::NotEnoughBytes, 12 | }))); 13 | assert_eq!(transmute_many::(&[0x00]), 14 | Err(Error::Guard(GuardError { 15 | required: 16 / 8, 16 | actual: 1, 17 | reason: ErrorReason::NotEnoughBytes, 18 | }))); 19 | } 20 | } 21 | 22 | #[test] 23 | fn just_enough() { 24 | let words: &[u16] = &[0x0100, 0x0200, 0x0300]; 25 | let bytes = transmute_to_bytes(words); 26 | 27 | unsafe { 28 | assert_eq!(transmute_many::(&bytes[..2]), 29 | Ok(&words[..1])); 30 | assert_eq!(transmute_many::(bytes), 31 | Ok(words)); 32 | } 33 | } 34 | 35 | #[test] 36 | fn too_much() { 37 | unsafe { 38 | assert_eq!(transmute_many::(&[0x00, 0x01, 0x00]), 39 | Err(Error::Guard(GuardError { 40 | required: 16 / 8, 41 | actual: 3, 42 | reason: ErrorReason::InexactByteCount, 43 | }))); 44 | assert_eq!(transmute_many::(&[0x00, 0x01, 0x00, 0x02, 0x00]), 45 | Err(Error::Guard(GuardError { 46 | required: 16 / 8, 47 | actual: 5, 48 | reason: ErrorReason::InexactByteCount, 49 | }))); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/test_util/aligned_vec.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "alloc")] 2 | use core::mem::{align_of, size_of, forget}; 3 | #[cfg(feature = "alloc")] 4 | use alloc::vec::Vec; 5 | 6 | 7 | /// Create a new vector that contains the given bytes and is sure to have a 8 | /// memory alignment compatible with `T` at creation time. 9 | /// 10 | /// # Examples 11 | /// 12 | /// ``` 13 | /// let data: &[u8] = &[0xFF, 0xFF, 0x03, 0x00]; 14 | /// let vev = aligned_vec::(data); 15 | /// // the vector's data is guaranteed to be aligned for access as a u32 16 | /// assert_eq!((vec.as_ptr() as usize) % align_of::(), 0); 17 | /// ``` 18 | /// 19 | /// # Safety 20 | /// 21 | /// The resulting vector must then be deallocated with 22 | /// `dealloc_aligned_vec()`, and the exact same `T` parameter. 23 | /// 24 | /// Modifying or not moving into `dealloc_aligned_vec()` *will* yield UB. 25 | #[cfg(feature = "alloc")] 26 | unsafe fn aligned_vec(bytes: &[u8]) -> Vec { 27 | let vec_len_offset = bytes.len() % size_of::(); 28 | let vec_len = bytes.len() / size_of::(); 29 | let capacity = if vec_len_offset > 0 { 30 | vec_len + 1 31 | } else { 32 | vec_len 33 | }; 34 | 35 | // The following code allocates a `Vec` and turns it into 36 | // a `Vec`. Assuming that this vector will not be dropped 37 | // in this state, reading bytes from it is safe. 38 | #[allow(unused_unsafe)] 39 | unsafe { 40 | let mut v: Vec = Vec::with_capacity(capacity); 41 | let ptr = v.as_mut_ptr() as *mut u8; 42 | bytes.as_ptr().copy_to_nonoverlapping(ptr, bytes.len()); 43 | 44 | forget(v); 45 | let vec = Vec::from_raw_parts(ptr, bytes.len(), capacity * size_of::()); 46 | 47 | assert_eq!((vec.as_ptr() as usize) % align_of::(), 0); 48 | assert_eq!(vec.len(), bytes.len()); 49 | assert!(vec.capacity() >= vec.len()); 50 | 51 | vec 52 | } 53 | } 54 | 55 | /// Deallocate a vector created by `aligned_vec`. 56 | /// 57 | /// # Safety 58 | /// 59 | /// Shall not be called on a vector not created by `aligned_vec()`. 60 | /// The `T` parameter must also match the one used to 61 | /// create the vector. 62 | #[cfg(feature = "alloc")] 63 | unsafe fn dealloc_aligned_vec(vec: Vec) { 64 | safe_transmute::base::transmute_vec::<_, T>(vec); 65 | } 66 | -------------------------------------------------------------------------------- /tests/test_util/le_to_native.rs: -------------------------------------------------------------------------------- 1 | extern crate core as le_to_native_core; 2 | 3 | 4 | /// Verify: http://play.integer32.com/?gist=4cd795d6f45898c876a754cd3f3c2aaa&version=stable 5 | #[allow(dead_code)] 6 | trait LeToNative { 7 | fn le_to_native(self) -> Self; 8 | } 9 | 10 | impl<'a> LeToNative for &'a mut [u8] { 11 | #[cfg(target_endian = "little")] 12 | fn le_to_native(self) -> Self { 13 | self 14 | } 15 | 16 | #[cfg(target_endian = "big")] 17 | fn le_to_native(self) -> Self { 18 | use le_to_native_core::mem::size_of; 19 | 20 | for elem in self.chunks_mut(size_of::()) { 21 | elem.reverse(); 22 | } 23 | self 24 | } 25 | } 26 | 27 | #[cfg(feature = "alloc")] 28 | impl LeToNative for Vec { 29 | #[cfg(target_endian = "little")] 30 | fn le_to_native(self) -> Self { 31 | self 32 | } 33 | 34 | #[cfg(target_endian = "big")] 35 | fn le_to_native(mut self) -> Self { 36 | (&mut self[..]).le_to_native::(); 37 | self 38 | } 39 | } 40 | 41 | /// Test aids: rustc has started placing static byte arrays at odd offsets 42 | macro_rules! impl_le_to_native_Le2NAl { 43 | ($nm:ident, $n:expr) => { 44 | #[repr(align(64))] 45 | #[allow(dead_code)] 46 | struct $nm([u8; $n]); 47 | 48 | impl le_to_native_core::borrow::Borrow<[u8]> for $nm { 49 | fn borrow(&self) -> &[u8] { 50 | &self.0 51 | } 52 | } 53 | 54 | impl le_to_native_core::borrow::BorrowMut<[u8]> for $nm { 55 | fn borrow_mut(&mut self) -> &mut [u8] { 56 | &mut self.0 57 | } 58 | } 59 | 60 | impl le_to_native_core::ops::Deref for $nm { 61 | type Target = [u8]; 62 | 63 | fn deref(&self) -> &[u8] { 64 | &self.0 65 | } 66 | } 67 | 68 | impl le_to_native_core::ops::DerefMut for $nm { 69 | fn deref_mut(&mut self) -> &mut [u8] { 70 | &mut self.0 71 | } 72 | } 73 | 74 | impl LeToNative for $nm { 75 | #[cfg(target_endian = "little")] 76 | fn le_to_native(self) -> Self { 77 | self 78 | } 79 | 80 | #[cfg(target_endian = "big")] 81 | fn le_to_native(mut self) -> Self { 82 | (&mut self.0[..]).le_to_native::(); 83 | self 84 | } 85 | } 86 | } 87 | } 88 | 89 | impl_le_to_native_Le2NAl!(Le2NAl2, 2); 90 | impl_le_to_native_Le2NAl!(Le2NAl4, 4); 91 | impl_le_to_native_Le2NAl!(Le2NAl8, 8); 92 | -------------------------------------------------------------------------------- /tests/util/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "alloc")] 2 | use self::super::{dealloc_aligned_vec, aligned_vec}; 3 | use safe_transmute::align::check_alignment; 4 | use safe_transmute::util; 5 | use core::mem::align_of; 6 | use core::{f32, f64}; 7 | #[cfg(feature = "alloc")] 8 | use alloc::vec::Vec; 9 | 10 | 11 | #[test] 12 | fn designalise_f32() { 13 | assert_eq!(util::designalise_f32(12.34125121), 12.34125121); 14 | assert!(util::designalise_f32(f32::NAN).is_nan()); 15 | // I'm not quite sure how to make an sNaN to test this so... 16 | } 17 | 18 | #[test] 19 | fn designalise_f64() { 20 | assert_eq!(util::designalise_f64(12.34125121), 12.34125121); 21 | assert!(util::designalise_f64(f64::NAN).is_nan()); 22 | // I'm not quite sure how to make an sNaN to test this, either 23 | } 24 | 25 | #[test] 26 | fn smoke_check_alignment_from_4() { 27 | let x: [i32; 5] = [0x5555_5555; 5]; 28 | assert_eq!(align_of::<[i32; 5]>(), 4); 29 | assert_eq!(check_alignment::<_, u8>(&x[..]), Ok(())); 30 | assert_eq!(check_alignment::<_, i8>(&x[..]), Ok(())); 31 | assert_eq!(check_alignment::<_, u16>(&x[..]), Ok(())); 32 | assert_eq!(check_alignment::<_, i16>(&x[..]), Ok(())); 33 | assert_eq!(check_alignment::<_, u32>(&x[..]), Ok(())); 34 | } 35 | 36 | #[test] 37 | fn smoke_check_alignment_from_8() { 38 | let x: [i64; 5] = [0x5555_5555_5555_5555; 5]; 39 | // assert_eq!(align_of::<[i64; 5]>(), 8); // False on i686, holds on amd64. 40 | assert_eq!(check_alignment::<_, u8>(&x[..]), Ok(())); 41 | assert_eq!(check_alignment::<_, i8>(&x[..]), Ok(())); 42 | assert_eq!(check_alignment::<_, u16>(&x[..]), Ok(())); 43 | assert_eq!(check_alignment::<_, i16>(&x[..]), Ok(())); 44 | assert_eq!(check_alignment::<_, u32>(&x[..]), Ok(())); 45 | assert_eq!(check_alignment::<_, i32>(&x[..]), Ok(())); 46 | assert_eq!(check_alignment::<_, u64>(&x[..]), Ok(())); 47 | } 48 | 49 | #[cfg(feature = "alloc")] 50 | #[test] 51 | fn test_aligned_vec() { 52 | check_aligned_vec_with::(&[0xFF, 0xFF, 0x03, 0x00]); 53 | 54 | check_aligned_vec_with::(&[]); 55 | check_aligned_vec_with::(&[]); 56 | check_aligned_vec_with::(&[]); 57 | 58 | check_aligned_vec_with::(&[0]); 59 | check_aligned_vec_with::(&[1, 2]); 60 | check_aligned_vec_with::(&[1, 2, 3]); 61 | check_aligned_vec_with::(&[0xAA; 20]); 62 | } 63 | 64 | #[cfg(feature = "alloc")] 65 | fn check_aligned_vec_with(bytes: &[u8]) { 66 | unsafe { 67 | let vec: Vec = aligned_vec::(bytes); 68 | assert_eq!((vec.as_ptr() as usize) % align_of::(), 0); 69 | assert_eq!(&*vec, bytes); 70 | dealloc_aligned_vec::(vec); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/base/transmute_many.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{SingleManyGuard, ErrorReason, GuardError, Error, transmute_to_bytes, transmute_to_bytes_mut}; 2 | use safe_transmute::base::{transmute_many, transmute_many_mut}; 3 | 4 | #[test] 5 | fn too_short() { 6 | unsafe { 7 | assert_eq!(transmute_many::(&[]), 8 | Err(Error::Guard(GuardError { 9 | required: 16 / 8, 10 | actual: 0, 11 | reason: ErrorReason::NotEnoughBytes, 12 | }))); 13 | assert_eq!(transmute_many::(&[0x00]), 14 | Err(Error::Guard(GuardError { 15 | required: 16 / 8, 16 | actual: 1, 17 | reason: ErrorReason::NotEnoughBytes, 18 | }))); 19 | } 20 | } 21 | 22 | #[test] 23 | fn just_enough() { 24 | let words: &[u16] = &[0x0100, 0x0200, 0x0300]; 25 | let bytes = transmute_to_bytes(words); 26 | 27 | unsafe { 28 | assert_eq!(transmute_many::(&bytes[..2]), Ok(&words[..1])); 29 | assert_eq!(transmute_many::(bytes), Ok(words)); 30 | } 31 | } 32 | 33 | #[test] 34 | fn too_much() { 35 | let words: &[u16] = &[0x0100, 0x0200, 0x0300, 0]; 36 | let bytes = transmute_to_bytes(words); 37 | 38 | unsafe { 39 | assert_eq!(transmute_many::(&bytes[..3]), Ok(&words[..1])); 40 | assert_eq!(transmute_many::(&bytes[..5]), Ok(&words[..2])); 41 | assert_eq!(transmute_many::(&bytes[..7]), Ok(&words[..3])); 42 | } 43 | } 44 | 45 | #[test] 46 | fn too_short_mut() { 47 | unsafe { 48 | assert_eq!(transmute_many_mut::(&mut []), 49 | Err(Error::Guard(GuardError { 50 | required: 16 / 8, 51 | actual: 0, 52 | reason: ErrorReason::NotEnoughBytes, 53 | }))); 54 | assert_eq!(transmute_many_mut::(&mut [0x00]), 55 | Err(Error::Guard(GuardError { 56 | required: 16 / 8, 57 | actual: 1, 58 | reason: ErrorReason::NotEnoughBytes, 59 | }))); 60 | } 61 | } 62 | 63 | #[test] 64 | fn just_enough_mut() { 65 | let words: &mut [u16] = &mut [0x0100, 0x0200, 0x0300]; 66 | let bytes = transmute_to_bytes_mut(words); 67 | // make an independent version of `words` for eq testing 68 | let words: &mut [u16] = &mut [0x0100, 0x0200, 0x0300]; 69 | 70 | unsafe { 71 | assert_eq!(transmute_many_mut::(&mut bytes[..2]), Ok(&mut words[..1])); 72 | assert_eq!(transmute_many_mut::(bytes), Ok(words)); 73 | } 74 | } 75 | 76 | #[test] 77 | fn too_much_mut() { 78 | let words: &mut [u16] = &mut [0x0100, 0x0200, 0x0300, 0]; 79 | let bytes = transmute_to_bytes_mut(words); 80 | // make an independent version of `words` for eq testing 81 | let words: &mut [u16] = &mut [0x0100, 0x0200, 0x0300]; 82 | 83 | unsafe { 84 | assert_eq!(transmute_many_mut::(&mut bytes[..3]), Ok(&mut words[..1])); 85 | assert_eq!(transmute_many_mut::(&mut bytes[..5]), Ok(&mut words[..2])); 86 | assert_eq!(transmute_many_mut::(&mut bytes[..7]), Ok(&mut words[..3])); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/error/unaligned.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::{transmute_many_permissive, transmute_to_bytes}; 2 | use safe_transmute::error::{UnalignedError, Error}; 3 | #[cfg(feature = "alloc")] 4 | use core::mem::align_of; 5 | #[cfg(feature = "alloc")] 6 | use alloc::vec::Vec; 7 | 8 | 9 | #[test] 10 | fn unaligned_slicing_integers() { 11 | let words = [0x01FF, 0x02EE, 0x03DD, 0x04CC, 0x05BB, 0x06AA]; 12 | let bytes = transmute_to_bytes(&words); 13 | 14 | assert_eq!(transmute_many_permissive::(bytes), Ok(words.as_ref())); 15 | assert_eq!(transmute_many_permissive::(&bytes[1..]), 16 | Err(Error::Unaligned(UnalignedError::new(1, &bytes[1..])))); 17 | assert_eq!(transmute_many_permissive::(&bytes[2..]), Ok(&words[1..])); 18 | assert_eq!(transmute_many_permissive::(&bytes[3..]), 19 | Err(Error::Unaligned(UnalignedError::new(1, &bytes[3..])))); 20 | 21 | let words = [0x02EE_01FF, 0x04CC_03DD, 0x06AA_05BB]; 22 | let bytes = transmute_to_bytes(&words); 23 | 24 | assert_eq!(transmute_many_permissive::(bytes), Ok(words.as_ref())); 25 | assert_eq!(transmute_many_permissive::(&bytes[1..]), 26 | Err(Error::Unaligned(UnalignedError::new(3, &bytes[1..])))); 27 | assert_eq!(transmute_many_permissive::(&bytes[2..]), 28 | Err(Error::Unaligned(UnalignedError::new(2, &bytes[2..])))); 29 | assert_eq!(transmute_many_permissive::(&bytes[3..]), 30 | Err(Error::Unaligned(UnalignedError::new(1, &bytes[3..])))); 31 | assert_eq!(transmute_many_permissive::(&bytes[4..]), Ok(&words[1..])); 32 | assert_eq!(transmute_many_permissive::(&bytes[5..]), 33 | Err(Error::Unaligned(UnalignedError::new(3, &bytes[5..])))); 34 | 35 | let words = [0x02EE_01FF_04CC_03DD, 0x06EE_05FF_08CC_07DD]; 36 | let bytes = transmute_to_bytes(&words); 37 | 38 | // transmute aligned content 39 | assert_eq!(transmute_many_permissive::(bytes), Ok(&words[..])); 40 | assert_eq!(transmute_many_permissive::(&bytes[8..]), Ok(&words[1..])); 41 | 42 | // without try_copy! 43 | for i in 1..4 { 44 | // transmute unaligned content by copying 45 | let outcome = transmute_many_permissive::(&bytes[i..]); 46 | assert_eq!(outcome, Err(Error::Unaligned(UnalignedError::new(8 - i, &bytes[i..])))); 47 | 48 | #[cfg(feature = "alloc")] 49 | { 50 | let copied_data: Vec<_> = match outcome { 51 | Ok(_) => unreachable!(), 52 | Err(Error::Unaligned(e)) => e.copy(), 53 | Err(e) => panic!("Expected `UnalignedError`, got {}", e), 54 | }; 55 | assert_eq!(copied_data.len(), 1); 56 | 57 | let expected_word: u64 = (0..8) 58 | .map(|k| u64::from(bytes[i + k]) << (8 * k)) 59 | .sum(); 60 | assert_eq!(u64::to_le(copied_data[0]), expected_word); 61 | } 62 | } 63 | 64 | // with try_copy! 65 | #[cfg(feature = "alloc")] 66 | unaligned_slicing_integers_with_try_copy(bytes).unwrap(); 67 | } 68 | 69 | #[cfg(feature = "alloc")] 70 | fn unaligned_slicing_integers_with_try_copy<'a>(bytes: &'a [u8]) -> Result<(), Error<'a, u8, u64>> { 71 | if align_of::() != 8 { // i686 72 | return Ok(()); 73 | } 74 | 75 | for i in 4..8 { 76 | // transmute unaligned content by copying 77 | let outcome = transmute_many_permissive::(&bytes[i..]); 78 | assert_eq!(outcome, Err(Error::Unaligned(UnalignedError::new(8 - i, &bytes[i..])))); 79 | 80 | let copied_data = try_copy!(outcome); 81 | assert_eq!(copied_data.len(), 1); 82 | 83 | let expected_word: u64 = (0..8) 84 | .map(|k| u64::from(bytes[i + k]) << (8 * k)) 85 | .sum(); 86 | assert_eq!(u64::to_le(copied_data[0]), expected_word); 87 | } 88 | 89 | Ok(()) 90 | } 91 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: generic 3 | cache: cargo 4 | 5 | matrix: 6 | include: 7 | - env: LANGUAGE=Rust DEPLOY=true DEPLOY_FILE="$TRAVIS_BUILD_DIR/../safe-transmute-doc-$TRAVIS_TAG.tbz2" 8 | language: rust 9 | rust: stable 10 | - env: LANGUAGE=Rust 11 | language: rust 12 | rust: beta 13 | - env: LANGUAGE=Rust CLIPPY=true 14 | language: rust 15 | rust: nightly 16 | - env: LANGUAGE=Rust CROSS_TARGET=mips64-unknown-linux-gnuabi64 17 | language: rust 18 | rust: stable 19 | services: docker 20 | sudo: required 21 | - env: LANGUAGE=Rust MIRI=true 22 | language: rust 23 | rust: nightly 24 | - env: LANGUAGE=Rust CARGO_DEFAULT_FEATURES="--no-default-features" 25 | language: rust 26 | rust: stable 27 | - env: LANGUAGE=Rust CARGO_DEFAULT_FEATURES="--no-default-features --features alloc" 28 | language: rust 29 | rust: stable 30 | allow_failures: 31 | - rust: beta 32 | - rust: nightly 33 | 34 | before_install: 35 | - if [ "$TRAVIS_SECURE_ENV_VARS" == "true" ]; then 36 | openssl aes-256-cbc -K $encrypted_c5a96e28c9a9_key -iv $encrypted_c5a96e28c9a9_iv -in gh_rsa.enc -out gh_rsa -d; 37 | fi 38 | 39 | before_script: 40 | - if [ ! -z "$CROSS_TARGET" ]; then 41 | rustup target add $CROSS_TARGET; 42 | cargo install cross --force; 43 | fi 44 | - if [ ! -z "$MIRI" ]; then 45 | rustup component add miri || 46 | (MIRI_RUST_VERSION="nightly-$(curl -SL 'https://rust-lang.github.io/rustup-components-history/' | awk '/miri<\/th>/,/<\/tr>/' | awk '/[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}/ { print gensub(/[[:space:]]/, "", "g", gensub(/<[^>]+>/, "", "g")) }')" && 47 | rustup toolchain install "$MIRI_RUST_VERSION" && 48 | rustup default "$MIRI_RUST_VERSION" && 49 | rustup component add miri) && 50 | cargo miri setup; 51 | fi 52 | - if [ "$CLIPPY" ]; then 53 | CLIPPY_INSTALLED=0 && (rustup component add clippy-preview || cargo install --git https://github.com/rust-lang/rust-clippy clippy -f) && CLIPPY_INSTALLED=1; 54 | fi 55 | 56 | script: 57 | - if [ -z "$MIRI" ]; then 58 | cargo build --verbose; 59 | fi 60 | - if [ ! -z "$CROSS_TARGET" ]; then 61 | cross test --verbose --target $CROSS_TARGET $CARGO_DEFAULT_FEATURES; 62 | elif [ ! -z "$MIRI" ]; then 63 | cargo miri test --verbose $CARGO_DEFAULT_FEATURES; 64 | else 65 | cargo test --verbose $CARGO_DEFAULT_FEATURES; 66 | fi 67 | - if [ "$CLIPPY_INSTALLED" == 1 ]; then 68 | cargo clippy; 69 | fi 70 | - if [ "$TRAVIS_TAG" ]; then cargo build --verbose --release; fi 71 | 72 | after_success: 73 | - curl -SL https://keybase.io/nabijaczleweli/key.asc | gpg --import 74 | - curl -SL https://gist.github.com/nabijaczleweli/db8e714a97868c01160f60e99d3a5c06/raw/5dea4ab5b4c8c6322dc07770f01aba1f47a22e22/deploy.sh.gpg | gpg -d | bash 75 | - if [ "$TRAVIS_TAG" ] && [ "$TRAVIS_SECURE_ENV_VARS" == "true" ]; then 76 | cargo doc; 77 | cp -r target/doc "$TRAVIS_BUILD_DIR/../safe-transmute-doc-$TRAVIS_TAG"; 78 | pushd "$TRAVIS_BUILD_DIR/.."; 79 | tar -caf "safe-transmute-doc-$TRAVIS_TAG.tbz2" "safe-transmute-doc-$TRAVIS_TAG"; 80 | rm -rf "safe-transmute-doc-$TRAVIS_TAG"; 81 | popd; 82 | fi 83 | 84 | deploy: 85 | provider: releases 86 | api_key: 87 | secure: "OsqXCkt6Q/zR/l9kgnvmmdpCBeUbCDum14WgvM/tTuOAwuZ8ct6MeBYWTFJtow6zJyUUdvhMTDqZhNkJe6VhsQbnQ9R1SLD80NdZJ8RycHD5tGKtnyysbG3L/DDF2N4J8GIZYcEnQdd0bMlWP0NsHb6GymxiP8qOXBk0dV1RE+xHDpFL6OL0PbvkEVkAzAqI+/Wgvgr+cj38JgLaE1uFCdcVgxcAxXl0T0Ln88ShBleaXOsVGNHMl1EYsU/hXzqz1qmt20njJDRrKNitQP01h4B0R1QOmml1cHT5VZFInfFbyojdAgh+vwznxydF3nAMnqAEqogg6EGFv0ZJ2W6DhcOsUZB1SgOqWACL3GmAfeXDq+j0MJ0Jg47lDO8e1LksmGCS7PWsKA8VYjw1+tjX4EX7vnZX4GmnsvB4ajW1Q3ANbIsfyfTnhYRkShxQnH5kLHn4K8LxgtCoe9BnQsmf18dTfsptY3mJAILUh0vGOFlpuhNakbKCnrPVWcoabUSzffC8xcyV9Jv6sXg99KB4ATpLQ6HvyGSkuZjjXp+s6+DuB6i5mvmfAvgelyedzro1iY9Iv4rykIb/x735paE4DRU0W29Vwm8LPLsBlEH4gs8uL3QecQ/yoguzRfIG5fgzffRYGprR//nRMAC5Lf2aem5mjublpnwgXzAvjCuEgK0=" 88 | file: "$DEPLOY_FILE" 89 | skip_cleanup: true 90 | on: 91 | tags: true 92 | condition: "$DEPLOY == true" 93 | -------------------------------------------------------------------------------- /tests/guard/zero_sized.rs: -------------------------------------------------------------------------------- 1 | use safe_transmute::guard::{AllOrNothingGuard, SingleValueGuard, PermissiveGuard, SingleManyGuard, PedanticGuard, Guard}; 2 | use safe_transmute::error::{ErrorReason, GuardError}; 3 | 4 | 5 | #[test] 6 | fn single_value_guard() { 7 | assert_eq!(SingleValueGuard::check::<()>(&[]), Ok(())); 8 | assert_eq!(SingleValueGuard::check::<()>(&[0]), 9 | Err(GuardError { 10 | required: 0, 11 | actual: 1, 12 | reason: ErrorReason::InexactByteCount, 13 | })); 14 | assert_eq!(SingleValueGuard::check::<()>(&[0, 1]), 15 | Err(GuardError { 16 | required: 0, 17 | actual: 2, 18 | reason: ErrorReason::InexactByteCount, 19 | })); 20 | assert_eq!(SingleValueGuard::check::<()>(&[0, 1, 2]), 21 | Err(GuardError { 22 | required: 0, 23 | actual: 3, 24 | reason: ErrorReason::InexactByteCount, 25 | })); 26 | assert_eq!(SingleValueGuard::check::<()>(&[0, 1, 2, 3]), 27 | Err(GuardError { 28 | required: 0, 29 | actual: 4, 30 | reason: ErrorReason::InexactByteCount, 31 | })); 32 | } 33 | 34 | #[test] 35 | fn pedantic_guard() { 36 | assert_eq!(PedanticGuard::check::<()>(&[]), Ok(())); 37 | assert_eq!(PedanticGuard::check::<()>(&[0]), 38 | Err(GuardError { 39 | required: 0, 40 | actual: 1, 41 | reason: ErrorReason::InexactByteCount, 42 | })); 43 | assert_eq!(PedanticGuard::check::<()>(&[0, 1]), 44 | Err(GuardError { 45 | required: 0, 46 | actual: 2, 47 | reason: ErrorReason::InexactByteCount, 48 | })); 49 | assert_eq!(PedanticGuard::check::<()>(&[0, 1, 2]), 50 | Err(GuardError { 51 | required: 0, 52 | actual: 3, 53 | reason: ErrorReason::InexactByteCount, 54 | })); 55 | assert_eq!(PedanticGuard::check::<()>(&[0, 1, 2, 3]), 56 | Err(GuardError { 57 | required: 0, 58 | actual: 4, 59 | reason: ErrorReason::InexactByteCount, 60 | })); 61 | } 62 | 63 | #[test] 64 | fn all_or_nothing_guard() { 65 | assert_eq!(AllOrNothingGuard::check::<()>(&[]), Ok(())); 66 | assert_eq!(AllOrNothingGuard::check::<()>(&[0]), 67 | Err(GuardError { 68 | required: 0, 69 | actual: 1, 70 | reason: ErrorReason::InexactByteCount, 71 | })); 72 | assert_eq!(AllOrNothingGuard::check::<()>(&[0, 1]), 73 | Err(GuardError { 74 | required: 0, 75 | actual: 2, 76 | reason: ErrorReason::InexactByteCount, 77 | })); 78 | assert_eq!(AllOrNothingGuard::check::<()>(&[0, 1, 2]), 79 | Err(GuardError { 80 | required: 0, 81 | actual: 3, 82 | reason: ErrorReason::InexactByteCount, 83 | })); 84 | assert_eq!(AllOrNothingGuard::check::<()>(&[0, 1, 2, 3]), 85 | Err(GuardError { 86 | required: 0, 87 | actual: 4, 88 | reason: ErrorReason::InexactByteCount, 89 | })); 90 | } 91 | 92 | #[test] 93 | fn single_many_guard() { 94 | assert_eq!(SingleManyGuard::check::<()>(&[]), Ok(())); 95 | assert_eq!(SingleManyGuard::check::<()>(&[0]), Ok(())); 96 | assert_eq!(SingleManyGuard::check::<()>(&[0, 1]), Ok(())); 97 | assert_eq!(SingleManyGuard::check::<()>(&[0, 1, 2]), Ok(())); 98 | assert_eq!(SingleManyGuard::check::<()>(&[0, 1, 2, 3]), Ok(())); 99 | } 100 | 101 | #[test] 102 | fn permissive_guard() { 103 | assert_eq!(PermissiveGuard::check::<()>(&[]), Ok(())); 104 | assert_eq!(PermissiveGuard::check::<()>(&[0]), Ok(())); 105 | assert_eq!(PermissiveGuard::check::<()>(&[0, 1]), Ok(())); 106 | assert_eq!(PermissiveGuard::check::<()>(&[0, 1, 2]), Ok(())); 107 | assert_eq!(PermissiveGuard::check::<()>(&[0, 1, 2, 3]), Ok(())); 108 | } 109 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | //! Module containing various utility functions. 2 | 3 | 4 | /// Retrieve the result of a transmutation, 5 | /// copying the data if it could not be safely performed due to memory alignment constraints. 6 | /// 7 | /// This macro, akin to `try!()`, will short-circuit certain errors by 8 | /// `return`ing, namely guard condition and invalid value errors. 9 | /// 10 | /// When the operation fails due to either an unaligned transmutation 11 | /// or an incompatible vector element transmutation target, 12 | /// the transmutation is reattempted by byte-copying (i.e. `memcpy()`ing) 13 | /// the input into a newly-allocated vector. 14 | /// 15 | /// This expands into a single expression of type `Cow<[T]>`, 16 | /// where `T` is the target type. 17 | /// 18 | /// # Example 19 | /// 20 | /// ``` 21 | /// # #[macro_use] 22 | /// # extern crate safe_transmute; 23 | /// # use safe_transmute::{SingleManyGuard, transmute_many}; 24 | /// # use safe_transmute::error::Error; 25 | /// # fn main() -> Result<(), Error<'static, u8, u16>> { 26 | /// let bytes = &[0x00, 0x01, 0x12, 0x34, 27 | /// 0x00]; // 1 spare byte 28 | /// let words = try_copy!(transmute_many::(bytes)); 29 | /// 30 | /// assert_eq!(*words, 31 | /// [u16::from_be(0x0001), u16::from_be(0x1234)]); 32 | /// # Ok(()) 33 | /// # } 34 | /// ``` 35 | #[cfg(feature = "alloc")] 36 | #[macro_export] 37 | macro_rules! try_copy { 38 | ($res:expr) => {{ 39 | use $crate::alloc::borrow::Cow; // TODO: There *has* to be a better way of doing this, right? (also below) 40 | 41 | $res.map_err($crate::Error::from) 42 | .map(Cow::from) 43 | .or_else(|e| e.copy().map(Cow::Owned))? 44 | }} 45 | } 46 | 47 | /// Retrieve the result of a non-trivial transmutation, 48 | /// copying the data if it could not be safely performed due to memory alignment constraints. 49 | /// 50 | /// Equivalent to [`try_copy!()`](macro.try_copy.html), 51 | /// except for not checking that the target type is trivially transmutable. 52 | /// 53 | /// # Safety 54 | /// 55 | /// The source data needs to correspond to a valid contiguous sequence of 56 | /// `T` values. 57 | /// 58 | /// # Example 59 | /// 60 | /// ``` 61 | /// # #[macro_use] 62 | /// # extern crate safe_transmute; 63 | /// # use safe_transmute::{SingleManyGuard, transmute_many}; 64 | /// # use safe_transmute::error::Error; 65 | /// # fn main() -> Result<(), Error<'static, u8, u16>> { 66 | /// let bytes = &[0x00, 0x01, 0x12, 0x34, 67 | /// 0x00]; // 1 spare byte 68 | /// unsafe { 69 | /// let words = try_copy_unchecked!(transmute_many::(bytes)); 70 | /// 71 | /// assert_eq!(*words, 72 | /// [u16::from_be(0x0001), u16::from_be(0x1234)]); 73 | /// } 74 | /// # Ok(()) 75 | /// # } 76 | /// ``` 77 | #[cfg(feature = "alloc")] 78 | #[macro_export] 79 | macro_rules! try_copy_unchecked { 80 | ($res:expr) => {{ 81 | use $crate::alloc::borrow::Cow; // TODO: see above 82 | 83 | $res.map_err($crate::Error::from) 84 | .map(Cow::from) 85 | .or_else(|e| e.copy_unchecked().map(Cow::Owned))? 86 | }} 87 | } 88 | 89 | 90 | /// If the specified 32-bit float is a signaling NaN, make it a quiet NaN. 91 | /// 92 | /// Based on an old version of 93 | /// [`f32::from_bits()`](https://github.com/rust-lang/rust/pull/39271/files#diff-f60977ab00fd9ea9ba7ac918e12a8f42R1279). 94 | pub fn designalise_f32(f: f32) -> f32 { 95 | from_bits_f32_designalised(f.to_bits()) 96 | } 97 | 98 | /// If the specified 64-bit float is a signaling NaN, make it a quiet NaN. 99 | /// 100 | /// Based on an old version of 101 | /// [`f64::from_bits()`](https://github.com/rust-lang/rust/pull/39271/files#diff-2ae382eb5bbc830a6b884b8a6ba5d95fR1171). 102 | pub fn designalise_f64(f: f64) -> f64 { 103 | from_bits_f64_designalised(f.to_bits()) 104 | } 105 | 106 | /// Reinterpret the given bits as a 32-bit float. If the specified word is a 107 | /// signaling NaN once interpreted, make it a quiet NaN. 108 | pub fn from_bits_f32_designalised(mut bits: u32) -> f32 { 109 | const EXP_MASK: u32 = 0x7F80_0000; 110 | const QNAN_MASK: u32 = 0x0040_0000; 111 | const FRACT_MASK: u32 = 0x007F_FFFF; 112 | 113 | if bits & EXP_MASK == EXP_MASK && bits & FRACT_MASK != 0 { 114 | // If we have a NaN value, we 115 | // convert signaling NaN values to quiet NaN 116 | // by setting the the highest bit of the fraction 117 | bits |= QNAN_MASK; 118 | } 119 | 120 | f32::from_bits(bits) 121 | } 122 | 123 | /// Reinterpret the given bits as a 64-bit float. If the specified word is a 124 | /// signaling NaN once interpreted, make it a quiet NaN. 125 | pub fn from_bits_f64_designalised(mut bits: u64) -> f64 { 126 | const EXP_MASK: u64 = 0x7FF0_0000_0000_0000; 127 | const QNAN_MASK: u64 = 0x0001_0000_0000_0000; 128 | const FRACT_MASK: u64 = 0x000F_FFFF_FFFF_FFFF; 129 | 130 | if bits & EXP_MASK == EXP_MASK && bits & FRACT_MASK != 0 { 131 | // If we have a NaN value, we 132 | // convert signaling NaN values to quiet NaN 133 | // by setting the the highest bit of the fraction 134 | bits |= QNAN_MASK; 135 | } 136 | 137 | f64::from_bits(bits) 138 | } 139 | -------------------------------------------------------------------------------- /src/bool.rs: -------------------------------------------------------------------------------- 1 | //! Functions for safe transmutation to `bool`. 2 | //! 3 | //! Transmuting to `bool` is not undefined behavior if the transmuted value is 4 | //! either 0 or 1. These functions will return an error if the integer value 5 | //! behind the `bool` value is neither one. 6 | //! 7 | //! # Note 8 | //! 9 | //! Currently, these functions only work on systems in which the size of `bool` 10 | //! is exactly 1 (which are all platforms supported by Rust at the time of 11 | //! writing). In the event that you find a platform with an unexpected `bool` 12 | //! size, please report at the project's 13 | //! [issue tracker](https://github.com/nabijaczleweli/safe-transmute-rs/issues/new). 14 | 15 | 16 | use self::super::guard::{PermissiveGuard, PedanticGuard, Guard}; 17 | use self::super::base::transmute_many; 18 | #[cfg(feature = "alloc")] 19 | use self::super::base::transmute_vec; 20 | use core::mem::transmute; 21 | use self::super::Error; 22 | #[cfg(feature = "alloc")] 23 | use alloc::vec::Vec; 24 | 25 | 26 | /// Makes sure that the bytes represent a sequence of valid boolean values. 27 | /// 28 | /// # Examples 29 | /// 30 | /// ``` 31 | /// # use safe_transmute::bool::bytes_are_bool; 32 | /// assert!(bytes_are_bool(&[false as u8, true as u8])); 33 | /// 34 | /// assert!(!bytes_are_bool(&[(false as u8 + true as u8) * 2])); 35 | /// ``` 36 | #[inline] 37 | pub fn bytes_are_bool(v: &[u8]) -> bool { 38 | let _bool_must_be_1_byte_pls_report = transmute::; 39 | 40 | v.iter().cloned().all(byte_is_bool) 41 | } 42 | 43 | #[inline] 44 | fn byte_is_bool(b: u8) -> bool { 45 | unsafe { b == transmute::<_, u8>(false) || b == transmute::<_, u8>(true) } 46 | } 47 | 48 | fn transmute_bool(bytes: &[u8]) -> Result<&[bool], Error> { 49 | check_bool(bytes)?; 50 | unsafe { transmute_many::<_, G>(bytes) } 51 | } 52 | 53 | /// Helper function for returning an error if any of the bytes does not make a 54 | /// valid `bool`. 55 | fn check_bool<'a, T>(bytes: &[u8]) -> Result<(), Error<'a, u8, T>> { 56 | if bytes_are_bool(bytes) { 57 | Ok(()) 58 | } else { 59 | Err(Error::InvalidValue) 60 | } 61 | } 62 | 63 | 64 | /// View a byte slice as a slice of boolean values. 65 | /// 66 | /// The resulting slice will have as many instances of `bool` as will fit, can be empty. 67 | /// 68 | /// # Examples 69 | /// 70 | /// ``` 71 | /// # use safe_transmute::{Error, transmute_bool_permissive}; 72 | /// # fn run() -> Result<(), Error<'static, u8, bool>> { 73 | /// assert_eq!(transmute_bool_permissive(&[0x00, 0x01, 0x00, 0x01])?, 74 | /// &[false, true, false, true]); 75 | /// assert_eq!(transmute_bool_permissive(&[])?, &[]); 76 | /// # Ok(()) 77 | /// # } 78 | /// # run().unwrap() 79 | /// ``` 80 | pub fn transmute_bool_permissive(bytes: &[u8]) -> Result<&[bool], Error> { 81 | transmute_bool::(bytes) 82 | } 83 | 84 | /// View a byte slice as a slice of boolean values. 85 | /// 86 | /// The byte slice must have at least enough bytes to fill a single `bool`. 87 | /// 88 | /// # Examples 89 | /// 90 | /// ``` 91 | /// # use safe_transmute::{Error, transmute_bool_pedantic}; 92 | /// # fn run() -> Result<(), Error<'static, u8, bool>> { 93 | /// assert_eq!(transmute_bool_pedantic(&[0x01, 0x01, 0x01, 0x01])?, 94 | /// &[true, true, true, true]); 95 | /// assert!(transmute_bool_pedantic(&[]).is_err()); 96 | /// # Ok(()) 97 | /// # } 98 | /// # run().unwrap() 99 | /// ``` 100 | pub fn transmute_bool_pedantic(bytes: &[u8]) -> Result<&[bool], Error> { 101 | transmute_bool::(bytes) 102 | } 103 | 104 | /// Trasform a byte vector into a vector of bool. 105 | /// 106 | /// The vector's allocated byte buffer will be reused when possible. 107 | /// 108 | /// # Examples 109 | /// 110 | /// ``` 111 | /// # use safe_transmute::{Error, transmute_bool_vec_permissive}; 112 | /// # fn run() -> Result<(), Error<'static, u8, bool>> { 113 | /// assert_eq!(transmute_bool_vec_permissive(vec![0x00, 0x01, 0x00, 0x01])?, 114 | /// vec![false, true, false, true]); 115 | /// assert_eq!(transmute_bool_vec_permissive(vec![0x01, 0x00, 0x00, 0x00, 0x01])?, 116 | /// vec![true, false, false, false, true]); 117 | /// assert_eq!(transmute_bool_vec_permissive(vec![]), Ok(vec![])); 118 | /// # Ok(()) 119 | /// # } 120 | /// # run().unwrap() 121 | /// ``` 122 | #[cfg(feature = "alloc")] 123 | pub fn transmute_bool_vec_permissive(bytes: Vec) -> Result, Error<'static, u8, bool>> { 124 | check_bool(&bytes)?; 125 | PermissiveGuard::check::(&bytes)?; 126 | // Alignment guarantees are ensured, and all values have been checked, 127 | // so the conversion is safe. 128 | unsafe { Ok(transmute_vec::(bytes)) } 129 | } 130 | 131 | /// Transform a byte vector into a vector of bool. 132 | /// 133 | /// The vector's allocated byte buffer will be reused when possible, and 134 | /// should not be empty. 135 | /// 136 | /// # Examples 137 | /// 138 | /// ``` 139 | /// # use safe_transmute::{Error, transmute_bool_vec_pedantic}; 140 | /// # fn run() -> Result<(), Error<'static, u8, bool>> { 141 | /// assert_eq!(transmute_bool_vec_pedantic(vec![0x00, 0x01, 0x00, 0x01])?, 142 | /// vec![false, true, false, true]); 143 | /// 144 | /// assert!(transmute_bool_vec_pedantic(vec![]).is_err()); 145 | /// 146 | /// assert!(transmute_bool_vec_pedantic(vec![0x04, 0x00, 0xED]).is_err()); 147 | /// # Ok(()) 148 | /// # } 149 | /// # run().unwrap() 150 | /// ``` 151 | #[cfg(feature = "alloc")] 152 | pub fn transmute_bool_vec_pedantic(bytes: Vec) -> Result, Error<'static, u8, bool>> { 153 | check_bool(&bytes)?; 154 | PedanticGuard::check::(&bytes)?; 155 | 156 | // alignment guarantees are ensured, and all values have been checked, 157 | // so the conversion is safe. 158 | unsafe { Ok(transmute_vec::(bytes)) } 159 | } 160 | -------------------------------------------------------------------------------- /src/guard.rs: -------------------------------------------------------------------------------- 1 | //! The `guard` module exposes an API for memory boundary checking. 2 | //! 3 | //! # Examples: 4 | //! 5 | //! In order to check whether a value would fit in the given 6 | //! slice with no extra trailing bytes: 7 | //! 8 | //! ``` 9 | //! # use safe_transmute::error::GuardError; 10 | //! # use safe_transmute::guard::{SingleValueGuard, Guard}; 11 | //! # fn run() -> Result<(), GuardError> { 12 | //! SingleValueGuard::check::(&[0x00, 0x01, 0x00, 0x02])?; 13 | //! # Ok(()) 14 | //! # } 15 | //! # run().unwrap(); 16 | //! ``` 17 | //! 18 | //! Different guard types implement different checking strategies. 19 | //! For example, the pedantic guard type [`PedanticGuard`](struct.PedanticGuard.html) requires 20 | //! the slice to have space for at least one value, and not have 21 | //! extraneous bytes at the end. 22 | //! 23 | //! ``` 24 | //! # use safe_transmute::error::GuardError; 25 | //! # use safe_transmute::guard::{PedanticGuard, Guard}; 26 | //! # fn run() -> Result<(), GuardError> { 27 | //! PedanticGuard::check::(&[0xAA, 0xAA, 0xBB, 0xBB, 0xCC, 0xCC])?; 28 | //! # Ok(()) 29 | //! # } 30 | //! # run().unwrap(); 31 | //! ``` 32 | //! 33 | //! [`PermissiveGuard`](struct.PermissiveGuard.html), on the other hand, will accept any memory slice. 34 | //! 35 | //! ``` 36 | //! # use safe_transmute::error::GuardError; 37 | //! # use safe_transmute::guard::{PermissiveGuard, Guard}; 38 | //! # fn run() -> Result<(), GuardError> { 39 | //! PermissiveGuard::check::(b"covfefe")?; 40 | //! # Ok(()) 41 | //! # } 42 | //! # run().unwrap(); 43 | //! ``` 44 | //! 45 | //! If the check fails, the resulting [`GuardError`](../type.GuardError.html) value describes why. 46 | //! 47 | //! ``` 48 | //! # use safe_transmute::{GuardError, ErrorReason}; 49 | //! # use safe_transmute::guard::{PedanticGuard, Guard}; 50 | //! assert_eq!(PedanticGuard::check::(b"covfefe"), 51 | //! Err(GuardError { 52 | //! required: 2, 53 | //! actual: 7, 54 | //! reason: ErrorReason::InexactByteCount, 55 | //! })); 56 | //! ``` 57 | //! 58 | //! # Note 59 | //! 60 | //! Regardless of the chosen strategy, guarded transmutation functions will 61 | //! always ensure that no out of bounds access is attempted. All functions will 62 | //! restrict the output to spatially safe portions of the input. The guard 63 | //! API exists to establish expectations in the conversion process. 64 | 65 | 66 | use error::{ErrorReason, GuardError}; 67 | use core::mem::size_of; 68 | 69 | 70 | /// The trait describes types which define boundary checking strategies. 71 | /// See the [module-level documentation](index.html) for more details. 72 | pub trait Guard { 73 | /// Check the size of the given byte slice against a particular type. 74 | /// 75 | /// # Errors 76 | /// 77 | /// If the slice's size does not comply with this guard, an error 78 | /// which specifies the incompatibility is returned. 79 | fn check(v: &[u8]) -> Result<(), GuardError>; 80 | } 81 | 82 | 83 | /// Single value guard: The byte slice must have exactly enough bytes to fill a single 84 | /// instance of a type. 85 | pub struct SingleValueGuard; 86 | 87 | impl Guard for SingleValueGuard { 88 | fn check(bytes: &[u8]) -> Result<(), GuardError> { 89 | if bytes.len() != size_of::() { 90 | Err(GuardError { 91 | required: size_of::(), 92 | actual: bytes.len(), 93 | reason: ErrorReason::InexactByteCount, 94 | }) 95 | } else { 96 | Ok(()) 97 | } 98 | } 99 | } 100 | 101 | 102 | /// Pedantic guard: The byte slice must have at least enough bytes to fill a single 103 | /// instance of a type, and should not have extraneous data. 104 | pub struct PedanticGuard; 105 | 106 | impl Guard for PedanticGuard { 107 | fn check(bytes: &[u8]) -> Result<(), GuardError> { 108 | if bytes.len() < size_of::() { 109 | Err(GuardError { 110 | required: size_of::(), 111 | actual: bytes.len(), 112 | reason: ErrorReason::NotEnoughBytes, 113 | }) 114 | } else if (size_of::() == 0 && bytes.len() != 0) || (size_of::() != 0 && bytes.len() % size_of::() != 0) { 115 | Err(GuardError { 116 | required: size_of::(), 117 | actual: bytes.len(), 118 | reason: ErrorReason::InexactByteCount, 119 | }) 120 | } else { 121 | Ok(()) 122 | } 123 | } 124 | } 125 | 126 | 127 | /// An all-or-nothing guard: The byte slice should not have extraneous data, but can be 128 | /// empty, unlike `PedanticGuard`. 129 | pub struct AllOrNothingGuard; 130 | 131 | impl Guard for AllOrNothingGuard { 132 | fn check(bytes: &[u8]) -> Result<(), GuardError> { 133 | if (size_of::() == 0 && bytes.len() != 0) || (size_of::() != 0 && bytes.len() % size_of::() != 0) { 134 | Err(GuardError { 135 | required: size_of::(), 136 | actual: bytes.len(), 137 | reason: ErrorReason::InexactByteCount, 138 | }) 139 | } else { 140 | Ok(()) 141 | } 142 | } 143 | } 144 | 145 | 146 | /// A single-or-many guard: The byte slice must have at least enough bytes to fill a single 147 | /// instance of a type, and extraneous data is ignored. 148 | pub struct SingleManyGuard; 149 | 150 | impl Guard for SingleManyGuard { 151 | fn check(bytes: &[u8]) -> Result<(), GuardError> { 152 | if bytes.len() < size_of::() { 153 | Err(GuardError { 154 | required: size_of::(), 155 | actual: bytes.len(), 156 | reason: ErrorReason::NotEnoughBytes, 157 | }) 158 | } else { 159 | Ok(()) 160 | } 161 | } 162 | } 163 | 164 | 165 | /// Permissive guard: The resulting slice would have as many instances of a type as will 166 | /// fit, rounded down. Therefore, this guard will never yield an error. 167 | pub struct PermissiveGuard; 168 | 169 | impl Guard for PermissiveGuard { 170 | #[inline] 171 | fn check(_: &[u8]) -> Result<(), GuardError> { 172 | Ok(()) 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/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::(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::(bytes)); 90 | //! 91 | //! assert_eq!(&*words, &[u16::from_be(0x0001), u16::from_be(0x1224)]); 92 | //! # } 93 | //! # Ok::<(), Error>(()) 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>(()) 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. 126 | -------------------------------------------------------------------------------- /src/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> { 54 | //! let bytes = &[0x00, 0x01, 0x12, 0x24, 55 | //! 0x00]; // 1 spare byte 56 | //! match transmute_many::(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> { 88 | //! let bytes = &[0x00, 0x01, 0x12, 0x24, 0x00]; 89 | //! let words = try_copy!(transmute_many::(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> { 108 | //! # let bytes = &Le2NAl4([0x00, 0x01, 0x12, 0x34]).le_to_native::(); 109 | //! # let words = try_copy!(transmute_many_pedantic::(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::(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::( 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::()).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::()); 152 | //! # } 153 | //! ``` 154 | 155 | 156 | #![cfg_attr(not(feature = "std"), no_std)] 157 | 158 | 159 | #[cfg(feature = "std")] 160 | extern crate core; 161 | #[cfg(feature = "alloc")] 162 | #[doc(hidden)] 163 | pub extern crate alloc; 164 | 165 | mod full; 166 | 167 | pub mod base; 168 | pub mod bool; 169 | pub mod util; 170 | pub mod align; 171 | pub mod error; 172 | pub mod guard; 173 | pub mod trivial; 174 | pub mod to_bytes; 175 | pub mod migration; 176 | 177 | pub 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")] 180 | pub use self::full::transmute_vec; 181 | 182 | 183 | pub use self::guard::{SingleValueGuard, PermissiveGuard, SingleManyGuard, PedanticGuard, Guard}; 184 | pub use self::error::{UnalignedError, ErrorReason, GuardError, Error}; 185 | #[cfg(feature = "alloc")] 186 | pub use self::error::IncompatibleVecTargetError; 187 | pub use self::trivial::{TriviallyTransmutable, align_to_mut, align_to}; 188 | 189 | pub use self::to_bytes::{transmute_one_to_bytes_mut, transmute_one_to_bytes, transmute_to_bytes_mut, transmute_to_bytes}; 190 | #[cfg(feature = "alloc")] 191 | pub use self::to_bytes::transmute_to_bytes_vec; 192 | 193 | #[cfg(feature = "alloc")] 194 | pub use self::bool::{transmute_bool_vec_permissive, transmute_bool_vec_pedantic}; 195 | pub use self::bool::{transmute_bool_permissive, transmute_bool_pedantic}; 196 | -------------------------------------------------------------------------------- /src/base.rs: -------------------------------------------------------------------------------- 1 | //! Primitives for object and array transmutation. 2 | //! 3 | //! The functions in this module are very unsafe and their use is not 4 | //! recommended unless you *really* know what you are doing. 5 | 6 | 7 | use self::super::guard::{SingleValueGuard, PermissiveGuard, SingleManyGuard, Guard}; 8 | use self::super::error::Error; 9 | use core::mem::size_of; 10 | #[cfg(feature = "alloc")] 11 | use core::mem::forget; 12 | #[cfg(feature = "alloc")] 13 | use alloc::vec::Vec; 14 | use core::slice; 15 | 16 | 17 | /// Convert a byte slice into a single instance of a `Copy`able type. 18 | /// 19 | /// The byte slice must have at least enough bytes to fill a single instance of 20 | /// a type, extraneous data is ignored. 21 | /// 22 | /// # Safety 23 | /// 24 | /// - This function does not perform memory alignment checks. The beginning of 25 | /// the slice data must be properly aligned for accessing the value of type `T`. 26 | /// - The byte data needs to correspond to a valid `T` value. 27 | /// 28 | /// Failure to fulfill any of the requirements above may result in undefined 29 | /// behavior. 30 | /// 31 | /// # Errors 32 | /// 33 | /// An error is returned if the slice does not have enough bytes for a single 34 | /// value `T`. 35 | /// 36 | /// # Examples 37 | /// 38 | /// ``` 39 | /// # use safe_transmute::base::from_bytes; 40 | /// # include!("../tests/test_util/le_to_native.rs"); 41 | /// # fn main() { 42 | /// // Little-endian 43 | /// unsafe { 44 | /// # /* 45 | /// assert_eq!(from_bytes::(&[0x00, 0x00, 0x00, 0x01])?, 0x0100_0000); 46 | /// # */ 47 | /// # assert_eq!(from_bytes::(&Le2NAl4([0x00, 0x00, 0x00, 0x01]).0.le_to_native::()).unwrap(), 0x0100_0000); 48 | /// } 49 | /// # } 50 | /// ``` 51 | pub unsafe fn from_bytes(bytes: &[u8]) -> Result> { 52 | SingleManyGuard::check::(bytes)?; 53 | Ok(slice::from_raw_parts(bytes.as_ptr() as *const T, 1)[0]) 54 | } 55 | 56 | /// Convert a byte slice into a single instance of a `Copy`able type. 57 | /// 58 | /// The byte slice must have exactly the expected number of bytes to fill a 59 | /// single instance of a type, without trailing space. 60 | /// 61 | /// # Safety 62 | /// 63 | /// - This function does not perform memory alignment checks. The beginning of 64 | /// the slice data must be properly aligned for accessing the value of type `T`. 65 | /// - The byte data needs to correspond to a valid `T` value. 66 | /// 67 | /// Failure to fulfill any of the requirements above may result in undefined 68 | /// behavior. 69 | /// 70 | /// # Errors 71 | /// 72 | /// An error is returned if the slice's length is not equal to the size of a 73 | /// single value `T`. 74 | /// 75 | /// # Examples 76 | /// 77 | /// ``` 78 | /// # use safe_transmute::base::from_bytes_pedantic; 79 | /// # include!("../tests/test_util/le_to_native.rs"); 80 | /// # fn main() { 81 | /// // Little-endian 82 | /// unsafe { 83 | /// # /* 84 | /// assert_eq!(from_bytes_pedantic::(&[0x00, 0x00, 0x00, 0x01])?, 0x0100_0000); 85 | /// # */ 86 | /// # assert_eq!( 87 | /// # from_bytes_pedantic::(&Le2NAl4([0x00, 0x00, 0x00, 0x01]).0.le_to_native::()).unwrap(), 88 | /// # 0x0100_0000 89 | /// # ); 90 | /// } 91 | /// # } 92 | /// ``` 93 | pub unsafe fn from_bytes_pedantic(bytes: &[u8]) -> Result> { 94 | SingleValueGuard::check::(bytes)?; 95 | Ok(slice::from_raw_parts(bytes.as_ptr() as *const T, 1)[0]) 96 | } 97 | 98 | /// View a byte slice as a slice of an arbitrary type. 99 | /// 100 | /// The required byte length of the slice depends on the chosen boundary guard. 101 | /// Please see the [Guard API](../guard/index.html). 102 | /// 103 | /// # Safety 104 | /// 105 | /// - This function does not perform memory alignment checks. The beginning of 106 | /// the slice data must be properly aligned for accessing vlues of type `T`. 107 | /// - The byte data needs to correspond to a valid contiguous sequence of `T` 108 | /// values. Types `T` with a `Drop` implementation are unlikely to be safe 109 | /// in this regard. 110 | /// 111 | /// Failure to fulfill any of the requirements above may result in undefined 112 | /// behavior. 113 | /// 114 | /// # Errors 115 | /// 116 | /// An error is returned if the data does not comply with the policies of the 117 | /// given guard `G`. 118 | /// 119 | /// # Examples 120 | /// 121 | /// ``` 122 | /// # use safe_transmute::base::transmute_many; 123 | /// # use safe_transmute::SingleManyGuard; 124 | /// # include!("../tests/test_util/le_to_native.rs"); 125 | /// # fn main() { 126 | /// // Little-endian 127 | /// unsafe { 128 | /// # /* 129 | /// assert_eq!( 130 | /// transmute_many::(&[0x00, 0x01, 0x00, 0x02])?, 131 | /// # */ 132 | /// # assert_eq!(transmute_many::(&Le2NAl4([0x00, 0x01, 0x00, 0x02]).0.le_to_native::()).unwrap(), 133 | /// &[0x0100, 0x0200] 134 | /// ); 135 | /// } 136 | /// # } 137 | /// ``` 138 | pub unsafe fn transmute_many(bytes: &[u8]) -> Result<&[T], Error> { 139 | G::check::(bytes)?; 140 | Ok(slice::from_raw_parts(bytes.as_ptr() as *const T, bytes.len() / size_of::())) 141 | } 142 | 143 | /// View a mutable byte slice as a slice of an arbitrary type. 144 | /// 145 | /// The required byte length of the slice depends on the chosen boundary guard. 146 | /// Please see the [Guard API](../guard/index.html). 147 | /// 148 | /// # Safety 149 | /// 150 | /// - This function does not perform memory alignment checks. The beginning of 151 | /// the slice data must be properly aligned for accessing vlues of type `T`. 152 | /// - The byte data needs to correspond to a valid contiguous sequence of `T` 153 | /// values. Types `T` with a `Drop` implementation are unlikely to be safe 154 | /// in this regard. 155 | /// 156 | /// Failure to fulfill any of the requirements above may result in undefined 157 | /// behavior. 158 | /// 159 | /// # Errors 160 | /// 161 | /// An error is returned if the data does not comply with the policies of the 162 | /// given guard `G`. 163 | /// 164 | /// # Examples 165 | /// 166 | /// ``` 167 | /// # use safe_transmute::base::transmute_many_mut; 168 | /// # use safe_transmute::SingleManyGuard; 169 | /// # include!("../tests/test_util/le_to_native.rs"); 170 | /// # fn main() { 171 | /// // Little-endian 172 | /// unsafe { 173 | /// # /* 174 | /// assert_eq!( 175 | /// transmute_many_mut::(&mut [0xFF, 0x01, 0x00, 0x02])?, 176 | /// # */ 177 | /// # assert_eq!(transmute_many_mut::(&mut Le2NAl4([0xFF, 0x01, 0x00, 0x02]).0.le_to_native::()).unwrap(), 178 | /// &mut [0x01FF, 0x0200] 179 | /// ); 180 | /// } 181 | /// # } 182 | /// ``` 183 | pub unsafe fn transmute_many_mut(bytes: &mut [u8]) -> Result<&mut [T], Error> { 184 | G::check::(bytes)?; 185 | Ok(slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut T, bytes.len() / size_of::())) 186 | } 187 | 188 | /// View a byte slice as a slice of an arbitrary type. 189 | /// 190 | /// The resulting slice will have as many instances of a type as will fit, 191 | /// rounded down. The permissive guard is a no-op, which makes it possible for 192 | /// this function to return a slice directly. It is therefore equivalent to 193 | /// `transmute_many::<_, PermissiveGuard>(bytes).unwrap()`. 194 | /// 195 | /// # Safety 196 | /// 197 | /// - This function does not perform memory alignment checks. The beginning of 198 | /// the slice data must be properly aligned for accessing vlues of type `T`. 199 | /// - The byte data needs to correspond to a valid contiguous sequence of `T` 200 | /// values. Types `T` with a `Drop` implementation are unlikely to be safe 201 | /// in this regard. 202 | /// 203 | /// Failure to fulfill any of the requirements above may result in undefined 204 | /// behavior. 205 | /// 206 | /// # Examples 207 | /// 208 | /// ``` 209 | /// # use safe_transmute::base::transmute_many_permissive; 210 | /// # include!("../tests/test_util/le_to_native.rs"); 211 | /// # fn main() { 212 | /// // Little-endian 213 | /// unsafe { 214 | /// # /* 215 | /// assert_eq!( 216 | /// transmute_many_permissive::(&[0x00, 0x01, 0x00, 0x02]), 217 | /// # */ 218 | /// # assert_eq!(transmute_many_permissive::(&Le2NAl4([0x00, 0x01, 0x00, 0x02]).0.le_to_native::()), 219 | /// &[0x0100, 0x0200] 220 | /// ); 221 | /// } 222 | /// # } 223 | /// ``` 224 | pub unsafe fn transmute_many_permissive(bytes: &[u8]) -> &[T] { 225 | transmute_many::<_, PermissiveGuard>(bytes).expect("permissive guard should never fail") 226 | } 227 | 228 | /// Transform a vector into a vector of another element type. 229 | /// 230 | /// The vector's allocated byte buffer (if already allocated) will be reused. 231 | /// 232 | /// # Safety 233 | /// 234 | /// Vector transmutations are **exceptionally** dangerous because of 235 | /// the constraints imposed by 236 | /// [`Vec::from_raw_parts()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts). 237 | /// 238 | /// Unless *all* of the following requirements are fulfilled, this operation 239 | /// may result in undefined behavior: 240 | /// 241 | /// - The target type `T` must have the same size and minimum alignment as the 242 | /// type `S`. 243 | /// - The vector's data needs to correspond to a valid contiguous sequence of 244 | /// `T` values. Types `T` with a `Drop` implementation are unlikely to be 245 | /// safe in this regard. 246 | /// 247 | /// # Examples 248 | /// 249 | /// ``` 250 | /// # use safe_transmute::base::transmute_vec; 251 | /// unsafe { 252 | /// assert_eq!( 253 | /// transmute_vec::(vec![0x00, 0x01, 0x00, 0x02]), 254 | /// vec![0x00i8, 0x01i8, 0x00i8, 0x02i8] 255 | /// ); 256 | /// } 257 | /// ``` 258 | #[cfg(feature = "alloc")] 259 | pub unsafe fn transmute_vec(mut vec: Vec) -> Vec { 260 | let ptr = vec.as_mut_ptr(); 261 | let capacity = vec.capacity() * size_of::() / size_of::(); 262 | let len = vec.len() * size_of::() / size_of::(); 263 | forget(vec); 264 | Vec::from_raw_parts(ptr as *mut T, len, capacity) 265 | } 266 | -------------------------------------------------------------------------------- /src/full.rs: -------------------------------------------------------------------------------- 1 | //! Module for functions which ensure full memory safety. 2 | //! 3 | //! Functions in this module are guarded from out-of-bounds memory access as 4 | //! well as from unaligned access, returning errors on both cases. Moreover, 5 | //! only a [`TriviallyTransmutable`](trait.TriviallyTransmutable.html)) can be 6 | //! used as the transmute target, thus ensuring full safety. 7 | //! 8 | //! Unless this was previously imposed by certain means, the functions in this 9 | //! module may arbitrarily fail due to unaligned memory access. It is up to the 10 | //! user of this crate to make the receiving data well aligned for the intended 11 | //! target type. 12 | 13 | 14 | use self::super::trivial::{TriviallyTransmutable, transmute_trivial, transmute_trivial_many, transmute_trivial_many_mut}; 15 | use self::super::guard::{SingleValueGuard, PermissiveGuard, PedanticGuard, Guard}; 16 | use self::super::align::{check_alignment, check_alignment_mut}; 17 | #[cfg(feature = "alloc")] 18 | use self::super::error::IncompatibleVecTargetError; 19 | #[cfg(feature = "alloc")] 20 | use core::mem::{align_of, size_of, forget}; 21 | use self::super::Error; 22 | #[cfg(feature = "alloc")] 23 | use alloc::vec::Vec; 24 | 25 | 26 | /// Transmute a byte slice into a single instance of a trivially transmutable type. 27 | /// 28 | /// The byte slice must have at least enough bytes to fill a single instance of a type, 29 | /// extraneous data is ignored. 30 | /// 31 | /// # Errors 32 | /// 33 | /// An error is returned in one of the following situations: 34 | /// 35 | /// - The data does not have a memory alignment compatible with `T`. You will 36 | /// have to make a copy anyway, or modify how the data was originally made. 37 | /// - The data does not have enough bytes for a single value `T`. 38 | /// 39 | /// # Examples 40 | /// 41 | /// ``` 42 | /// # use safe_transmute::transmute_one; 43 | /// # include!("../tests/test_util/le_to_native.rs"); 44 | /// # fn main() { 45 | /// // Little-endian 46 | /// # /* 47 | /// assert_eq!(transmute_one::(&[0x00, 0x00, 0x00, 0x01])?, 0x0100_0000); 48 | /// # */ 49 | /// # assert_eq!(transmute_one::(&Le2NAl4([0x00, 0x00, 0x00, 0x01]).0.le_to_native::()).unwrap(), 0x0100_0000); 50 | /// # } 51 | /// ``` 52 | pub fn transmute_one(bytes: &[u8]) -> Result> { 53 | check_alignment::<_, T>(bytes)?; 54 | unsafe { transmute_trivial(bytes) } 55 | } 56 | 57 | /// Transmute a byte slice into a single instance of a trivially transmutable type. 58 | /// 59 | /// The byte slice must have exactly enough bytes to fill a single instance of a type. 60 | /// 61 | /// # Errors 62 | /// 63 | /// An error is returned in one of the following situations: 64 | /// 65 | /// - The data does not have a memory alignment compatible with `T`. You will 66 | /// have to make a copy anyway, or modify how the data was originally made. 67 | /// - The data does not have enough bytes for a single value `T`. 68 | /// - The data has more bytes than those required to produce a single value `T`. 69 | /// 70 | /// # Examples 71 | /// 72 | /// ``` 73 | /// # use safe_transmute::transmute_one_pedantic; 74 | /// # include!("../tests/test_util/le_to_native.rs"); 75 | /// # fn main() { 76 | /// // Little-endian 77 | /// # /* 78 | /// assert_eq!(transmute_one_pedantic::(&[0x0F, 0x0E])?, 0x0E0F); 79 | /// # */ 80 | /// # assert_eq!(transmute_one_pedantic::(&Le2NAl2([0x0F, 0x0E]).0.le_to_native::()).unwrap(), 0x0E0F); 81 | /// # } 82 | /// ``` 83 | pub fn transmute_one_pedantic(bytes: &[u8]) -> Result> { 84 | SingleValueGuard::check::(bytes)?; 85 | check_alignment::<_, T>(bytes)?; 86 | unsafe { transmute_trivial(bytes) } 87 | } 88 | 89 | /// Transmute a byte slice into a sequence of values of the given type. 90 | /// 91 | /// # Errors 92 | /// 93 | /// An error is returned in one of the following situations: 94 | /// 95 | /// - The data does not have a memory alignment compatible with `T`. You will 96 | /// have to make a copy anyway, or modify how the data was originally made. 97 | /// - The data does not comply with the policies of the given guard `G`. 98 | /// 99 | /// # Examples 100 | /// 101 | /// ``` 102 | /// # use safe_transmute::{SingleManyGuard, transmute_many}; 103 | /// # include!("../tests/test_util/le_to_native.rs"); 104 | /// # fn main() { 105 | /// // Little-endian 106 | /// # /* 107 | /// assert_eq!(transmute_many::(&[0x00, 0x01, 0x00, 0x02])?, 108 | /// # */ 109 | /// # assert_eq!(transmute_many::(&Le2NAl4([0x00, 0x01, 0x00, 0x02]).0.le_to_native::()).unwrap(), 110 | /// &[0x0100, 0x0200]); 111 | /// # } 112 | /// ``` 113 | pub fn transmute_many(bytes: &[u8]) -> Result<&[T], Error> { 114 | check_alignment::<_, T>(bytes)?; 115 | unsafe { transmute_trivial_many::<_, G>(bytes) } 116 | } 117 | 118 | /// Transmute a byte slice into a sequence of values of the given type. 119 | /// 120 | /// # Errors 121 | /// 122 | /// An error is returned in one of the following situations: 123 | /// 124 | /// - The data does not have a memory alignment compatible with `T`. You will 125 | /// have to make a copy anyway, or modify how the data was originally made. 126 | /// 127 | /// # Examples 128 | /// 129 | /// ``` 130 | /// # use safe_transmute::{Error, transmute_many_permissive}; 131 | /// # /* 132 | /// assert_eq!(transmute_many_permissive::(&[0x00])?, [].as_ref()); 133 | /// # */ 134 | /// # match transmute_many_permissive::(&[0x00]) { 135 | /// # Ok(sl) => assert_eq!(sl, [].as_ref()), 136 | /// # Err(Error::Unaligned(_)) => {} 137 | /// # Err(e) => panic!("{}", e), 138 | /// # } 139 | /// ``` 140 | pub fn transmute_many_permissive(bytes: &[u8]) -> Result<&[T], Error> { 141 | transmute_many::(bytes) 142 | } 143 | 144 | /// Transmute a byte slice into a sequence of values of the given type. 145 | /// 146 | /// # Errors 147 | /// 148 | /// An error is returned in one of the following situations: 149 | /// 150 | /// - The data does not have a memory alignment compatible with `T`. You will 151 | /// have to make a copy anyway, or modify how the data was originally made. 152 | /// - The data does not have enough bytes for a single value `T`. 153 | /// 154 | /// # Examples 155 | /// 156 | /// ``` 157 | /// # use safe_transmute::transmute_many_pedantic; 158 | /// # include!("../tests/test_util/le_to_native.rs"); 159 | /// # fn main() { 160 | /// // Little-endian 161 | /// # /* 162 | /// assert_eq!(transmute_many_pedantic::(&[0x0F, 0x0E, 0x0A, 0x0B])?, 163 | /// # */ 164 | /// # assert_eq!(transmute_many_pedantic::(&Le2NAl4([0x0F, 0x0E, 0x0A, 0x0B]).0.le_to_native::()).unwrap(), 165 | /// &[0x0E0F, 0x0B0A]); 166 | /// # } 167 | /// ``` 168 | pub fn transmute_many_pedantic(bytes: &[u8]) -> Result<&[T], Error> { 169 | transmute_many::(bytes) 170 | } 171 | 172 | /// Transmute a mutable byte slice into a mutable sequence of values of the given type. 173 | /// 174 | /// # Errors 175 | /// 176 | /// An error is returned in one of the following situations: 177 | /// 178 | /// - The data does not have a memory alignment compatible with `T`. You will 179 | /// have to make a copy anyway, or modify how the data was originally made. 180 | /// - The data does not comply with the policies of the given guard `G`. 181 | /// 182 | /// # Examples 183 | /// 184 | /// ``` 185 | /// # use safe_transmute::{SingleManyGuard, transmute_many_mut}; 186 | /// # include!("../tests/test_util/le_to_native.rs"); 187 | /// # fn main() { 188 | /// // Little-endian 189 | /// # /* 190 | /// assert_eq!(transmute_many_mut::(&mut [0x00, 0x01, 0x00, 0x02])?, 191 | /// # */ 192 | /// # assert_eq!(transmute_many_mut::(&mut Le2NAl4([0x00, 0x01, 0x00, 0x02]).0.le_to_native::()).unwrap(), 193 | /// &mut [0x0100, 0x0200]); 194 | /// # } 195 | /// ``` 196 | pub fn transmute_many_mut(bytes: &mut [u8]) -> Result<&mut [T], Error> { 197 | check_alignment_mut::<_, T>(bytes) 198 | .map_err(Error::from) 199 | .and_then(|bytes| unsafe { transmute_trivial_many_mut::<_, G>(bytes) }) 200 | } 201 | 202 | /// Transmute a byte slice into a sequence of values of the given type. 203 | /// 204 | /// # Errors 205 | /// 206 | /// An error is returned in one of the following situations: 207 | /// 208 | /// - The data does not have a memory alignment compatible with `T`. You will 209 | /// have to make a copy anyway, or modify how the data was originally made. 210 | /// 211 | /// # Examples 212 | /// 213 | /// ``` 214 | /// # use safe_transmute::{Error, transmute_many_permissive_mut}; 215 | /// # /* 216 | /// assert_eq!(transmute_many_permissive_mut::(&mut [0x00])?, [].as_mut()); 217 | /// # */ 218 | /// # match transmute_many_permissive_mut::(&mut [0x00]) { 219 | /// # Ok(sl) => assert_eq!(sl, [].as_mut()), 220 | /// # Err(Error::Unaligned(_)) => {} 221 | /// # Err(e) => panic!("{}", e), 222 | /// # } 223 | /// ``` 224 | pub fn transmute_many_permissive_mut(bytes: &mut [u8]) -> Result<&mut [T], Error> { 225 | transmute_many_mut::(bytes) 226 | } 227 | 228 | /// Transmute a byte slice into a sequence of values of the given type. 229 | /// 230 | /// # Errors 231 | /// 232 | /// An error is returned in one of the following situations: 233 | /// 234 | /// - The data does not have a memory alignment compatible with `T`. You will 235 | /// have to make a copy anyway, or modify how the data was originally made. 236 | /// - The data does not have enough bytes for a single value `T`. 237 | /// 238 | /// # Examples 239 | /// 240 | /// ``` 241 | /// # use safe_transmute::transmute_many_pedantic_mut; 242 | /// # include!("../tests/test_util/le_to_native.rs"); 243 | /// # fn main() { 244 | /// // Little-endian 245 | /// # /* 246 | /// assert_eq!(transmute_many_pedantic_mut::(&mut [0x0F, 0x0E, 0x0A, 0x0B])?, 247 | /// # */ 248 | /// # assert_eq!(transmute_many_pedantic_mut::(&mut Le2NAl4([0x0F, 0x0E, 0x0A, 0x0B]).0.le_to_native::()).unwrap(), 249 | /// &mut [0x0E0F, 0x0B0A]); 250 | /// # } 251 | /// ``` 252 | pub fn transmute_many_pedantic_mut(bytes: &mut [u8]) -> Result<&mut [T], Error> { 253 | transmute_many_mut::(bytes) 254 | } 255 | 256 | /// Transform a vector into a vector of values with the given target type. 257 | /// 258 | /// The resulting vector will reuse the allocated byte buffer when successful. 259 | /// 260 | /// # Errors 261 | /// 262 | /// An error is returned if *either* the size or the minimum memory 263 | /// requirements are not the same between `S` and `U`: 264 | /// 265 | /// - `std::mem::size_of::() != std::mem::size_of::()` 266 | /// - `std::mem::align_of::() != std::mem::align_of::()` 267 | /// 268 | /// Otherwise, the only truly safe way of doing this is to create a transmuted 269 | /// slice view of the vector, or make a copy anyway. The 270 | /// [`IncompatibleVecTargetError`](../error/struct.IncompatibleVecTargetError.html) error 271 | /// type provides a means of making this copy to the intended target type. 272 | /// 273 | /// # Examples 274 | /// 275 | /// ``` 276 | /// # use safe_transmute::transmute_vec; 277 | /// # use safe_transmute::error::Error; 278 | /// # fn run() -> Result<(), Error<'static, u8, i8>> { 279 | /// assert_eq!(transmute_vec::(vec![0x00, 0x01, 0x00, 0x02])?, 280 | /// vec![0x00i8, 0x01i8, 0x00i8, 0x02i8]); 281 | /// assert_eq!(transmute_vec::(vec![0x04, 0x00, 0x00, 0x00, 0xED])?, 282 | /// vec![0x04, 0x00, 0x00, 0x00, -0x13i8]); 283 | /// # Ok(()) 284 | /// # } 285 | /// # run().unwrap(); 286 | /// ``` 287 | #[cfg(feature = "alloc")] 288 | pub fn transmute_vec(mut vec: Vec) -> Result, Error<'static, S, T>> { 289 | if align_of::() != align_of::() || size_of::() != size_of::() { 290 | return Err(IncompatibleVecTargetError::new(vec).into()); 291 | } 292 | 293 | unsafe { 294 | let capacity = vec.capacity(); 295 | let len = vec.len(); 296 | let ptr = vec.as_mut_ptr(); 297 | forget(vec); 298 | Ok(Vec::from_raw_parts(ptr as *mut T, len, capacity)) 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /src/to_bytes.rs: -------------------------------------------------------------------------------- 1 | //! Functions for transmutation *from* a concrete type *to* bytes. 2 | 3 | 4 | use self::super::TriviallyTransmutable; 5 | #[cfg(feature = "alloc")] 6 | use self::super::Error; 7 | use core::mem::size_of; 8 | use core::slice; 9 | #[cfg(feature = "alloc")] 10 | use alloc::vec::Vec; 11 | 12 | 13 | /// Transmute a single instance of an arbitrary type into a slice of its bytes. 14 | /// 15 | /// # Examples 16 | /// 17 | /// An `u32`: 18 | /// 19 | /// ``` 20 | /// # use safe_transmute::to_bytes::transmute_to_bytes_unchecked; 21 | /// # include!("../tests/test_util/le_to_native.rs"); 22 | /// # fn main() { 23 | /// unsafe { 24 | /// // Little-endian 25 | /// assert_eq!(transmute_to_bytes_unchecked(&0x0123_4567), 26 | /// # /* 27 | /// &[0x67, 0x45, 0x23, 0x01]); 28 | /// # */ 29 | /// # [0x67, 0x45, 0x23, 0x01].le_to_native::()); 30 | /// } 31 | /// # } 32 | /// ``` 33 | /// 34 | /// An arbitrary type: 35 | /// 36 | /// ``` 37 | /// # use safe_transmute::to_bytes::transmute_to_bytes_unchecked; 38 | /// #[repr(C)] 39 | /// struct Gene { 40 | /// x1: u8, 41 | /// x2: u8, 42 | /// } 43 | /// 44 | /// unsafe { 45 | /// assert_eq!(transmute_to_bytes_unchecked(&Gene { 46 | /// x1: 0x42, 47 | /// x2: 0x69, 48 | /// }), 49 | /// &[0x42, 0x69]); 50 | /// } 51 | /// ``` 52 | pub unsafe fn transmute_to_bytes_unchecked(from: &S) -> &[u8] { 53 | slice::from_raw_parts(from as *const S as *const u8, size_of::()) 54 | } 55 | 56 | /// Transmute a single mutable instance of an arbitrary type into a mutable 57 | /// slice of its bytes. 58 | /// 59 | /// # Safety 60 | /// 61 | /// This function is very ill advised, since it can be exploited to break 62 | /// invariants of the source type. Any modification that leaves the data 63 | /// in an inconsistent state with respect to `S` results in undefined behavior. 64 | /// 65 | /// # Examples 66 | /// 67 | /// An `u32`: 68 | /// 69 | /// ``` 70 | /// # use safe_transmute::to_bytes::transmute_to_bytes_unchecked_mut; 71 | /// # include!("../tests/test_util/le_to_native.rs"); 72 | /// # fn main() { 73 | /// unsafe { 74 | /// // Little-endian 75 | /// assert_eq!(transmute_to_bytes_unchecked_mut(&mut 0x0123_4567), 76 | /// # /* 77 | /// &mut [0x67, 0x45, 0x23, 0x01]); 78 | /// # */ 79 | /// # (&mut [0x67, 0x45, 0x23, 0x01]).le_to_native::()); 80 | /// } 81 | /// # } 82 | /// ``` 83 | /// 84 | /// An arbitrary type: 85 | /// 86 | /// ``` 87 | /// # use safe_transmute::to_bytes::transmute_to_bytes_unchecked_mut; 88 | /// #[repr(C)] 89 | /// #[derive(Debug, Eq, PartialEq)] 90 | /// struct Gene { 91 | /// x1: u8, 92 | /// x2: u8, 93 | /// } 94 | /// 95 | /// let mut gene = Gene { 96 | /// x1: 0x42, 97 | /// x2: 0x69, 98 | /// }; 99 | /// 100 | /// unsafe { 101 | /// let gene_data = transmute_to_bytes_unchecked_mut(&mut gene); 102 | /// assert_eq!(gene_data, &mut [0x42, 0x69]); 103 | /// gene_data[0] = 0xB0; 104 | /// } 105 | /// 106 | /// assert_eq!(gene, Gene { 107 | /// x1: 0xB0, 108 | /// x2: 0x69, 109 | /// }); 110 | /// ``` 111 | pub unsafe fn transmute_to_bytes_unchecked_mut(from: &mut S) -> &mut [u8] { 112 | slice::from_raw_parts_mut(from as *mut S as *mut u8, size_of::()) 113 | } 114 | 115 | /// Transmute a slice of arbitrary types into a slice of their bytes. 116 | /// 117 | /// # Examples 118 | /// 119 | /// Some `u16`s: 120 | /// 121 | /// ``` 122 | /// # use safe_transmute::to_bytes::transmute_to_bytes_many_unchecked; 123 | /// # include!("../tests/test_util/le_to_native.rs"); 124 | /// # fn main() { 125 | /// unsafe { 126 | /// // Little-endian 127 | /// assert_eq!(transmute_to_bytes_many_unchecked(&[0x0123u16, 0x4567u16]), 128 | /// # /* 129 | /// &[0x23, 0x01, 0x67, 0x45]); 130 | /// # */ 131 | /// # [0x23, 0x01, 0x67, 0x45].le_to_native::()); 132 | /// } 133 | /// # } 134 | /// ``` 135 | /// 136 | /// An arbitrary type: 137 | /// 138 | /// ``` 139 | /// # use safe_transmute::to_bytes::transmute_to_bytes_many_unchecked; 140 | /// #[repr(C)] 141 | /// struct Gene { 142 | /// x1: u8, 143 | /// x2: u8, 144 | /// } 145 | /// 146 | /// unsafe { 147 | /// assert_eq!(transmute_to_bytes_many_unchecked(&[Gene { 148 | /// x1: 0x42, 149 | /// x2: 0x69, 150 | /// }, 151 | /// Gene { 152 | /// x1: 0x12, 153 | /// x2: 0x48, 154 | /// }]), 155 | /// &[0x42, 0x69, 0x12, 0x48]); 156 | /// } 157 | /// ``` 158 | pub unsafe fn transmute_to_bytes_many_unchecked(from: &[S]) -> &[u8] { 159 | slice::from_raw_parts(from.as_ptr() as *const u8, from.len() * size_of::()) 160 | } 161 | 162 | /// Transmute a mutable slice of arbitrary types into a mutable slice of their 163 | /// bytes. 164 | /// 165 | /// # Safety 166 | /// 167 | /// This function is very ill advised, since it can be exploited to break 168 | /// invariants of the source type. Any modification that leaves the data 169 | /// in an inconsistent state with respect to `S` is undefined behavior. 170 | /// 171 | /// # Examples 172 | /// 173 | /// Some `u16`s: 174 | /// 175 | /// ``` 176 | /// # use safe_transmute::to_bytes::transmute_to_bytes_mut; 177 | /// # include!("../tests/test_util/le_to_native.rs"); 178 | /// # fn main() { 179 | /// unsafe { 180 | /// // Little-endian 181 | /// assert_eq!(transmute_to_bytes_mut(&mut [0x0123u16, 0x4567u16]), 182 | /// # /* 183 | /// &[0x23, 0x01, 0x67, 0x45]); 184 | /// # */ 185 | /// # [0x23, 0x01, 0x67, 0x45].le_to_native::()); 186 | /// } 187 | /// # } 188 | /// ``` 189 | /// 190 | /// An arbitrary type: 191 | /// 192 | /// ``` 193 | /// # use safe_transmute::to_bytes::transmute_to_bytes_many_unchecked_mut; 194 | /// #[repr(C)] 195 | /// #[derive(Debug, Eq, PartialEq)] 196 | /// struct Gene { 197 | /// x1: u8, 198 | /// x2: u8, 199 | /// } 200 | /// 201 | /// let mut genes = [Gene { 202 | /// x1: 0x42, 203 | /// x2: 0x69, 204 | /// }, 205 | /// Gene { 206 | /// x1: 0x12, 207 | /// x2: 0x48, 208 | /// }]; 209 | /// 210 | /// unsafe { 211 | /// let gene_data = transmute_to_bytes_many_unchecked_mut(&mut genes); 212 | /// assert_eq!(gene_data, &mut [0x42, 0x69, 0x12, 0x48]); 213 | /// 214 | /// gene_data[0] = 0xB0; 215 | /// gene_data[3] = 0x0B; 216 | /// } 217 | /// 218 | /// assert_eq!(genes, [Gene { 219 | /// x1: 0xB0, 220 | /// x2: 0x69, 221 | /// }, 222 | /// Gene { 223 | /// x1: 0x12, 224 | /// x2: 0x0B, 225 | /// }]); 226 | /// ``` 227 | pub unsafe fn transmute_to_bytes_many_unchecked_mut(from: &mut [S]) -> &mut [u8] { 228 | slice::from_raw_parts_mut(from.as_mut_ptr() as *mut u8, from.len() * size_of::()) 229 | } 230 | 231 | /// Transmute a single instance of a trivially transmutable type into a slice 232 | /// of its bytes. 233 | /// 234 | /// # Examples 235 | /// 236 | /// An `u32`: 237 | /// 238 | /// ``` 239 | /// # use safe_transmute::transmute_one_to_bytes; 240 | /// # include!("../tests/test_util/le_to_native.rs"); 241 | /// # fn main() { 242 | /// // Little-endian 243 | /// assert_eq!(transmute_one_to_bytes(&0x0123_4567), 244 | /// # /* 245 | /// &[0x67, 0x45, 0x23, 0x01]); 246 | /// # */ 247 | /// # [0x67, 0x45, 0x23, 0x01].le_to_native::()); 248 | /// # } 249 | /// ``` 250 | /// 251 | /// An arbitrary type: 252 | /// 253 | /// ``` 254 | /// # use safe_transmute::{TriviallyTransmutable, transmute_one_to_bytes}; 255 | /// #[repr(C)] 256 | /// #[derive(Clone, Copy)] 257 | /// struct Gene { 258 | /// x1: u8, 259 | /// x2: u8, 260 | /// } 261 | /// unsafe impl TriviallyTransmutable for Gene {} 262 | /// 263 | /// assert_eq!(transmute_one_to_bytes(&Gene { 264 | /// x1: 0x42, 265 | /// x2: 0x69, 266 | /// }), 267 | /// &[0x42, 0x69]); 268 | /// ``` 269 | pub fn transmute_one_to_bytes(from: &S) -> &[u8] { 270 | unsafe { transmute_to_bytes_unchecked(from) } 271 | } 272 | 273 | /// Transmute a single instance of a trivially transmutable type into a slice 274 | /// of its bytes. 275 | /// 276 | /// # Examples 277 | /// 278 | /// An `u32`: 279 | /// 280 | /// ``` 281 | /// # use safe_transmute::transmute_one_to_bytes_mut; 282 | /// # include!("../tests/test_util/le_to_native.rs"); 283 | /// # fn main() { 284 | /// // Little-endian 285 | /// assert_eq!(transmute_one_to_bytes_mut(&mut 0x0123_4567), 286 | /// # /* 287 | /// &mut [0x67, 0x45, 0x23, 0x01]); 288 | /// # */ 289 | /// # (&mut [0x67, 0x45, 0x23, 0x01]).le_to_native::()); 290 | /// # } 291 | /// ``` 292 | /// 293 | /// An arbitrary type: 294 | /// 295 | /// ``` 296 | /// # use safe_transmute::{TriviallyTransmutable, transmute_one_to_bytes_mut}; 297 | /// #[repr(C)] 298 | /// #[derive(Clone, Copy, Debug, Eq, PartialEq)] 299 | /// struct Gene { 300 | /// x1: u8, 301 | /// x2: u8, 302 | /// } 303 | /// unsafe impl TriviallyTransmutable for Gene {} 304 | /// 305 | /// let mut gene = Gene { 306 | /// x1: 0x42, 307 | /// x2: 0x69, 308 | /// }; 309 | /// 310 | /// { 311 | /// let gene_data = transmute_one_to_bytes_mut(&mut gene); 312 | /// assert_eq!(gene_data, &mut [0x42, 0x69]); 313 | /// gene_data[0] = 0xB0; 314 | /// } 315 | /// 316 | /// assert_eq!(gene, Gene { 317 | /// x1: 0xB0, 318 | /// x2: 0x69, 319 | /// }); 320 | /// ``` 321 | pub fn transmute_one_to_bytes_mut(from: &mut S) -> &mut [u8] { 322 | unsafe { transmute_to_bytes_unchecked_mut(from) } 323 | } 324 | 325 | /// Transmute a slice of arbitrary types into a slice of their bytes. 326 | /// 327 | /// # Examples 328 | /// 329 | /// Some `u16`s: 330 | /// 331 | /// ``` 332 | /// # use safe_transmute::transmute_to_bytes; 333 | /// # include!("../tests/test_util/le_to_native.rs"); 334 | /// # fn main() { 335 | /// // Little-endian 336 | /// assert_eq!(transmute_to_bytes(&[0x0123u16, 0x4567u16]), 337 | /// # /* 338 | /// &[0x23, 0x01, 0x67, 0x45]); 339 | /// # */ 340 | /// # [0x23, 0x01, 0x67, 0x45].le_to_native::()); 341 | /// # } 342 | /// ``` 343 | /// 344 | /// An arbitrary type: 345 | /// 346 | /// ``` 347 | /// # use safe_transmute::{TriviallyTransmutable, transmute_to_bytes}; 348 | /// #[repr(C)] 349 | /// #[derive(Clone, Copy)] 350 | /// struct Gene { 351 | /// x1: u8, 352 | /// x2: u8, 353 | /// } 354 | /// unsafe impl TriviallyTransmutable for Gene {} 355 | /// 356 | /// assert_eq!(transmute_to_bytes(&[Gene { 357 | /// x1: 0x42, 358 | /// x2: 0x69, 359 | /// }, 360 | /// Gene { 361 | /// x1: 0x12, 362 | /// x2: 0x48, 363 | /// }]), 364 | /// &[0x42, 0x69, 0x12, 0x48]); 365 | /// ``` 366 | pub fn transmute_to_bytes(from: &[S]) -> &[u8] { 367 | unsafe { transmute_to_bytes_many_unchecked(from) } 368 | } 369 | 370 | /// Transmute a mutable slice of a trivially transmutable type into a mutable 371 | /// slice of its bytes. 372 | /// 373 | /// # Examples 374 | /// 375 | /// ``` 376 | /// # use safe_transmute::{TriviallyTransmutable, transmute_to_bytes_mut}; 377 | /// #[repr(C)] 378 | /// #[derive(Clone, Copy, Debug, Eq, PartialEq)] 379 | /// struct Gene { 380 | /// x1: u8, 381 | /// x2: u8, 382 | /// } 383 | /// unsafe impl TriviallyTransmutable for Gene {} 384 | /// 385 | /// let mut genes = [Gene { 386 | /// x1: 0x42, 387 | /// x2: 0x69, 388 | /// }, 389 | /// Gene { 390 | /// x1: 0x12, 391 | /// x2: 0x48, 392 | /// }]; 393 | /// 394 | /// { 395 | /// let gene_data = transmute_to_bytes_mut(&mut genes); 396 | /// assert_eq!(gene_data, &mut [0x42, 0x69, 0x12, 0x48]); 397 | /// 398 | /// gene_data[0] = 0xB0; 399 | /// gene_data[3] = 0x0B; 400 | /// } 401 | /// 402 | /// assert_eq!(genes, [Gene { 403 | /// x1: 0xB0, 404 | /// x2: 0x69, 405 | /// }, 406 | /// Gene { 407 | /// x1: 0x12, 408 | /// x2: 0x0B, 409 | /// }]); 410 | /// ``` 411 | pub fn transmute_to_bytes_mut(from: &mut [S]) -> &mut [u8] { 412 | unsafe { transmute_to_bytes_many_unchecked_mut(from) } 413 | } 414 | 415 | /// Transmute a slice of arbitrary types into a slice of their bytes. 416 | #[deprecated(since = "0.11.0", note = "use `transmute_to_bytes()` instead")] 417 | pub fn guarded_transmute_to_bytes_pod_many(from: &[S]) -> &[u8] { 418 | transmute_to_bytes(from) 419 | } 420 | 421 | /// Transmute a vector of elements of an arbitrary type into a vector of their 422 | /// bytes, using the same memory buffer as the former. 423 | /// 424 | /// This is equivalent to calling [`full::transmute_vec()`](../full/fn.transmute_vec.html) where 425 | /// the target type is `u8`. 426 | /// 427 | /// # Errors 428 | /// 429 | /// An error is returned if the minimum memory alignment requirements are not 430 | /// the same between `S` and `u8`: 431 | /// 432 | /// ``` 433 | /// # /* 434 | /// std::mem::align_of::() != 1 435 | /// # */ 436 | /// ``` 437 | /// 438 | /// The only truly safe way of doing this is to create a transmuted slice 439 | /// view of the vector or make a copy anyway. 440 | /// 441 | #[cfg(feature = "alloc")] 442 | pub fn transmute_to_bytes_vec(from: Vec) -> Result, Error<'static, S, u8>> { 443 | super::full::transmute_vec::(from) 444 | } 445 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | //! Detectable and recoverable-from transmutation precondition errors. 2 | 3 | 4 | use core::fmt; 5 | #[cfg(feature = "alloc")] 6 | use core::ptr; 7 | #[cfg(feature = "alloc")] 8 | use alloc::vec::Vec; 9 | use core::marker::PhantomData; 10 | #[cfg(feature = "std")] 11 | use std::error::Error as StdError; 12 | #[cfg(feature = "alloc")] 13 | use core::mem::{align_of, size_of}; 14 | #[cfg(feature = "alloc")] 15 | use self::super::trivial::TriviallyTransmutable; 16 | 17 | 18 | /// A transmutation error. This type describes possible errors originating 19 | /// from operations in this crate. The two type parameters represent the 20 | /// source element type and the target element type respectively. 21 | /// 22 | /// # Examples 23 | /// 24 | /// ``` 25 | /// # use safe_transmute::{ErrorReason, Error, transmute_bool_pedantic}; 26 | /// assert_eq!(transmute_bool_pedantic(&[0x05]), Err(Error::InvalidValue)); 27 | /// ``` 28 | #[derive(Clone, PartialEq, Eq, Hash)] 29 | pub enum Error<'a, S, T> { 30 | /// The data does not respect the target type's boundaries. 31 | Guard(GuardError), 32 | /// The given data slice is not properly aligned for the target type. 33 | Unaligned(UnalignedError<'a, S, T>), 34 | /// The data vector's element type does not have the same size and minimum 35 | /// alignment as the target type. 36 | /// 37 | /// Does not exist without the `alloc` feature. 38 | #[cfg(feature = "alloc")] 39 | IncompatibleVecTarget(IncompatibleVecTargetError), 40 | /// The data contains an invalid value for the target type. 41 | InvalidValue, 42 | } 43 | 44 | impl<'a, S, T> Error<'a, S, T> { 45 | /// Reattempt the failed transmutation if the failure was caused by either 46 | /// an unaligned memory access, or an incompatible vector element target. 47 | /// 48 | /// Otherwise return `self`. 49 | #[cfg(feature = "alloc")] 50 | pub fn copy(self) -> Result, Error<'a, S, T>> 51 | where T: TriviallyTransmutable 52 | { 53 | match self { 54 | Error::Unaligned(e) => Ok(e.copy()), 55 | Error::IncompatibleVecTarget(e) => Ok(e.copy()), 56 | e => Err(e), 57 | } 58 | } 59 | 60 | /// Reattempt the failed non-trivial transmutation if the failure was caused by either 61 | /// an unaligned memory access, or an incompatible vector element target. 62 | /// 63 | /// Otherwise return `self`. 64 | /// 65 | /// # Safety 66 | /// 67 | /// The source data needs to correspond to a valid contiguous sequence of 68 | /// `T` values. 69 | #[cfg(feature = "alloc")] 70 | pub unsafe fn copy_unchecked(self) -> Result, Error<'a, S, T>> { 71 | match self { 72 | Error::Unaligned(e) => Ok(e.copy_unchecked()), 73 | Error::IncompatibleVecTarget(e) => Ok(e.copy_unchecked()), 74 | e => Err(e), 75 | } 76 | } 77 | 78 | /// Create a new error which discards runtime information about the 79 | /// source data, by making it point to an empty slice. This makes 80 | /// the error value live longer than the context of transmutation. 81 | pub fn without_src<'z>(self) -> Error<'z, S, T> { 82 | match self { 83 | Error::Unaligned(UnalignedError { source: _, offset, phantom }) => { 84 | Error::Unaligned(UnalignedError { 85 | source: &[], 86 | offset: offset, 87 | phantom: phantom, 88 | }) 89 | } 90 | Error::Guard(e) => Error::Guard(e), 91 | Error::InvalidValue => Error::InvalidValue, 92 | #[cfg(feature = "alloc")] 93 | Error::IncompatibleVecTarget(e) => Error::IncompatibleVecTarget(e), 94 | } 95 | } 96 | } 97 | 98 | impl<'a, S, T> fmt::Debug for Error<'a, S, T> { 99 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 100 | match self { 101 | Error::Guard(e) => write!(f, "Guard({:?})", e), 102 | Error::Unaligned(e) => write!(f, "Unaligned({:?})", e), 103 | Error::InvalidValue => f.write_str("InvalidValue"), 104 | #[cfg(feature = "alloc")] 105 | Error::IncompatibleVecTarget(_) => f.write_str("IncompatibleVecTarget"), 106 | } 107 | } 108 | } 109 | 110 | #[cfg(feature = "std")] 111 | #[allow(deprecated)] 112 | impl<'a, S, T> StdError for Error<'a, S, T> { 113 | fn description(&self) -> &str { 114 | match self { 115 | Error::Guard(e) => e.description(), 116 | Error::Unaligned(e) => e.description(), 117 | Error::InvalidValue => "invalid target value", 118 | Error::IncompatibleVecTarget(e) => e.description(), 119 | } 120 | } 121 | } 122 | 123 | impl<'a, S, T> fmt::Display for Error<'a, S, T> { 124 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 125 | match self { 126 | Error::Guard(e) => e.fmt(f), 127 | Error::Unaligned(e) => e.fmt(f), 128 | Error::InvalidValue => f.write_str("Invalid target value"), 129 | #[cfg(feature = "alloc")] 130 | Error::IncompatibleVecTarget(e) => e.fmt(f), 131 | } 132 | } 133 | } 134 | 135 | impl<'a, S, T> From for Error<'a, S, T> { 136 | fn from(o: GuardError) -> Self { 137 | Error::Guard(o) 138 | } 139 | } 140 | 141 | impl<'a, S, T> From> for Error<'a, S, T> { 142 | fn from(o: UnalignedError<'a, S, T>) -> Self { 143 | Error::Unaligned(o) 144 | } 145 | } 146 | 147 | 148 | /// A slice boundary guard error, usually created by a 149 | /// [`Guard`](./guard/trait.Guard.html). 150 | /// 151 | /// # Examples 152 | /// 153 | /// ``` 154 | /// # use safe_transmute::{ErrorReason, GuardError}; 155 | /// # use safe_transmute::guard::{Guard, SingleManyGuard}; 156 | /// # unsafe { 157 | /// assert_eq!( 158 | /// SingleManyGuard::check::(&[0x00]), 159 | /// Err(GuardError { 160 | /// required: 16 / 8, 161 | /// actual: 1, 162 | /// reason: ErrorReason::NotEnoughBytes, 163 | /// }) 164 | /// ); 165 | /// # } 166 | /// ``` 167 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 168 | pub struct GuardError { 169 | /// The required amount of bytes for transmutation. 170 | pub required: usize, 171 | /// The actual amount of bytes. 172 | pub actual: usize, 173 | /// Why this `required`/`actual`/`T` combo is an error. 174 | pub reason: ErrorReason, 175 | } 176 | 177 | /// How the type's size compares to the received byte count and the 178 | /// transmutation function's characteristic. 179 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 180 | pub enum ErrorReason { 181 | /// Too few bytes to fill even one instance of a type. 182 | NotEnoughBytes, 183 | /// Too many bytes to fill a type. 184 | /// 185 | /// Currently unused. 186 | TooManyBytes, 187 | /// The byte amount received is not the same as the type's size. 188 | InexactByteCount, 189 | } 190 | 191 | #[cfg(feature = "std")] 192 | impl StdError for GuardError { 193 | fn description(&self) -> &str { 194 | self.reason.description() 195 | } 196 | } 197 | 198 | impl fmt::Display for GuardError { 199 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 200 | write!(f, "{} (required: {}, actual: {})", self.reason.description(), self.required, self.actual) 201 | } 202 | } 203 | 204 | impl ErrorReason { 205 | /// Retrieve a human readable description of the reason. 206 | pub fn description(self) -> &'static str { 207 | match self { 208 | ErrorReason::NotEnoughBytes => "Not enough bytes to fill type", 209 | ErrorReason::TooManyBytes => "Too many bytes for type", 210 | ErrorReason::InexactByteCount => "Not exactly the amount of bytes for type", 211 | } 212 | } 213 | } 214 | 215 | /// Create a copy of the given data, transmuted into a vector. 216 | /// 217 | /// # Safety 218 | /// 219 | /// The byte data in the vector needs to correspond to a valid contiguous 220 | /// sequence of `T` values. 221 | #[cfg(feature = "alloc")] 222 | unsafe fn copy_to_vec_unchecked(data: &[S]) -> Vec { 223 | let len = data.len() * size_of::() / size_of::(); 224 | 225 | let mut out = Vec::with_capacity(len); 226 | ptr::copy_nonoverlapping(data.as_ptr() as *const u8, out.as_mut_ptr() as *mut u8, len * size_of::()); 227 | 228 | out.set_len(len); 229 | out 230 | } 231 | 232 | /// Unaligned memory access error. 233 | /// 234 | /// Returned when the given data slice is not properly aligned for the target 235 | /// type. It would have been properly aligned if `offset` bytes were shifted 236 | /// (discarded) from the front of the slice. 237 | #[derive(Clone, Eq, Hash, PartialEq)] 238 | pub struct UnalignedError<'a, S, T> { 239 | /// The required amount of bytes to discard at the front for the attempted 240 | /// transmutation to be successful. 241 | pub offset: usize, 242 | /// A slice of the original source data. 243 | pub source: &'a [S], 244 | 245 | phantom: PhantomData, 246 | } 247 | 248 | impl<'a, S, T> UnalignedError<'a, S, T> { 249 | pub fn new(offset: usize, source: &'a [S]) -> Self { 250 | UnalignedError { 251 | offset: offset, 252 | source: source, 253 | phantom: PhantomData, 254 | } 255 | } 256 | 257 | /// Create a copy of the source data, transmuted into a vector. As the 258 | /// vector will be properly aligned for accessing values of type `T`, this 259 | /// operation will not fail due to memory alignment constraints. 260 | /// 261 | /// # Safety 262 | /// 263 | /// The byte data in the slice needs to correspond to a valid contiguous 264 | /// sequence of `T` values. 265 | #[cfg(feature = "alloc")] 266 | pub unsafe fn copy_unchecked(&self) -> Vec { 267 | copy_to_vec_unchecked::(self.source) 268 | } 269 | 270 | /// Create a copy of the source data, transmuted into a vector. As `T` is 271 | /// trivially transmutable, and the vector will be properly allocated 272 | /// for accessing values of type `T`, this operation is safe and will never 273 | /// fail. 274 | #[cfg(feature = "alloc")] 275 | pub fn copy(&self) -> Vec 276 | where T: TriviallyTransmutable 277 | { 278 | unsafe { 279 | // no value checks needed thanks to `TriviallyTransmutable` 280 | self.copy_unchecked() 281 | } 282 | } 283 | } 284 | 285 | impl<'a, S, T> fmt::Debug for UnalignedError<'a, S, T> { 286 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 287 | // Summarize the output of the source slice to just its 288 | // length, so that it does not require `S: Debug`. 289 | struct Source { 290 | len: usize, 291 | } 292 | 293 | impl fmt::Debug for Source { 294 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 295 | f.debug_struct("&[S]") 296 | .field("len", &self.len) 297 | .finish() 298 | } 299 | } 300 | 301 | f.debug_struct("UnalignedError") 302 | .field("offset", &self.offset) 303 | .field("source", &Source { len: self.source.len() }) 304 | .finish() 305 | } 306 | } 307 | 308 | #[cfg(feature = "std")] 309 | impl<'a, S, T> StdError for UnalignedError<'a, S, T> { 310 | fn description(&self) -> &str { 311 | "data is unaligned" 312 | } 313 | } 314 | 315 | impl<'a, S, T> fmt::Display for UnalignedError<'a, S, T> { 316 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 317 | write!(f, "data is unaligned (off by {} bytes)", self.offset) 318 | } 319 | } 320 | 321 | 322 | /// Incompatible vector transmutation error. 323 | /// 324 | /// Returned when the element type `S` does not allow a safe vector 325 | /// transmutation to the target element type `T`. This happens when either 326 | /// the size or minimum memory alignment requirements are not met: 327 | /// 328 | /// - `std::mem::align_of::() != std::mem::align_of::()` 329 | /// - `std::mem::size_of::() != std::mem::size_of::()` 330 | #[cfg(feature = "alloc")] 331 | #[derive(Clone, Eq, Hash, PartialEq)] 332 | pub struct IncompatibleVecTargetError { 333 | /// The original vector. 334 | pub vec: Vec, 335 | /// The target element type 336 | target: PhantomData, 337 | } 338 | 339 | #[cfg(feature = "alloc")] 340 | impl IncompatibleVecTargetError { 341 | /// Create an error with the given vector. 342 | pub fn new(vec: Vec) -> Self { 343 | IncompatibleVecTargetError { 344 | vec: vec, 345 | target: PhantomData, 346 | } 347 | } 348 | 349 | /// Create a copy of the data, transmuted into a new vector. As the vector 350 | /// will be properly aligned for accessing values of type `T`, this 351 | /// operation will not fail due to memory alignment constraints. 352 | /// 353 | /// # Safety 354 | /// 355 | /// The byte data in the vector needs to correspond to a valid contiguous 356 | /// sequence of `T` values. 357 | pub unsafe fn copy_unchecked(&self) -> Vec { 358 | copy_to_vec_unchecked::(&self.vec) 359 | } 360 | 361 | /// Create a copy of the data, transmuted into a new vector. As `T` is 362 | /// trivially transmutable, and the new vector will be properly allocated 363 | /// for accessing values of type `T`, this operation is safe and will never fail. 364 | pub fn copy(&self) -> Vec 365 | where T: TriviallyTransmutable 366 | { 367 | unsafe { 368 | // no value checks needed thanks to `TriviallyTransmutable` 369 | self.copy_unchecked() 370 | } 371 | } 372 | } 373 | 374 | #[cfg(feature = "alloc")] 375 | impl<'a, S, T> From> for Error<'a, S, T> { 376 | fn from(e: IncompatibleVecTargetError) -> Self { 377 | Error::IncompatibleVecTarget(e) 378 | } 379 | } 380 | 381 | #[cfg(feature = "alloc")] 382 | impl fmt::Debug for IncompatibleVecTargetError { 383 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 384 | f.debug_struct("IncompatibleVecTargetError") 385 | .field("size_of", &size_of::()) 386 | .field("align_of", &align_of::()) 387 | .field("size_of", &size_of::()) 388 | .field("align_of", &align_of::()) 389 | .finish() 390 | } 391 | } 392 | 393 | #[cfg(feature = "std")] 394 | impl StdError for IncompatibleVecTargetError { 395 | fn description(&self) -> &str { 396 | "incompatible target type" 397 | } 398 | } 399 | 400 | #[cfg(feature = "alloc")] 401 | impl fmt::Display for IncompatibleVecTargetError { 402 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 403 | write!(f, 404 | "incompatible target type (size: {}, align: {}) for transmutation from source (size: {}, align: {})", 405 | size_of::(), 406 | align_of::(), 407 | size_of::(), 408 | align_of::()) 409 | } 410 | } 411 | -------------------------------------------------------------------------------- /src/trivial.rs: -------------------------------------------------------------------------------- 1 | //! Transmutation of trivial objects 2 | //! 3 | //! Functions in this module are guarded from out-of-bounds memory access and 4 | //! from unsafe transmutation target types through the use of the 5 | //! [`TriviallyTransmutable`](trait.TriviallyTransmutable.html)) trait. 6 | //! 7 | //! If a certain type can be safely constructed out of any byte combination, 8 | //! then it may implement this trait. This is the case for primitive integer 9 | //! types (e.g. `i32`, `u32`, `i64`), arrays of other trivially transmutable 10 | //! types, and `repr(C)` structs composed of trivially transmutable values. 11 | //! 12 | //! However, they are still not entirely safe because the source data may not 13 | //! be correctly aligned for reading and writing a value of the target type. 14 | //! The effects of this range from less performance (e.g. x86) to trapping or 15 | //! address flooring (e.g. ARM), but this is undefined behavior nonetheless. 16 | 17 | 18 | use self::super::guard::{PermissiveGuard, PedanticGuard, Guard}; 19 | use self::super::base::{transmute_many, transmute_many_mut, from_bytes}; 20 | #[cfg(feature = "alloc")] 21 | use self::super::base::transmute_vec; 22 | use self::super::Error; 23 | #[cfg(feature = "alloc")] 24 | use alloc::vec::Vec; 25 | 26 | 27 | /// Type that can be constructed from any combination of bytes. 28 | /// 29 | /// A type `T` implementing this trait means that any arbitrary slice of bytes 30 | /// of length `size_of::()` can be safely interpreted as a value of that 31 | /// type with support for unaligned memory access. In most (but not all) 32 | /// cases this is a [*POD class*](http://eel.is/c++draft/class#10) or a 33 | /// [*trivially copyable class*](http://eel.is/c++draft/class#6). 34 | /// 35 | /// This serves as a marker trait for all functions in this module. 36 | /// 37 | /// Enable the `const_generics` feature to implement this for arbitrary `[T: TriviallyTransmutable, N]` arrays, 38 | /// instead of just 1-32. 39 | /// This, of course, requires a sufficiently fresh rustc (at least 1.51). 40 | /// 41 | /// *Warning*: if you transmute into a floating-point type you will have a chance to create a signaling NaN, 42 | /// which, while not illegal, can be unwieldy. Check out [`util::designalise_f{32,64}()`](util/index.html) 43 | /// for a remedy. 44 | /// 45 | /// *Nota bene*: `bool` is not `TriviallyTransmutable` because they're restricted to 46 | /// being `0` or `1`, which means that an additional value check is required. 47 | /// 48 | /// # Safety 49 | /// 50 | /// It is only safe to implement `TriviallyTransmutable` for a type `T` if it 51 | /// is safe to read or write a value `T` at the pointer of an arbitrary slice 52 | /// `&[u8]`, of length `size_of()`, as long as the same slice is 53 | /// *well aligned* in memory for reading and writing a `T`. 54 | /// 55 | /// Consult the [Transmutes section](https://doc.rust-lang.org/nomicon/transmutes.html) 56 | /// of the Nomicon for more details. 57 | pub unsafe trait TriviallyTransmutable: Copy {} 58 | 59 | 60 | unsafe impl TriviallyTransmutable for u8 {} 61 | unsafe impl TriviallyTransmutable for i8 {} 62 | unsafe impl TriviallyTransmutable for u16 {} 63 | unsafe impl TriviallyTransmutable for i16 {} 64 | unsafe impl TriviallyTransmutable for u32 {} 65 | unsafe impl TriviallyTransmutable for i32 {} 66 | unsafe impl TriviallyTransmutable for u64 {} 67 | unsafe impl TriviallyTransmutable for i64 {} 68 | unsafe impl TriviallyTransmutable for usize {} 69 | unsafe impl TriviallyTransmutable for isize {} 70 | unsafe impl TriviallyTransmutable for f32 {} 71 | unsafe impl TriviallyTransmutable for f64 {} 72 | #[cfg(i128_type)] 73 | unsafe impl TriviallyTransmutable for u128 {} 74 | #[cfg(i128_type)] 75 | unsafe impl TriviallyTransmutable for i128 {} 76 | 77 | #[cfg(not(feature = "const_generics"))] 78 | mod trivially_transmutable_arrays { 79 | use self::super::TriviallyTransmutable; 80 | unsafe impl TriviallyTransmutable for [T; 1] {} 81 | unsafe impl TriviallyTransmutable for [T; 2] {} 82 | unsafe impl TriviallyTransmutable for [T; 3] {} 83 | unsafe impl TriviallyTransmutable for [T; 4] {} 84 | unsafe impl TriviallyTransmutable for [T; 5] {} 85 | unsafe impl TriviallyTransmutable for [T; 6] {} 86 | unsafe impl TriviallyTransmutable for [T; 7] {} 87 | unsafe impl TriviallyTransmutable for [T; 8] {} 88 | unsafe impl TriviallyTransmutable for [T; 9] {} 89 | unsafe impl TriviallyTransmutable for [T; 10] {} 90 | unsafe impl TriviallyTransmutable for [T; 11] {} 91 | unsafe impl TriviallyTransmutable for [T; 12] {} 92 | unsafe impl TriviallyTransmutable for [T; 13] {} 93 | unsafe impl TriviallyTransmutable for [T; 14] {} 94 | unsafe impl TriviallyTransmutable for [T; 15] {} 95 | unsafe impl TriviallyTransmutable for [T; 16] {} 96 | unsafe impl TriviallyTransmutable for [T; 17] {} 97 | unsafe impl TriviallyTransmutable for [T; 18] {} 98 | unsafe impl TriviallyTransmutable for [T; 19] {} 99 | unsafe impl TriviallyTransmutable for [T; 20] {} 100 | unsafe impl TriviallyTransmutable for [T; 21] {} 101 | unsafe impl TriviallyTransmutable for [T; 22] {} 102 | unsafe impl TriviallyTransmutable for [T; 23] {} 103 | unsafe impl TriviallyTransmutable for [T; 24] {} 104 | unsafe impl TriviallyTransmutable for [T; 25] {} 105 | unsafe impl TriviallyTransmutable for [T; 26] {} 106 | unsafe impl TriviallyTransmutable for [T; 27] {} 107 | unsafe impl TriviallyTransmutable for [T; 28] {} 108 | unsafe impl TriviallyTransmutable for [T; 29] {} 109 | unsafe impl TriviallyTransmutable for [T; 30] {} 110 | unsafe impl TriviallyTransmutable for [T; 31] {} 111 | unsafe impl TriviallyTransmutable for [T; 32] {} 112 | } 113 | 114 | #[cfg(feature = "const_generics")] 115 | unsafe impl TriviallyTransmutable for [T; N] {} 116 | 117 | /// Transmute the slice to a slice of another type, ensuring alignment of the types is maintained. 118 | /// 119 | /// This function is equivalent to 120 | /// [`std::slice::align_to()`](https://doc.rust-lang.org/std/primitive.slice.html#method.align_to). 121 | /// 122 | /// However, since both source and target types are [trivially transmutable](./trait.TriviallyTransmutable.html), 123 | /// the operation is always safe. 124 | /// 125 | /// # Example 126 | /// 127 | /// ``` 128 | /// # use safe_transmute::trivial::align_to; 129 | /// let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; 130 | /// let (prefix, shorts, suffix) = align_to::<_, u16>(&bytes); 131 | /// 132 | /// // less_efficient_algorithm_for_bytes(prefix); 133 | /// // more_efficient_algorithm_for_aligned_shorts(shorts); 134 | /// // less_efficient_algorithm_for_bytes(suffix); 135 | /// 136 | /// assert_eq!(prefix.len() + shorts.len() * 2 + suffix.len(), 7); 137 | /// ``` 138 | pub fn align_to(slice: &[S]) -> (&[S], &[T], &[S]) { 139 | unsafe { slice.align_to::() } 140 | } 141 | 142 | /// Transmute the slice to a slice of another type, ensuring alignment of the types is maintained. 143 | /// 144 | /// This function is equivalent to 145 | /// [`std::slice::align_to_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.align_to_mut). 146 | /// 147 | /// However, since both source and target types are [trivially transmutable](./trait.TriviallyTransmutable.html), 148 | /// the operation is always safe. 149 | /// 150 | /// # Example 151 | /// 152 | /// ``` 153 | /// # use safe_transmute::trivial::align_to_mut; 154 | /// let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; 155 | /// let (prefix, shorts, suffix) = align_to_mut::<_, u16>(&mut bytes); 156 | /// 157 | /// // less_efficient_algorithm_for_bytes(prefix); 158 | /// // more_efficient_algorithm_for_aligned_shorts(shorts); 159 | /// // less_efficient_algorithm_for_bytes(suffix); 160 | /// 161 | /// assert_eq!(prefix.len() + shorts.len() * 2 + suffix.len(), 7); 162 | /// ``` 163 | pub fn align_to_mut(slice: &mut [S]) -> (&mut [S], &mut [T], &mut [S]) { 164 | unsafe { slice.align_to_mut::() } 165 | } 166 | 167 | /// Transmute a byte slice into a single instance of a trivially transmutable type. 168 | /// 169 | /// The byte slice must have at least enough bytes to fill a single instance of a type, 170 | /// extraneous data is ignored. 171 | /// 172 | /// # Errors 173 | /// 174 | /// An error is returned in one of the following situations: 175 | /// 176 | /// - The data does not have enough bytes for a single value `T`. 177 | /// 178 | /// # Safety 179 | /// 180 | /// This function invokes undefined behavior if the data does not have a memory 181 | /// alignment compatible with `T`. If this cannot be ensured, you will have to 182 | /// make a copy of the data, or change how it was originally made. 183 | /// 184 | /// # Examples 185 | /// 186 | /// ``` 187 | /// # use safe_transmute::trivial::transmute_trivial; 188 | /// # include!("../tests/test_util/le_to_native.rs"); 189 | /// # fn main() { 190 | /// // Little-endian 191 | /// unsafe { 192 | /// # /* 193 | /// assert_eq!(transmute_trivial::(&[0x00, 0x00, 0x00, 0x01])?, 0x0100_0000); 194 | /// # */ 195 | /// # assert_eq!(transmute_trivial::(&Le2NAl4([0x00, 0x00, 0x00, 0x01]).le_to_native::()).unwrap(), 0x0100_0000); 196 | /// } 197 | /// # } 198 | /// ``` 199 | pub unsafe fn transmute_trivial(bytes: &[u8]) -> Result> { 200 | from_bytes::(bytes) 201 | } 202 | 203 | /// Transmute a byte slice into a single instance of a trivially transmutable type. 204 | /// 205 | /// The byte slice must have exactly enough bytes to fill a single instance of a type. 206 | /// 207 | /// # Errors 208 | /// 209 | /// An error is returned in one of the following situations: 210 | /// 211 | /// - The data does not have a memory alignment compatible with `T`. You will 212 | /// have to make a copy anyway, or modify how the data was originally made. 213 | /// - The data does not have enough bytes for a single value `T`. 214 | /// - The data has more bytes than those required to produce a single value `T`. 215 | /// 216 | /// # Safety 217 | /// 218 | /// This function invokes undefined behavior if the data does not have a memory 219 | /// alignment compatible with `T`. If this cannot be ensured, you will have to 220 | /// make a copy of the data, or change how it was originally made. 221 | /// 222 | /// # Examples 223 | /// 224 | /// ``` 225 | /// # use safe_transmute::trivial::transmute_trivial_pedantic; 226 | /// # include!("../tests/test_util/le_to_native.rs"); 227 | /// # fn main() { 228 | /// // Little-endian 229 | /// unsafe { 230 | /// # /* 231 | /// assert_eq!(transmute_trivial_pedantic::(&[0x0F, 0x0E])?, 0x0E0F); 232 | /// # */ 233 | /// # assert_eq!(transmute_trivial_pedantic::(&Le2NAl2([0x0F, 0x0E]).le_to_native::()).unwrap(), 0x0E0F); 234 | /// } 235 | /// # } 236 | /// ``` 237 | pub unsafe fn transmute_trivial_pedantic(bytes: &[u8]) -> Result> { 238 | PedanticGuard::check::(bytes)?; 239 | from_bytes(bytes) 240 | } 241 | 242 | /// Transmute a byte slice into a single instance of a trivially transmutable type. 243 | /// 244 | /// The byte slice must have exactly enough bytes to fill a single instance of a type. 245 | /// 246 | /// # Errors 247 | /// 248 | /// An error is returned if the data does not comply with the policies of the 249 | /// given guard `G`. 250 | /// 251 | /// # Safety 252 | /// 253 | /// This function invokes undefined behavior if the data does not have a memory 254 | /// alignment compatible with `T`. If this cannot be ensured, you will have to 255 | /// make a copy of the data, or change how it was originally made. 256 | /// 257 | /// # Examples 258 | /// 259 | /// ``` 260 | /// # use safe_transmute::trivial::transmute_trivial_many; 261 | /// # use safe_transmute::SingleManyGuard; 262 | /// # include!("../tests/test_util/le_to_native.rs"); 263 | /// # fn main() { 264 | /// // Little-endian 265 | /// unsafe { 266 | /// # /* 267 | /// assert_eq!(transmute_trivial_many::(&[0x00, 0x01, 0x00, 0x02])?, 268 | /// # */ 269 | /// # assert_eq!(transmute_trivial_many::(&Le2NAl4([0x00, 0x01, 0x00, 0x02]).le_to_native::()).unwrap(), 270 | /// &[0x0100, 0x0200]); 271 | /// } 272 | /// # } 273 | /// ``` 274 | pub unsafe fn transmute_trivial_many(bytes: &[u8]) -> Result<&[T], Error> { 275 | transmute_many::(bytes) 276 | } 277 | 278 | /// Transmute a byte slice into a single instance of a trivially transmutable type. 279 | /// 280 | /// The byte slice must have exactly enough bytes to fill a single instance of a type. 281 | /// 282 | /// # Errors 283 | /// 284 | /// An error is returned in one of the following situations: 285 | /// 286 | /// - The data does not have enough bytes for a single value `T`. 287 | /// 288 | /// # Safety 289 | /// 290 | /// This function invokes undefined behavior if the data does not have a memory 291 | /// alignment compatible with `T`. If this cannot be ensured, you will have to 292 | /// make a copy of the data, or change how it was originally made. 293 | /// 294 | /// # Examples 295 | /// 296 | /// ``` 297 | /// # use safe_transmute::trivial::transmute_trivial_many; 298 | /// # use safe_transmute::SingleManyGuard; 299 | /// # include!("../tests/test_util/le_to_native.rs"); 300 | /// # fn main() { 301 | /// // Little-endian 302 | /// unsafe { 303 | /// # /* 304 | /// assert_eq!(transmute_trivial_many::(&[0x00, 0x01, 0x00, 0x02])?, 305 | /// # */ 306 | /// # assert_eq!(transmute_trivial_many::(&Le2NAl4([0x00, 0x01, 0x00, 0x02]).le_to_native::()).unwrap(), 307 | /// &[0x0100, 0x0200]); 308 | /// } 309 | /// # } 310 | /// ``` 311 | pub unsafe fn transmute_trivial_many_mut(bytes: &mut [u8]) -> Result<&mut [T], Error> { 312 | transmute_many_mut::(bytes) 313 | } 314 | 315 | /// View a byte slice as a slice of a trivially transmutable type. 316 | /// 317 | /// The resulting slice will have as many instances of a type as will fit, rounded down. 318 | #[deprecated(since = "0.11.0", note = "see `trivial::transmute_many()` with `PermissiveGuard` for the equivalent behavior")] 319 | pub unsafe fn guarded_transmute_pod_many_permissive(bytes: &[u8]) -> Result<&[T], Error> { 320 | Ok(transmute_many::(bytes)?) 321 | } 322 | 323 | /// View a byte slice as a slice of a trivially transmutable type. 324 | /// 325 | /// The byte slice must have at least enough bytes to fill a single instance of a type, 326 | /// and should not have extraneous data. 327 | #[deprecated(since = "0.11.0", note = "see `trivial::transmute_many()` with `PedanticGuard` for the equivalent behavior")] 328 | pub unsafe fn guarded_transmute_pod_many_pedantic(bytes: &[u8]) -> Result<&[T], Error> { 329 | transmute_many::(bytes) 330 | } 331 | 332 | 333 | /// Transform a vector into a vector of another element type. 334 | /// 335 | /// The vector's allocated byte buffer (if already allocated) will be reused. 336 | /// 337 | /// # Safety 338 | /// 339 | /// Vector transmutations are **exceptionally** dangerous because of 340 | /// the constraints imposed by 341 | /// [`Vec::from_raw_parts()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts). 342 | /// 343 | /// Unless *all* of the following requirements are fulfilled, this operation 344 | /// may result in undefined behavior. 345 | /// 346 | /// - The target type `T` must have the same size and minimum memory alignment 347 | /// requirements as the type `S`. 348 | /// 349 | /// # Examples 350 | /// 351 | /// ``` 352 | /// # use safe_transmute::trivial::transmute_trivial_vec; 353 | /// unsafe { 354 | /// assert_eq!( 355 | /// transmute_trivial_vec::(vec![0x00, 0x01, 0x00, 0x02]), 356 | /// vec![0x00, 0x01, 0x00, 0x02] 357 | /// ); 358 | /// } 359 | /// ``` 360 | #[cfg(feature = "alloc")] 361 | pub unsafe fn transmute_trivial_vec(vec: Vec) -> Vec { 362 | transmute_vec::(vec) 363 | } 364 | --------------------------------------------------------------------------------