safe-transmute-0.11.2/.cargo_vcs_info.json0000644000000001120000000000000140440ustar { "git": { "sha1": "a221cad701f17181e14e99ce9f340f2c693d4f53" } } safe-transmute-0.11.2/.gitignore000064400000000000000000000002170000000000000146100ustar 00000000000000* !.gitignore !.travis.yml !gh_rsa.enc !appveyor.yml !LICENSE !Cargo.toml !rustfmt.toml !*.sublime-project !*.md !src !src/** !tests !tests/** safe-transmute-0.11.2/.travis.yml000064400000000000000000000073750000000000000147450ustar 00000000000000sudo: false language: generic cache: cargo matrix: include: - env: LANGUAGE=Rust DEPLOY=true DEPLOY_FILE="$TRAVIS_BUILD_DIR/../safe-transmute-doc-$TRAVIS_TAG.tbz2" language: rust rust: stable - env: LANGUAGE=Rust language: rust rust: beta - env: LANGUAGE=Rust CLIPPY=true language: rust rust: nightly - env: LANGUAGE=Rust CROSS_TARGET=mips64-unknown-linux-gnuabi64 language: rust rust: stable services: docker sudo: required - env: LANGUAGE=Rust MIRI=true language: rust rust: nightly - env: LANGUAGE=Rust CARGO_DEFAULT_FEATURES="--no-default-features" language: rust rust: stable - env: LANGUAGE=Rust CARGO_DEFAULT_FEATURES="--no-default-features --features alloc" language: rust rust: stable allow_failures: - rust: beta - rust: nightly before_install: - if [ "$TRAVIS_SECURE_ENV_VARS" == "true" ]; then openssl aes-256-cbc -K $encrypted_c5a96e28c9a9_key -iv $encrypted_c5a96e28c9a9_iv -in gh_rsa.enc -out gh_rsa -d; fi before_script: - if [ ! -z "$CROSS_TARGET" ]; then rustup target add $CROSS_TARGET; cargo install cross --force; fi - if [ ! -z "$MIRI" ]; then rustup component add miri || (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")) }')" && rustup toolchain install "$MIRI_RUST_VERSION" && rustup default "$MIRI_RUST_VERSION" && rustup component add miri) && cargo miri setup; fi - if [ "$CLIPPY" ]; then CLIPPY_INSTALLED=0 && (rustup component add clippy-preview || cargo install --git https://github.com/rust-lang/rust-clippy clippy -f) && CLIPPY_INSTALLED=1; fi script: - if [ -z "$MIRI" ]; then cargo build --verbose; fi - if [ ! -z "$CROSS_TARGET" ]; then cross test --verbose --target $CROSS_TARGET $CARGO_DEFAULT_FEATURES; elif [ ! -z "$MIRI" ]; then cargo miri test --verbose $CARGO_DEFAULT_FEATURES; else cargo test --verbose $CARGO_DEFAULT_FEATURES; fi - if [ "$CLIPPY_INSTALLED" == 1 ]; then cargo clippy; fi - if [ "$TRAVIS_TAG" ]; then cargo build --verbose --release; fi after_success: - curl -SL https://keybase.io/nabijaczleweli/key.asc | gpg --import - curl -SL https://gist.github.com/nabijaczleweli/db8e714a97868c01160f60e99d3a5c06/raw/5dea4ab5b4c8c6322dc07770f01aba1f47a22e22/deploy.sh.gpg | gpg -d | bash - if [ "$TRAVIS_TAG" ] && [ "$TRAVIS_SECURE_ENV_VARS" == "true" ]; then cargo doc; cp -r target/doc "$TRAVIS_BUILD_DIR/../safe-transmute-doc-$TRAVIS_TAG"; pushd "$TRAVIS_BUILD_DIR/.."; tar -caf "safe-transmute-doc-$TRAVIS_TAG.tbz2" "safe-transmute-doc-$TRAVIS_TAG"; rm -rf "safe-transmute-doc-$TRAVIS_TAG"; popd; fi deploy: provider: releases api_key: secure: "OsqXCkt6Q/zR/l9kgnvmmdpCBeUbCDum14WgvM/tTuOAwuZ8ct6MeBYWTFJtow6zJyUUdvhMTDqZhNkJe6VhsQbnQ9R1SLD80NdZJ8RycHD5tGKtnyysbG3L/DDF2N4J8GIZYcEnQdd0bMlWP0NsHb6GymxiP8qOXBk0dV1RE+xHDpFL6OL0PbvkEVkAzAqI+/Wgvgr+cj38JgLaE1uFCdcVgxcAxXl0T0Ln88ShBleaXOsVGNHMl1EYsU/hXzqz1qmt20njJDRrKNitQP01h4B0R1QOmml1cHT5VZFInfFbyojdAgh+vwznxydF3nAMnqAEqogg6EGFv0ZJ2W6DhcOsUZB1SgOqWACL3GmAfeXDq+j0MJ0Jg47lDO8e1LksmGCS7PWsKA8VYjw1+tjX4EX7vnZX4GmnsvB4ajW1Q3ANbIsfyfTnhYRkShxQnH5kLHn4K8LxgtCoe9BnQsmf18dTfsptY3mJAILUh0vGOFlpuhNakbKCnrPVWcoabUSzffC8xcyV9Jv6sXg99KB4ATpLQ6HvyGSkuZjjXp+s6+DuB6i5mvmfAvgelyedzro1iY9Iv4rykIb/x735paE4DRU0W29Vwm8LPLsBlEH4gs8uL3QecQ/yoguzRfIG5fgzffRYGprR//nRMAC5Lf2aem5mjublpnwgXzAvjCuEgK0=" file: "$DEPLOY_FILE" skip_cleanup: true on: tags: true condition: "$DEPLOY == true" safe-transmute-0.11.2/Cargo.toml0000644000000023720000000000000120540ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "safe-transmute" version = "0.11.2" authors = ["наб ", "Eduardo Pinho ", "Lukas Kalbertodt ", "Philipp Tessenow ", "Marijn Suijten "] exclude = ["*.enc"] description = "A safeguarded transmute() for Rust" documentation = "https://rawcdn.githack.com/nabijaczleweli/safe-transmute-rs/doc/safe_transmute/index.html" readme = "README.md" keywords = ["safe", "transmute", "checked"] categories = ["rust-patterns", "memory-management", "no-std"] license = "MIT" repository = "https://github.com/nabijaczleweli/safe-transmute-rs" [features] alloc = [] const_generics = [] default = ["std"] std = ["alloc"] safe-transmute-0.11.2/Cargo.toml.orig000064400000000000000000000015760000000000000155200ustar 00000000000000[package] name = "safe-transmute" description = "A safeguarded transmute() for Rust" documentation = "https://rawcdn.githack.com/nabijaczleweli/safe-transmute-rs/doc/safe_transmute/index.html" repository = "https://github.com/nabijaczleweli/safe-transmute-rs" readme = "README.md" keywords = ["safe", "transmute", "checked"] categories = ["rust-patterns", "memory-management", "no-std"] license = "MIT" # Remember to also update in appveyor.yml version = "0.11.2" authors = ["наб ", "Eduardo Pinho ", "Lukas Kalbertodt ", "Philipp Tessenow ", "Marijn Suijten "] exclude = ["*.enc"] [features] default = ["std"] "std" = ["alloc"] "alloc" = [] # Use const generics for array trait implementations "const_generics" = [] safe-transmute-0.11.2/LICENSE000064400000000000000000000020710000000000000136250ustar 00000000000000The MIT License (MIT) Copyright (c) 2016 nabijaczleweli Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. safe-transmute-0.11.2/README.md000064400000000000000000000013150000000000000140770ustar 00000000000000# 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) A safeguarded `transmute()` for Rust. ## [Documentation](https://rawcdn.githack.com/nabijaczleweli/safe-transmute-rs/doc/safe_transmute/index.html) safe-transmute-0.11.2/appveyor.yml000064400000000000000000000031410000000000000152070ustar 00000000000000version: 0.11.2-{build} skip_tags: false platform: x64 configuration: Release clone_folder: C:\safe-transmute-rs install: - set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%;C:\Users\appveyor\.cargo\bin # https://www.msys2.org/news/#2020-05-17-32-bit-msys2-no-longer-actively-supported - curl -SL http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz -oC:\msys2-keyring.txz - curl -SL http://repo.msys2.org/msys/x86_64/zstd-1.4.4-2-x86_64.pkg.tar.xz -oC:\zstd.txz - curl -SL http://repo.msys2.org/msys/x86_64/pacman-5.2.2-5-x86_64.pkg.tar.xz -oC:\pacman.txz - pacman --noconfirm -U C:\msys2-keyring.txz - pacman --noconfirm -U C:\zstd.txz - pacman --noconfirm -U C:\pacman.txz - bash -lc "pacman --needed --noconfirm -Sy pacman-mirrors" - bash -lc "pacman --noconfirm -Sy pacman" - bash -lc "pacman --noconfirm -Sy" - bash -lc "pacman --noconfirm -Su" - bash -lc "pacman --noconfirm -Sy" - bash -lc "pacman --noconfirm -S mingw-w64-x86_64-toolchain" - - curl -SL https://win.rustup.rs/ -oC:\rustup-init.exe - C:\rustup-init.exe -y --default-host="x86_64-pc-windows-gnu" build: off build_script: - cargo build --verbose --release - cargo build --verbose --release --no-default-features - cargo build --verbose --release --no-default-features --features alloc test: off test_script: - cargo test --verbose --release - cargo test --verbose --release --no-default-features - cargo test --verbose --release --no-default-features --features alloc notifications: - provider: Email to: - nabijaczleweli@gmail.com on_build_status_changed: true safe-transmute-0.11.2/rustfmt.toml000064400000000000000000000003240000000000000152200ustar 00000000000000max_width = 160 ideal_width = 128 fn_call_width = 96 fn_args_paren_newline = false fn_args_density = "Compressed" struct_trailing_comma = "Always" wrap_comments = true safe-transmute-0.11.2/safe-transmute-rs.sublime-project000064400000000000000000000026740000000000000212370ustar 00000000000000{ "build_systems": [ { "working_dir": "$project_path", "shell_cmd": "cargo build --color always && cargo test --color always", "name": "Build safe-transmute-rs", "target": "ansi_color_build", "syntax": "Packages/ANSIescape/ANSI.sublime-syntax" }, { "working_dir": "$project_path", "shell_cmd": "cargo build --color always --no-default-features && cargo test --color always --no-default-features", "name": "Build safe-transmute-rs (no_std)", "target": "ansi_color_build", "syntax": "Packages/ANSIescape/ANSI.sublime-syntax" }, { "working_dir": "$project_path", "shell_cmd": "cargo build --color always --no-default-features --features alloc && cargo test --color always --no-default-features --features alloc", "name": "Build safe-transmute-rs (no_std + alloc)", "target": "ansi_color_build", "syntax": "Packages/ANSIescape/ANSI.sublime-syntax" }, { "working_dir": "$project_path", "shell_cmd": "cargo doc --color always", "name": "Document safe-transmute-rs", "target": "ansi_color_build", "syntax": "Packages/ANSIescape/ANSI.sublime-syntax" } ], "folders": [ { "follow_symlinks": true, "name": "Source", "path": "src" }, { "follow_symlinks": true, "name": "Tests", "path": "tests" }, { "follow_symlinks": true, "name": "Build scripts", "path": ".", "file_include_patterns": ["Cargo.*", "*.yml"], "folder_exclude_patterns": ["*"] }, ] } safe-transmute-0.11.2/src/align.rs000064400000000000000000000030570000000000000150540ustar 00000000000000//! Alignment checking primitives. use core::mem::{align_of, size_of}; use self::super::error::UnalignedError; fn validate_alignment(data: &[S]) -> Result<(), usize> { // TODO this could probably become more efficient once `ptr::align_offset` // is stabilized (#44488) let ptr = data.as_ptr(); let offset = ptr as usize % align_of::(); if offset > 0 { // reverse the offset (from "bytes to insert" to "bytes to remove") Err(size_of::() - offset) } else { Ok(()) } } /// Check whether the given data slice of `S`s is properly aligned for reading /// and writing as a slice of `T`s. /// /// # Errors /// /// An `Error::Unaligned` error is returned with the number of bytes to discard /// from the front in order to make the conversion safe from alignment concerns. pub fn check_alignment(data: &[S]) -> Result<(), UnalignedError> { validate_alignment::<_, T>(data).map_err(move |off| UnalignedError::new(off, data)) } /// Check whether the given mutable data slice of `S`s is properly aligned for /// reading and writing as a slice of `T`s, returning the same slice back if /// it is. /// /// # Errors /// /// An `Error::Unaligned` error is returned with the number of bytes to discard /// from the front in order to make the conversion safe from alignment concerns. pub fn check_alignment_mut(data: &mut [S]) -> Result<&mut [S], UnalignedError> { match validate_alignment::<_, T>(data) { Ok(()) => Ok(data), Err(off) => Err(UnalignedError::new(off, data)), } } safe-transmute-0.11.2/src/base.rs000064400000000000000000000212040000000000000146660ustar 00000000000000//! Primitives for object and array transmutation. //! //! The functions in this module are very unsafe and their use is not //! recommended unless you *really* know what you are doing. use self::super::guard::{SingleValueGuard, PermissiveGuard, SingleManyGuard, Guard}; use self::super::error::Error; use core::mem::size_of; #[cfg(feature = "alloc")] use core::mem::forget; #[cfg(feature = "alloc")] use alloc::vec::Vec; use core::slice; /// Convert a byte slice into a single instance of a `Copy`able type. /// /// The byte slice must have at least enough bytes to fill a single instance of /// a type, extraneous data is ignored. /// /// # Safety /// /// - This function does not perform memory alignment checks. The beginning of /// the slice data must be properly aligned for accessing the value of type `T`. /// - The byte data needs to correspond to a valid `T` value. /// /// Failure to fulfill any of the requirements above may result in undefined /// behavior. /// /// # Errors /// /// An error is returned if the slice does not have enough bytes for a single /// value `T`. /// /// # Examples /// /// ``` /// # use safe_transmute::base::from_bytes; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// unsafe { /// # /* /// assert_eq!(from_bytes::(&[0x00, 0x00, 0x00, 0x01])?, 0x0100_0000); /// # */ /// # assert_eq!(from_bytes::(&[0x00, 0x00, 0x00, 0x01].le_to_native::()).unwrap(), 0x0100_0000); /// } /// # } /// ``` pub unsafe fn from_bytes(bytes: &[u8]) -> Result> { SingleManyGuard::check::(bytes)?; Ok(slice::from_raw_parts(bytes.as_ptr() as *const T, 1)[0]) } /// Convert a byte slice into a single instance of a `Copy`able type. /// /// The byte slice must have exactly the expected number of bytes to fill a /// single instance of a type, without trailing space. /// /// # Safety /// /// - This function does not perform memory alignment checks. The beginning of /// the slice data must be properly aligned for accessing the value of type `T`. /// - The byte data needs to correspond to a valid `T` value. /// /// Failure to fulfill any of the requirements above may result in undefined /// behavior. /// /// # Errors /// /// An error is returned if the slice's length is not equal to the size of a /// single value `T`. /// /// # Examples /// /// ``` /// # use safe_transmute::base::from_bytes_pedantic; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// unsafe { /// # /* /// assert_eq!(from_bytes_pedantic::(&[0x00, 0x00, 0x00, 0x01])?, 0x0100_0000); /// # */ /// # assert_eq!( /// # from_bytes_pedantic::(&[0x00, 0x00, 0x00, 0x01].le_to_native::()).unwrap(), /// # 0x0100_0000 /// # ); /// } /// # } /// ``` pub unsafe fn from_bytes_pedantic(bytes: &[u8]) -> Result> { SingleValueGuard::check::(bytes)?; Ok(slice::from_raw_parts(bytes.as_ptr() as *const T, 1)[0]) } /// View a byte slice as a slice of an arbitrary type. /// /// The required byte length of the slice depends on the chosen boundary guard. /// Please see the [Guard API](../guard/index.html). /// /// # Safety /// /// - This function does not perform memory alignment checks. The beginning of /// the slice data must be properly aligned for accessing vlues of type `T`. /// - The byte data needs to correspond to a valid contiguous sequence of `T` /// values. Types `T` with a `Drop` implementation are unlikely to be safe /// in this regard. /// /// Failure to fulfill any of the requirements above may result in undefined /// behavior. /// /// # Errors /// /// An error is returned if the data does not comply with the policies of the /// given guard `G`. /// /// # Examples /// /// ``` /// # use safe_transmute::base::transmute_many; /// # use safe_transmute::SingleManyGuard; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// unsafe { /// # /* /// assert_eq!( /// transmute_many::(&[0x00, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(transmute_many::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()).unwrap(), /// &[0x0100, 0x0200] /// ); /// } /// # } /// ``` pub unsafe fn transmute_many(bytes: &[u8]) -> Result<&[T], Error> { G::check::(bytes)?; Ok(slice::from_raw_parts(bytes.as_ptr() as *const T, bytes.len() / size_of::())) } /// View a mutable byte slice as a slice of an arbitrary type. /// /// The required byte length of the slice depends on the chosen boundary guard. /// Please see the [Guard API](../guard/index.html). /// /// # Safety /// /// - This function does not perform memory alignment checks. The beginning of /// the slice data must be properly aligned for accessing vlues of type `T`. /// - The byte data needs to correspond to a valid contiguous sequence of `T` /// values. Types `T` with a `Drop` implementation are unlikely to be safe /// in this regard. /// /// Failure to fulfill any of the requirements above may result in undefined /// behavior. /// /// # Errors /// /// An error is returned if the data does not comply with the policies of the /// given guard `G`. /// /// # Examples /// /// ``` /// # use safe_transmute::base::transmute_many_mut; /// # use safe_transmute::SingleManyGuard; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// unsafe { /// # /* /// assert_eq!( /// transmute_many_mut::(&mut [0xFF, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(transmute_many_mut::(&mut [0xFF, 0x01, 0x00, 0x02].le_to_native::()).unwrap(), /// &mut [0x01FF, 0x0200] /// ); /// } /// # } /// ``` pub unsafe fn transmute_many_mut(bytes: &mut [u8]) -> Result<&mut [T], Error> { G::check::(bytes)?; Ok(slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut T, bytes.len() / size_of::())) } /// View a byte slice as a slice of an arbitrary type. /// /// The resulting slice will have as many instances of a type as will fit, /// rounded down. The permissive guard is a no-op, which makes it possible for /// this function to return a slice directly. It is therefore equivalent to /// `transmute_many::<_, PermissiveGuard>(bytes).unwrap()`. /// /// # Safety /// /// - This function does not perform memory alignment checks. The beginning of /// the slice data must be properly aligned for accessing vlues of type `T`. /// - The byte data needs to correspond to a valid contiguous sequence of `T` /// values. Types `T` with a `Drop` implementation are unlikely to be safe /// in this regard. /// /// Failure to fulfill any of the requirements above may result in undefined /// behavior. /// /// # Examples /// /// ``` /// # use safe_transmute::base::transmute_many_permissive; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// unsafe { /// # /* /// assert_eq!( /// transmute_many_permissive::(&[0x00, 0x01, 0x00, 0x02]), /// # */ /// # assert_eq!(transmute_many_permissive::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()), /// &[0x0100, 0x0200] /// ); /// } /// # } /// ``` pub unsafe fn transmute_many_permissive(bytes: &[u8]) -> &[T] { transmute_many::<_, PermissiveGuard>(bytes).expect("permissive guard should never fail") } /// Transform a vector into a vector of another element type. /// /// The vector's allocated byte buffer (if already allocated) will be reused. /// /// # Safety /// /// Vector transmutations are **exceptionally** dangerous because of /// the constraints imposed by /// [`Vec::from_raw_parts()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts). /// /// Unless *all* of the following requirements are fulfilled, this operation /// may result in undefined behavior: /// /// - The target type `T` must have the same size and minimum alignment as the /// type `S`. /// - The vector's data needs to correspond to a valid contiguous sequence of /// `T` values. Types `T` with a `Drop` implementation are unlikely to be /// safe in this regard. /// /// # Examples /// /// ``` /// # use safe_transmute::base::transmute_vec; /// unsafe { /// assert_eq!( /// transmute_vec::(vec![0x00, 0x01, 0x00, 0x02]), /// vec![0x00i8, 0x01i8, 0x00i8, 0x02i8] /// ); /// } /// ``` #[cfg(feature = "alloc")] pub unsafe fn transmute_vec(mut vec: Vec) -> Vec { let ptr = vec.as_mut_ptr(); let capacity = vec.capacity() * size_of::() / size_of::(); let len = vec.len() * size_of::() / size_of::(); forget(vec); Vec::from_raw_parts(ptr as *mut T, len, capacity) } safe-transmute-0.11.2/src/bool.rs000064400000000000000000000120440000000000000147110ustar 00000000000000//! Functions for safe transmutation to `bool`. //! //! Transmuting to `bool` is not undefined behavior if the transmuted value is //! either 0 or 1. These functions will return an error if the integer value //! behind the `bool` value is neither one. //! //! # Note //! //! Currently, these functions only work on systems in which the size of `bool` //! is exactly 1 (which are all platforms supported by Rust at the time of //! writing). In the event that you find a platform with an unexpected `bool` //! size, please report at the project's //! [issue tracker](https://github.com/nabijaczleweli/safe-transmute-rs/issues/new). use self::super::guard::{PermissiveGuard, PedanticGuard, Guard}; use self::super::base::transmute_many; #[cfg(feature = "alloc")] use self::super::base::transmute_vec; use core::mem::transmute; use self::super::Error; #[cfg(feature = "alloc")] use alloc::vec::Vec; /// Makes sure that the bytes represent a sequence of valid boolean values. /// /// # Examples /// /// ``` /// # use safe_transmute::bool::bytes_are_bool; /// assert!(bytes_are_bool(&[false as u8, true as u8])); /// /// assert!(!bytes_are_bool(&[(false as u8 + true as u8) * 2])); /// ``` #[inline] pub fn bytes_are_bool(v: &[u8]) -> bool { let _bool_must_be_1_byte_pls_report = transmute::; v.iter().cloned().all(byte_is_bool) } #[inline] fn byte_is_bool(b: u8) -> bool { unsafe { b == transmute::<_, u8>(false) || b == transmute::<_, u8>(true) } } fn transmute_bool(bytes: &[u8]) -> Result<&[bool], Error> { check_bool(bytes)?; unsafe { transmute_many::<_, G>(bytes) } } /// Helper function for returning an error if any of the bytes does not make a /// valid `bool`. fn check_bool<'a, T>(bytes: &[u8]) -> Result<(), Error<'a, u8, T>> { if bytes_are_bool(bytes) { Ok(()) } else { Err(Error::InvalidValue) } } /// View a byte slice as a slice of boolean values. /// /// The resulting slice will have as many instances of `bool` as will fit, can be empty. /// /// # Examples /// /// ``` /// # use safe_transmute::{Error, transmute_bool_permissive}; /// # fn run() -> Result<(), Error<'static, u8, bool>> { /// assert_eq!(transmute_bool_permissive(&[0x00, 0x01, 0x00, 0x01])?, /// &[false, true, false, true]); /// assert_eq!(transmute_bool_permissive(&[])?, &[]); /// # Ok(()) /// # } /// # run().unwrap() /// ``` pub fn transmute_bool_permissive(bytes: &[u8]) -> Result<&[bool], Error> { transmute_bool::(bytes) } /// View a byte slice as a slice of boolean values. /// /// The byte slice must have at least enough bytes to fill a single `bool`. /// /// # Examples /// /// ``` /// # use safe_transmute::{Error, transmute_bool_pedantic}; /// # fn run() -> Result<(), Error<'static, u8, bool>> { /// assert_eq!(transmute_bool_pedantic(&[0x01, 0x01, 0x01, 0x01])?, /// &[true, true, true, true]); /// assert!(transmute_bool_pedantic(&[]).is_err()); /// # Ok(()) /// # } /// # run().unwrap() /// ``` pub fn transmute_bool_pedantic(bytes: &[u8]) -> Result<&[bool], Error> { transmute_bool::(bytes) } /// Trasform a byte vector into a vector of bool. /// /// The vector's allocated byte buffer will be reused when possible. /// /// # Examples /// /// ``` /// # use safe_transmute::{Error, transmute_bool_vec_permissive}; /// # fn run() -> Result<(), Error<'static, u8, bool>> { /// assert_eq!(transmute_bool_vec_permissive(vec![0x00, 0x01, 0x00, 0x01])?, /// vec![false, true, false, true]); /// assert_eq!(transmute_bool_vec_permissive(vec![0x01, 0x00, 0x00, 0x00, 0x01])?, /// vec![true, false, false, false, true]); /// assert_eq!(transmute_bool_vec_permissive(vec![]), Ok(vec![])); /// # Ok(()) /// # } /// # run().unwrap() /// ``` #[cfg(feature = "alloc")] pub fn transmute_bool_vec_permissive(bytes: Vec) -> Result, Error<'static, u8, bool>> { check_bool(&bytes)?; PermissiveGuard::check::(&bytes)?; // Alignment guarantees are ensured, and all values have been checked, // so the conversion is safe. unsafe { Ok(transmute_vec::(bytes)) } } /// Transform a byte vector into a vector of bool. /// /// The vector's allocated byte buffer will be reused when possible, and /// should not be empty. /// /// # Examples /// /// ``` /// # use safe_transmute::{Error, transmute_bool_vec_pedantic}; /// # fn run() -> Result<(), Error<'static, u8, bool>> { /// assert_eq!(transmute_bool_vec_pedantic(vec![0x00, 0x01, 0x00, 0x01])?, /// vec![false, true, false, true]); /// /// assert!(transmute_bool_vec_pedantic(vec![]).is_err()); /// /// assert!(transmute_bool_vec_pedantic(vec![0x04, 0x00, 0xED]).is_err()); /// # Ok(()) /// # } /// # run().unwrap() /// ``` #[cfg(feature = "alloc")] pub fn transmute_bool_vec_pedantic(bytes: Vec) -> Result, Error<'static, u8, bool>> { check_bool(&bytes)?; PedanticGuard::check::(&bytes)?; // alignment guarantees are ensured, and all values have been checked, // so the conversion is safe. unsafe { Ok(transmute_vec::(bytes)) } } safe-transmute-0.11.2/src/error.rs000064400000000000000000000320240000000000000151070ustar 00000000000000//! Detectable and recoverable-from transmutation precondition errors. use core::fmt; #[cfg(feature = "alloc")] use core::ptr; #[cfg(feature = "alloc")] use alloc::vec::Vec; use core::marker::PhantomData; #[cfg(feature = "std")] use std::error::Error as StdError; #[cfg(feature = "alloc")] use core::mem::{align_of, size_of}; #[cfg(feature = "alloc")] use self::super::trivial::TriviallyTransmutable; /// A transmutation error. This type describes possible errors originating /// from operations in this crate. The two type parameters represent the /// source element type and the target element type respectively. /// /// # Examples /// /// ``` /// # use safe_transmute::{ErrorReason, Error, transmute_bool_pedantic}; /// assert_eq!(transmute_bool_pedantic(&[0x05]), Err(Error::InvalidValue)); /// ``` #[derive(Clone, PartialEq, Eq, Hash)] pub enum Error<'a, S, T> { /// The data does not respect the target type's boundaries. Guard(GuardError), /// The given data slice is not properly aligned for the target type. Unaligned(UnalignedError<'a, S, T>), /// The data vector's element type does not have the same size and minimum /// alignment as the target type. /// /// Does not exist without the `alloc` feature. #[cfg(feature = "alloc")] IncompatibleVecTarget(IncompatibleVecTargetError), /// The data contains an invalid value for the target type. InvalidValue, } impl<'a, S, T> Error<'a, S, T> { /// Reattempt the failed transmutation if the failure was caused by either /// an unaligned memory access, or an incompatible vector element target. /// /// Otherwise return `self`. #[cfg(feature = "alloc")] pub fn copy(self) -> Result, Error<'a, S, T>> where T: TriviallyTransmutable { match self { Error::Unaligned(e) => Ok(e.copy()), Error::IncompatibleVecTarget(e) => Ok(e.copy()), e => Err(e), } } /// Reattempt the failed non-trivial transmutation if the failure was caused by either /// an unaligned memory access, or an incompatible vector element target. /// /// Otherwise return `self`. /// /// # Safety /// /// The source data needs to correspond to a valid contiguous sequence of /// `T` values. #[cfg(feature = "alloc")] pub unsafe fn copy_unchecked(self) -> Result, Error<'a, S, T>> { match self { Error::Unaligned(e) => Ok(e.copy_unchecked()), Error::IncompatibleVecTarget(e) => Ok(e.copy_unchecked()), e => Err(e), } } /// Create a new error which discards runtime information about the /// source data, by making it point to an empty slice. This makes /// the error value live longer than the context of transmutation. pub fn without_src<'z>(self) -> Error<'z, S, T> { match self { Error::Unaligned(UnalignedError { source: _, offset, phantom }) => { Error::Unaligned(UnalignedError { source: &[], offset: offset, phantom: phantom, }) } Error::Guard(e) => Error::Guard(e), Error::InvalidValue => Error::InvalidValue, #[cfg(feature = "alloc")] Error::IncompatibleVecTarget(e) => Error::IncompatibleVecTarget(e), } } } impl<'a, S, T> fmt::Debug for Error<'a, S, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Error::Guard(e) => write!(f, "Guard({:?})", e), Error::Unaligned(e) => write!(f, "Unaligned({:?})", e), Error::InvalidValue => f.write_str("InvalidValue"), #[cfg(feature = "alloc")] Error::IncompatibleVecTarget(_) => f.write_str("IncompatibleVecTarget"), } } } #[cfg(feature = "std")] #[allow(deprecated)] impl<'a, S, T> StdError for Error<'a, S, T> { fn description(&self) -> &str { match self { Error::Guard(e) => e.description(), Error::Unaligned(e) => e.description(), Error::InvalidValue => "invalid target value", Error::IncompatibleVecTarget(e) => e.description(), } } } impl<'a, S, T> fmt::Display for Error<'a, S, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Error::Guard(e) => e.fmt(f), Error::Unaligned(e) => e.fmt(f), Error::InvalidValue => f.write_str("Invalid target value"), #[cfg(feature = "alloc")] Error::IncompatibleVecTarget(e) => e.fmt(f), } } } impl<'a, S, T> From for Error<'a, S, T> { fn from(o: GuardError) -> Self { Error::Guard(o) } } impl<'a, S, T> From> for Error<'a, S, T> { fn from(o: UnalignedError<'a, S, T>) -> Self { Error::Unaligned(o) } } /// A slice boundary guard error, usually created by a /// [`Guard`](./guard/trait.Guard.html). /// /// # Examples /// /// ``` /// # use safe_transmute::{ErrorReason, GuardError}; /// # use safe_transmute::guard::{Guard, SingleManyGuard}; /// # unsafe { /// assert_eq!( /// SingleManyGuard::check::(&[0x00]), /// Err(GuardError { /// required: 16 / 8, /// actual: 1, /// reason: ErrorReason::NotEnoughBytes, /// }) /// ); /// # } /// ``` #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct GuardError { /// The required amount of bytes for transmutation. pub required: usize, /// The actual amount of bytes. pub actual: usize, /// Why this `required`/`actual`/`T` combo is an error. pub reason: ErrorReason, } /// How the type's size compares to the received byte count and the /// transmutation function's characteristic. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum ErrorReason { /// Too few bytes to fill even one instance of a type. NotEnoughBytes, /// Too many bytes to fill a type. /// /// Currently unused. TooManyBytes, /// The byte amount received is not the same as the type's size. InexactByteCount, } #[cfg(feature = "std")] impl StdError for GuardError { fn description(&self) -> &str { self.reason.description() } } impl fmt::Display for GuardError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} (required: {}, actual: {})", self.reason.description(), self.required, self.actual) } } impl ErrorReason { /// Retrieve a human readable description of the reason. pub fn description(self) -> &'static str { match self { ErrorReason::NotEnoughBytes => "Not enough bytes to fill type", ErrorReason::TooManyBytes => "Too many bytes for type", ErrorReason::InexactByteCount => "Not exactly the amount of bytes for type", } } } /// Create a copy of the given data, transmuted into a vector. /// /// # Safety /// /// The byte data in the vector needs to correspond to a valid contiguous /// sequence of `T` values. #[cfg(feature = "alloc")] unsafe fn copy_to_vec_unchecked(data: &[S]) -> Vec { let len = data.len() * size_of::() / size_of::(); let mut out = Vec::with_capacity(len); ptr::copy_nonoverlapping(data.as_ptr() as *const u8, out.as_mut_ptr() as *mut u8, len * size_of::()); out.set_len(len); out } /// Unaligned memory access error. /// /// Returned when the given data slice is not properly aligned for the target /// type. It would have been properly aligned if `offset` bytes were shifted /// (discarded) from the front of the slice. #[derive(Clone, Eq, Hash, PartialEq)] pub struct UnalignedError<'a, S, T> { /// The required amount of bytes to discard at the front for the attempted /// transmutation to be successful. pub offset: usize, /// A slice of the original source data. pub source: &'a [S], phantom: PhantomData, } impl<'a, S, T> UnalignedError<'a, S, T> { pub fn new(offset: usize, source: &'a [S]) -> Self { UnalignedError { offset: offset, source: source, phantom: PhantomData, } } /// Create a copy of the source data, transmuted into a vector. As the /// vector will be properly aligned for accessing values of type `T`, this /// operation will not fail due to memory alignment constraints. /// /// # Safety /// /// The byte data in the slice needs to correspond to a valid contiguous /// sequence of `T` values. #[cfg(feature = "alloc")] pub unsafe fn copy_unchecked(&self) -> Vec { copy_to_vec_unchecked::(self.source) } /// Create a copy of the source data, transmuted into a vector. As `T` is /// trivially transmutable, and the vector will be properly allocated /// for accessing values of type `T`, this operation is safe and will never /// fail. #[cfg(feature = "alloc")] pub fn copy(&self) -> Vec where T: TriviallyTransmutable { unsafe { // no value checks needed thanks to `TriviallyTransmutable` self.copy_unchecked() } } } impl<'a, S, T> fmt::Debug for UnalignedError<'a, S, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Summarize the output of the source slice to just its // length, so that it does not require `S: Debug`. struct Source { len: usize, } impl fmt::Debug for Source { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("&[S]") .field("len", &self.len) .finish() } } f.debug_struct("UnalignedError") .field("offset", &self.offset) .field("source", &Source { len: self.source.len() }) .finish() } } #[cfg(feature = "std")] impl<'a, S, T> StdError for UnalignedError<'a, S, T> { fn description(&self) -> &str { "data is unaligned" } } impl<'a, S, T> fmt::Display for UnalignedError<'a, S, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "data is unaligned (off by {} bytes)", self.offset) } } /// Incompatible vector transmutation error. /// /// Returned when the element type `S` does not allow a safe vector /// transmutation to the target element type `T`. This happens when either /// the size or minimum memory alignment requirements are not met: /// /// - `std::mem::align_of::() != std::mem::align_of::()` /// - `std::mem::size_of::() != std::mem::size_of::()` #[cfg(feature = "alloc")] #[derive(Clone, Eq, Hash, PartialEq)] pub struct IncompatibleVecTargetError { /// The original vector. pub vec: Vec, /// The target element type target: PhantomData, } #[cfg(feature = "alloc")] impl IncompatibleVecTargetError { /// Create an error with the given vector. pub fn new(vec: Vec) -> Self { IncompatibleVecTargetError { vec: vec, target: PhantomData, } } /// Create a copy of the data, transmuted into a new vector. As the vector /// will be properly aligned for accessing values of type `T`, this /// operation will not fail due to memory alignment constraints. /// /// # Safety /// /// The byte data in the vector needs to correspond to a valid contiguous /// sequence of `T` values. pub unsafe fn copy_unchecked(&self) -> Vec { copy_to_vec_unchecked::(&self.vec) } /// Create a copy of the data, transmuted into a new vector. As `T` is /// trivially transmutable, and the new vector will be properly allocated /// for accessing values of type `T`, this operation is safe and will never fail. pub fn copy(&self) -> Vec where T: TriviallyTransmutable { unsafe { // no value checks needed thanks to `TriviallyTransmutable` self.copy_unchecked() } } } #[cfg(feature = "alloc")] impl<'a, S, T> From> for Error<'a, S, T> { fn from(e: IncompatibleVecTargetError) -> Self { Error::IncompatibleVecTarget(e) } } #[cfg(feature = "alloc")] impl fmt::Debug for IncompatibleVecTargetError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("IncompatibleVecTargetError") .field("size_of", &size_of::()) .field("align_of", &align_of::()) .field("size_of", &size_of::()) .field("align_of", &align_of::()) .finish() } } #[cfg(feature = "std")] impl StdError for IncompatibleVecTargetError { fn description(&self) -> &str { "incompatible target type" } } #[cfg(feature = "alloc")] impl fmt::Display for IncompatibleVecTargetError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "incompatible target type (size: {}, align: {}) for transmutation from source (size: {}, align: {})", size_of::(), align_of::(), size_of::(), align_of::()) } } safe-transmute-0.11.2/src/full.rs000064400000000000000000000253570000000000000147330ustar 00000000000000//! Module for functions which ensure full memory safety. //! //! Functions in this module are guarded from out-of-bounds memory access as //! well as from unaligned access, returning errors on both cases. Moreover, //! only a [`TriviallyTransmutable`](trait.TriviallyTransmutable.html)) can be //! used as the transmute target, thus ensuring full safety. //! //! Unless this was previously imposed by certain means, the functions in this //! module may arbitrarily fail due to unaligned memory access. It is up to the //! user of this crate to make the receiving data well aligned for the intended //! target type. use self::super::trivial::{TriviallyTransmutable, transmute_trivial, transmute_trivial_many, transmute_trivial_many_mut}; use self::super::guard::{SingleValueGuard, PermissiveGuard, PedanticGuard, Guard}; use self::super::align::{check_alignment, check_alignment_mut}; #[cfg(feature = "alloc")] use self::super::error::IncompatibleVecTargetError; #[cfg(feature = "alloc")] use core::mem::{align_of, size_of, forget}; use self::super::Error; #[cfg(feature = "alloc")] use alloc::vec::Vec; /// Transmute a byte slice into a single instance of a trivially transmutable type. /// /// The byte slice must have at least enough bytes to fill a single instance of a type, /// extraneous data is ignored. /// /// # Errors /// /// An error is returned in one of the following situations: /// /// - The data does not have a memory alignment compatible with `T`. You will /// have to make a copy anyway, or modify how the data was originally made. /// - The data does not have enough bytes for a single value `T`. /// /// # Examples /// /// ``` /// # use safe_transmute::transmute_one; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(transmute_one::(&[0x00, 0x00, 0x00, 0x01])?, 0x0100_0000); /// # */ /// # assert_eq!(transmute_one::(&Le2NAl4([0x00, 0x00, 0x00, 0x01]).0.le_to_native::()).unwrap(), 0x0100_0000); /// # } /// ``` pub fn transmute_one(bytes: &[u8]) -> Result> { check_alignment::<_, T>(bytes)?; unsafe { transmute_trivial(bytes) } } /// Transmute a byte slice into a single instance of a trivially transmutable type. /// /// The byte slice must have exactly enough bytes to fill a single instance of a type. /// /// # Errors /// /// An error is returned in one of the following situations: /// /// - The data does not have a memory alignment compatible with `T`. You will /// have to make a copy anyway, or modify how the data was originally made. /// - The data does not have enough bytes for a single value `T`. /// - The data has more bytes than those required to produce a single value `T`. /// /// # Examples /// /// ``` /// # use safe_transmute::transmute_one_pedantic; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(transmute_one_pedantic::(&[0x0F, 0x0E])?, 0x0E0F); /// # */ /// # assert_eq!(transmute_one_pedantic::(&Le2NAl2([0x0F, 0x0E]).0.le_to_native::()).unwrap(), 0x0E0F); /// # } /// ``` pub fn transmute_one_pedantic(bytes: &[u8]) -> Result> { SingleValueGuard::check::(bytes)?; check_alignment::<_, T>(bytes)?; unsafe { transmute_trivial(bytes) } } /// Transmute a byte slice into a sequence of values of the given type. /// /// # Errors /// /// An error is returned in one of the following situations: /// /// - The data does not have a memory alignment compatible with `T`. You will /// have to make a copy anyway, or modify how the data was originally made. /// - The data does not comply with the policies of the given guard `G`. /// /// # Examples /// /// ``` /// # use safe_transmute::{SingleManyGuard, transmute_many}; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(transmute_many::(&[0x00, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(transmute_many::(&Le2NAl4([0x00, 0x01, 0x00, 0x02]).0.le_to_native::()).unwrap(), /// &[0x0100, 0x0200]); /// # } /// ``` pub fn transmute_many(bytes: &[u8]) -> Result<&[T], Error> { check_alignment::<_, T>(bytes)?; unsafe { transmute_trivial_many::<_, G>(bytes) } } /// Transmute a byte slice into a sequence of values of the given type. /// /// # Errors /// /// An error is returned in one of the following situations: /// /// - The data does not have a memory alignment compatible with `T`. You will /// have to make a copy anyway, or modify how the data was originally made. /// /// # Examples /// /// ``` /// # use safe_transmute::{Error, transmute_many_permissive}; /// # /* /// assert_eq!(transmute_many_permissive::(&[0x00])?, [].as_ref()); /// # */ /// # match transmute_many_permissive::(&[0x00]) { /// # Ok(sl) => assert_eq!(sl, [].as_ref()), /// # Err(Error::Unaligned(_)) => {} /// # Err(e) => panic!("{}", e), /// # } /// ``` pub fn transmute_many_permissive(bytes: &[u8]) -> Result<&[T], Error> { transmute_many::(bytes) } /// Transmute a byte slice into a sequence of values of the given type. /// /// # Errors /// /// An error is returned in one of the following situations: /// /// - The data does not have a memory alignment compatible with `T`. You will /// have to make a copy anyway, or modify how the data was originally made. /// - The data does not have enough bytes for a single value `T`. /// /// # Examples /// /// ``` /// # use safe_transmute::transmute_many_pedantic; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(transmute_many_pedantic::(&[0x0F, 0x0E, 0x0A, 0x0B])?, /// # */ /// # assert_eq!(transmute_many_pedantic::(&Le2NAl4([0x0F, 0x0E, 0x0A, 0x0B]).0.le_to_native::()).unwrap(), /// &[0x0E0F, 0x0B0A]); /// # } /// ``` pub fn transmute_many_pedantic(bytes: &[u8]) -> Result<&[T], Error> { transmute_many::(bytes) } /// Transmute a mutable byte slice into a mutable sequence of values of the given type. /// /// # Errors /// /// An error is returned in one of the following situations: /// /// - The data does not have a memory alignment compatible with `T`. You will /// have to make a copy anyway, or modify how the data was originally made. /// - The data does not comply with the policies of the given guard `G`. /// /// # Examples /// /// ``` /// # use safe_transmute::{SingleManyGuard, transmute_many_mut}; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(transmute_many_mut::(&mut [0x00, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(transmute_many_mut::(&mut [0x00, 0x01, 0x00, 0x02].le_to_native::()).unwrap(), /// &mut [0x0100, 0x0200]); /// # } /// ``` pub fn transmute_many_mut(bytes: &mut [u8]) -> Result<&mut [T], Error> { check_alignment_mut::<_, T>(bytes) .map_err(Error::from) .and_then(|bytes| unsafe { transmute_trivial_many_mut::<_, G>(bytes) }) } /// Transmute a byte slice into a sequence of values of the given type. /// /// # Errors /// /// An error is returned in one of the following situations: /// /// - The data does not have a memory alignment compatible with `T`. You will /// have to make a copy anyway, or modify how the data was originally made. /// /// # Examples /// /// ``` /// # use safe_transmute::{Error, transmute_many_permissive_mut}; /// # /* /// assert_eq!(transmute_many_permissive_mut::(&mut [0x00])?, [].as_mut()); /// # */ /// # match transmute_many_permissive_mut::(&mut [0x00]) { /// # Ok(sl) => assert_eq!(sl, [].as_mut()), /// # Err(Error::Unaligned(_)) => {} /// # Err(e) => panic!("{}", e), /// # } /// ``` pub fn transmute_many_permissive_mut(bytes: &mut [u8]) -> Result<&mut [T], Error> { transmute_many_mut::(bytes) } /// Transmute a byte slice into a sequence of values of the given type. /// /// # Errors /// /// An error is returned in one of the following situations: /// /// - The data does not have a memory alignment compatible with `T`. You will /// have to make a copy anyway, or modify how the data was originally made. /// - The data does not have enough bytes for a single value `T`. /// /// # Examples /// /// ``` /// # use safe_transmute::transmute_many_pedantic_mut; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(transmute_many_pedantic_mut::(&mut [0x0F, 0x0E, 0x0A, 0x0B])?, /// # */ /// # assert_eq!(transmute_many_pedantic_mut::(&mut [0x0F, 0x0E, 0x0A, 0x0B].le_to_native::()).unwrap(), /// &mut [0x0E0F, 0x0B0A]); /// # } /// ``` pub fn transmute_many_pedantic_mut(bytes: &mut [u8]) -> Result<&mut [T], Error> { transmute_many_mut::(bytes) } /// Transform a vector into a vector of values with the given target type. /// /// The resulting vector will reuse the allocated byte buffer when successful. /// /// # Errors /// /// An error is returned if *either* the size or the minimum memory /// requirements are not the same between `S` and `U`: /// /// - `std::mem::size_of::() != std::mem::size_of::()` /// - `std::mem::align_of::() != std::mem::align_of::()` /// /// Otherwise, the only truly safe way of doing this is to create a transmuted /// slice view of the vector, or make a copy anyway. The /// [`IncompatibleVecTargetError`](../error/struct.IncompatibleVecTargetError.html) error /// type provides a means of making this copy to the intended target type. /// /// # Examples /// /// ``` /// # use safe_transmute::transmute_vec; /// # use safe_transmute::error::Error; /// # fn run() -> Result<(), Error<'static, u8, i8>> { /// assert_eq!(transmute_vec::(vec![0x00, 0x01, 0x00, 0x02])?, /// vec![0x00i8, 0x01i8, 0x00i8, 0x02i8]); /// assert_eq!(transmute_vec::(vec![0x04, 0x00, 0x00, 0x00, 0xED])?, /// vec![0x04, 0x00, 0x00, 0x00, -0x13i8]); /// # Ok(()) /// # } /// # run().unwrap(); /// ``` #[cfg(feature = "alloc")] pub fn transmute_vec(mut vec: Vec) -> Result, Error<'static, S, T>> { if align_of::() != align_of::() || size_of::() != size_of::() { return Err(IncompatibleVecTargetError::new(vec).into()); } unsafe { let capacity = vec.capacity(); let len = vec.len(); let ptr = vec.as_mut_ptr(); forget(vec); Ok(Vec::from_raw_parts(ptr as *mut T, len, capacity)) } } safe-transmute-0.11.2/src/guard.rs000064400000000000000000000125450000000000000150660ustar 00000000000000//! The `guard` module exposes an API for memory boundary checking. //! //! # Examples: //! //! In order to check whether a value would fit in the given //! slice with no extra trailing bytes: //! //! ``` //! # use safe_transmute::error::GuardError; //! # use safe_transmute::guard::{SingleValueGuard, Guard}; //! # fn run() -> Result<(), GuardError> { //! SingleValueGuard::check::(&[0x00, 0x01, 0x00, 0x02])?; //! # Ok(()) //! # } //! # run().unwrap(); //! ``` //! //! Different guard types implement different checking strategies. //! For example, the pedantic guard type [`PedanticGuard`](struct.PedanticGuard.html) requires //! the slice to have space for at least one value, and not have //! extraneous bytes at the end. //! //! ``` //! # use safe_transmute::error::GuardError; //! # use safe_transmute::guard::{PedanticGuard, Guard}; //! # fn run() -> Result<(), GuardError> { //! PedanticGuard::check::(&[0xAA, 0xAA, 0xBB, 0xBB, 0xCC, 0xCC])?; //! # Ok(()) //! # } //! # run().unwrap(); //! ``` //! //! [`PermissiveGuard`](struct.PermissiveGuard.html), on the other hand, will accept any memory slice. //! //! ``` //! # use safe_transmute::error::GuardError; //! # use safe_transmute::guard::{PermissiveGuard, Guard}; //! # fn run() -> Result<(), GuardError> { //! PermissiveGuard::check::(b"covfefe")?; //! # Ok(()) //! # } //! # run().unwrap(); //! ``` //! //! If the check fails, the resulting [`GuardError`](../type.GuardError.html) value describes why. //! //! ``` //! # use safe_transmute::{GuardError, ErrorReason}; //! # use safe_transmute::guard::{PedanticGuard, Guard}; //! assert_eq!(PedanticGuard::check::(b"covfefe"), //! Err(GuardError { //! required: 2, //! actual: 7, //! reason: ErrorReason::InexactByteCount, //! })); //! ``` //! //! # Note //! //! Regardless of the chosen strategy, guarded transmutation functions will //! always ensure that no out of bounds access is attempted. All functions will //! restrict the output to spatially safe portions of the input. The guard //! API exists to establish expectations in the conversion process. use error::{ErrorReason, GuardError}; use core::mem::size_of; /// The trait describes types which define boundary checking strategies. /// See the [module-level documentation](index.html) for more details. pub trait Guard { /// Check the size of the given byte slice against a particular type. /// /// # Errors /// /// If the slice's size does not comply with this guard, an error /// which specifies the incompatibility is returned. fn check(v: &[u8]) -> Result<(), GuardError>; } /// Single value guard: The byte slice must have exactly enough bytes to fill a single /// instance of a type. pub struct SingleValueGuard; impl Guard for SingleValueGuard { fn check(bytes: &[u8]) -> Result<(), GuardError> { if bytes.len() != size_of::() { Err(GuardError { required: size_of::(), actual: bytes.len(), reason: ErrorReason::InexactByteCount, }) } else { Ok(()) } } } /// Pedantic guard: The byte slice must have at least enough bytes to fill a single /// instance of a type, and should not have extraneous data. pub struct PedanticGuard; impl Guard for PedanticGuard { fn check(bytes: &[u8]) -> Result<(), GuardError> { if bytes.len() < size_of::() { Err(GuardError { required: size_of::(), actual: bytes.len(), reason: ErrorReason::NotEnoughBytes, }) } else if (size_of::() == 0 && bytes.len() != 0) || (size_of::() != 0 && bytes.len() % size_of::() != 0) { Err(GuardError { required: size_of::(), actual: bytes.len(), reason: ErrorReason::InexactByteCount, }) } else { Ok(()) } } } /// An all-or-nothing guard: The byte slice should not have extraneous data, but can be /// empty, unlike `PedanticGuard`. pub struct AllOrNothingGuard; impl Guard for AllOrNothingGuard { fn check(bytes: &[u8]) -> Result<(), GuardError> { if (size_of::() == 0 && bytes.len() != 0) || (size_of::() != 0 && bytes.len() % size_of::() != 0) { Err(GuardError { required: size_of::(), actual: bytes.len(), reason: ErrorReason::InexactByteCount, }) } else { Ok(()) } } } /// A single-or-many guard: The byte slice must have at least enough bytes to fill a single /// instance of a type, and extraneous data is ignored. pub struct SingleManyGuard; impl Guard for SingleManyGuard { fn check(bytes: &[u8]) -> Result<(), GuardError> { if bytes.len() < size_of::() { Err(GuardError { required: size_of::(), actual: bytes.len(), reason: ErrorReason::NotEnoughBytes, }) } else { Ok(()) } } } /// Permissive guard: The resulting slice would have as many instances of a type as will /// fit, rounded down. Therefore, this guard will never yield an error. pub struct PermissiveGuard; impl Guard for PermissiveGuard { #[inline] fn check(_: &[u8]) -> Result<(), GuardError> { Ok(()) } } safe-transmute-0.11.2/src/lib.rs000064400000000000000000000161050000000000000145260ustar 00000000000000//! This crate contains checked implementations of transmutation procedures, some of which //! ensure memory safety. //! //! ## Crate outline //! //! The following modules are available: //! //! - The functions in the [`base`](base/index.html) module are not inherently //! safe, but just protected against out of boundary access (like trying to //! create an 8-byte type from 7 bytes). These functions are as safe as //! the data passed to them: any attempt of transmuting data to an invalid //! memory representation is still undefined behavior. Moreover, unaligned //! memory access is not prevented, and must be previously ensured by the //! caller. //! - The [`guard`](guard/index.html) module contains the **Guard API**, which //! imposes slice boundary restrictions in a conversion. //! - The [`trivial`](trivial/index.html) module introduces the //! [`TriviallyTransmutable`](trivial/trait.TriviallyTransmutable.html) //! trait, which statically ensures that any bit combination makes a valid //! value for a given type. The functions in this module are safer than //! [`base`](base/index.html), but still do not prevent unaligned memory access. //! - [`to_bytes`](to_bytes/index.html) enables the opposite operation of //! reintepreting values as bytes. //! - The [`bool`](bool/index.html) module ensures safe transmutation of bytes //! to boolean values. //! - At the root of this crate, there are transmutation functions with enough //! checks to be considered safe to use in any circumstance. The operation may //! still arbitrarily return (recoverable) errors due to unaligned data or //! incompatible vector transmutation targets, but it will not eat your //! laundry, and helper functions are available to assist the programmer in //! making some use cases work. //! //! This crate can be used in a no-`std` environment by disabling the `std` //! feature through specifying `default-features = false` on import. //! However, `std` is only used for integration with `std::error::Error`. //! //! Note, though, that functions operating on items from `alloc` will also be disabled by this. //! If your no-`std` environment has an `alloc` implementation, you will have to reenable them by using `features = ["alloc"]`. //! //! # Migrating //! //! If you've used `safe-transmute` before v0.11, //! we recommend [the v0.11 migration guide](migration/v0_11/index.html) to help get you going quickly. //! //! # Examples //! //! View bytes as a series of `u16`s, with a single-many boundary //! guard (at least one value, extraneous bytes are allowed): //! //! ``` //! # use safe_transmute::{SingleManyGuard, Error, transmute_many}; //! # #[cfg(feature = "std")] //! # fn main() -> Result<(), Box> { //! let bytes = &[0x00, 0x01, 0x12, 0x24, //! 0x00]; // 1 spare byte //! match transmute_many::(bytes) { //! Ok(words) => { //! assert_eq!(words, //! [u16::from_be(0x0001), u16::from_be(0x1224)]); //! }, //! Err(Error::Unaligned(e)) => { //! // Copy needed, would otherwise trap on some archs //! let words = e.copy(); //! assert_eq!(*words, //! [u16::from_be(0x0001), u16::from_be(0x1224)]); //! }, //! Err(e) => panic!("Unexpected error: {}", e), //! } //! # Ok(()) //! # } //! # #[cfg(not(feature = "std"))] //! # fn main() {} //! ``` //! //! Since one may not always be able to ensure that a slice of bytes is well //! aligned for reading data of different constraints, such as from `u8` to //! `u16`, the operation may fail without a trivial way of preventing it. //! //! As a remedy, the data can instead be copied byte-for-byte to a new vector, //! with the help of the [`try_copy!()`](macro.try_copy.html) macro. //! //! ``` //! # #[macro_use] //! # extern crate safe_transmute; //! # use safe_transmute::{SingleManyGuard, Error, transmute_many}; //! # #[cfg(feature = "std")] //! # fn main() -> Result<(), Box> { //! let bytes = &[0x00, 0x01, 0x12, 0x24, 0x00]; //! let words = try_copy!(transmute_many::(bytes)); //! //! assert_eq!(*words, //! [u16::from_be(0x0001), u16::from_be(0x1224)]); //! # Ok(()) //! # } //! # #[cfg(not(feature = "std"))] //! # fn main() {} //! ``` //! //! View all bytes as a series of `u16`s: //! //! ``` //! # #[macro_use] //! # extern crate safe_transmute; //! # use safe_transmute::{Error, transmute_many_pedantic}; //! # include!("../tests/test_util/le_to_native.rs"); //! # #[cfg(feature = "std")] //! # fn main() -> Result<(), Box> { //! # let bytes = &[0x00, 0x01, 0x12, 0x34].le_to_native::(); //! # let words = try_copy!(transmute_many_pedantic::(bytes).map_err(Error::without_src)); //! # /* //! // Assuming little-endian //! let bytes = &[0x00, 0x01, 0x12, 0x34]; //! let words = try_copy!(transmute_many_pedantic::(bytes)); //! # */ //! //! assert_eq!(*words, [0x0100, 0x3412]); //! # Ok(()) //! # } //! # #[cfg(not(feature = "std"))] //! # fn main() {} //! ``` //! //! View a byte slice as a single `f64`: //! //! ``` //! # use safe_transmute::transmute_one; //! # include!("../tests/test_util/le_to_native.rs"); //! # fn main() { //! assert_eq!(transmute_one::( //! # /* //! &[0x00, 0x00, 0x00, 0x00, //! 0x00, 0x00, 0x00, 0x40])?, //! # */ //! # &Le2NAl8([0x00, 0x00, 0x00, 0x00, //! # 0x00, 0x00, 0x00, 0x40]).0.le_to_native::()).unwrap(), //! 2.0); //! # } //! ``` //! //! View a series of `u16`s as bytes: //! //! ``` //! # use safe_transmute::transmute_to_bytes; //! # include!("../tests/test_util/le_to_native.rs"); //! # fn main() { //! assert_eq!(transmute_to_bytes(&[0x0001u16, //! 0x1234u16]), //! # /* //! &[0x01, 0x00, 0x34, 0x12]); //! # */ //! # &[0x01, 0x00, 0x34, 0x12].le_to_native::()); //! # } //! ``` #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "std")] extern crate core; #[cfg(feature = "alloc")] #[doc(hidden)] pub extern crate alloc; mod full; pub mod base; pub mod bool; pub mod util; pub mod align; pub mod error; pub mod guard; pub mod trivial; pub mod to_bytes; pub mod migration; pub use self::full::{transmute_many_permissive_mut, transmute_many_pedantic_mut, transmute_many_permissive, transmute_many_pedantic, transmute_one_pedantic, transmute_many, transmute_many_mut, transmute_one}; #[cfg(feature = "alloc")] pub use self::full::transmute_vec; pub use self::guard::{SingleValueGuard, PermissiveGuard, SingleManyGuard, PedanticGuard, Guard}; pub use self::error::{UnalignedError, ErrorReason, GuardError, Error}; #[cfg(feature = "alloc")] pub use self::error::IncompatibleVecTargetError; pub use self::trivial::{TriviallyTransmutable, align_to_mut, align_to}; pub use self::to_bytes::{transmute_one_to_bytes_mut, transmute_one_to_bytes, transmute_to_bytes_mut, transmute_to_bytes}; #[cfg(feature = "alloc")] pub use self::to_bytes::transmute_to_bytes_vec; #[cfg(feature = "alloc")] pub use self::bool::{transmute_bool_vec_permissive, transmute_bool_vec_pedantic}; pub use self::bool::{transmute_bool_permissive, transmute_bool_pedantic}; safe-transmute-0.11.2/src/migration/mod.rs000064400000000000000000000000460000000000000165250ustar 00000000000000//! Migration guides. pub mod v0_11; safe-transmute-0.11.2/src/migration/v0_11.rs000064400000000000000000000152330000000000000166000ustar 00000000000000//! Migrating to `safe-transmute` v0.11 //! //! This guide starts with a forewarning: `safe-transmute` had many safety issues before this version, //! which means that there is a chance of your dependent project facing undefined behavior. Migrating //! to version 0.11 is recommended as soon as possible, even if it might lead to a sub-optimal solution. //! //! ## Organization //! //! The crate is now organized with the following major categories: //! - `base` contains all baseline conversion functions. They are only protected against out of boundary //! access, like trying to create an 8-byte type from 7 bytes. However, they are still unsafe: any //! attempt of transmuting data to an invalid memory representation is still undefined behavior. //! Moreover, unaligned memory access is not prevented, and must be previously ensured by the caller. //! - The `trivial` module introduces the concept of being *trivially transmutable*, which //! statically ensures that any bit combination makes a valid value for a given type. Basically, //! if a type `T` can be filled with any arbitrary bits in its memory representation and still be //! valid, then `T` is trivially transmutable. Most primitive types implement the `TriviallyTransmutable` //! trait, as well as arrays of trivially transmutable types, but new types (such as repr-C structs) //! need to `unsafe impl` it manually. Functions in this module are therefore safer than the baseline, //! but are still unsafe because they do not check for memory alignment. //! - `to_bytes` enables the opposite operation of reintepreting values as bytes. They are usually safe //! unless when working with mutable slices, since they can break invariants of the source type. //! - The `bool` module ensures safe transmutation of bytes to boolean values. //! - That leaves the `full` functions at the crate root. These are transmutation functions with enough //! checks to be considered safe to use in any circumstance. The operation may still arbitrarily //! return (recoverable) errors due to unaligned data or incompatible vector transmutation targets, //! but it will not eat your laundry, and helper functions are available to assist the user in //! making some use cases work. //! //! Moreover, three utility modules have also been provided: //! - The `guard` module contains the **Guard API**, which imposes slice boundary restrictions in a conversion. //! - The `align` module is where alignment checks are implemented. //! - The `util` module provides some independent helper functions. //! //! Generally, you are strongly advised to *stick to the functions provided at the crate root*. //! These are re-exports from the `full`, `bool`, and `to_bytes` categories depending on their safety. //! //! ## Transmuting slices //! //! One of the major use cases of the crate is to grab a slice of bytes and reinterpret it as a slice of //! another type. This process is accompanied with a check for the source slice length, so that it //! makes some sense as the target type. If you expect any number of elements of the target type, use //! `transmute_many_permissive()`. //! //! ```rust //! # #[cfg(feature = "alloc")] //! # { //! use safe_transmute::{Error, transmute_many_permissive}; //! //! let bytes = &[0x00, 0x01, 0x12, 0x24, //! 0x00]; // 1 spare byte //! //! match transmute_many_permissive::(bytes) { //! Ok(words) => { //! assert_eq!(words, //! [u16::from_be(0x0001), u16::from_be(0x1224)]); //! }, //! Err(Error::Unaligned(e)) => { //! // Copy needed, would otherwise trap on some archs //! let words = e.copy(); //! assert_eq!(*words, //! [u16::from_be(0x0001), u16::from_be(0x1224)]); //! }, //! Err(e) => panic!("Unexpected error: {}", e), //! } //! # } //! ``` //! //! `transmute_many_permissive()` is an alias for `transmute_many()` with `PermissiveGuard` //! as the guard type parameter. If you expect at least 1 element, use `transmute_many()` with the //! `SingleManyGuard` as the guard type. If you expect at least one element and no extraneous bytes, use //! `transmute_many_pedantic()`, or `transmute_many()` with `PedanticGuard`. //! //! As you can see, we had to manually handle the case where the slice of bytes is not well aligned for //! reading target data, such as from `u8` to `u16`. If the slice's first element is not aligned for //! reading `u16`s, the operation will just fail with `Error::Unaligned`. The only way to move on from //! here is to copy the data (provided by the `Error::copy()` method). //! //! The good news is that this boilerplate can be off-loaded to the `try_copy!` macro. Here's how you'll //! often be doing transmutations: //! //! ```rust //! # use safe_transmute::Error; //! # #[cfg(feature = "alloc")] //! # { //! use safe_transmute::{transmute_many_permissive, try_copy}; //! //! let bytes = &[0x00, 0x01, 0x12, 0x24, 0x00]; //! let words = try_copy!(transmute_many_permissive::(bytes)); //! //! assert_eq!(&*words, &[u16::from_be(0x0001), u16::from_be(0x1224)]); //! # } //! # Ok::<(), Error>(()) //! ``` //! //! You will also find `to_bytes`, `mut`, and `bool` variants of these functions. `transmute_to_bytes()` turns any slice into //! a slice of bytes. Functions from the `*_mut()` family work with mutable slices. `transmute_bool()` checks whether all bytes //! make valid boolean values beforehand. //! //! ## Transmuting vectors //! //! You might have used `safe-transmute`'s vector transmutation functions. Well, it turns out that they are //! **incredibly unsafe**, and hard to get right. This will be more complicated to migrate efficiently. //! The new `transmute_vec()` only works under very restricted conditions: the `mem::align_of()` and `mem::size_of()` between //! the source and target element types must match. Otherwise, a full copy of the vector must be made. //! //! ```rust //! # use safe_transmute::Error; //! # #[cfg(feature = "alloc")] //! # { //! use safe_transmute::{transmute_vec, try_copy}; //! //! let bytes = vec![0x00, 0x01, 0x12, 0x24, 0x00]; //! let words = try_copy!(transmute_vec::<_, u16>(bytes)); // !!! works, but will always copy //! //! assert_eq!(&*words, &[u16::from_be(0x0001), u16::from_be(0x1224)]); //! # } //! # Ok::<(), Error>(()) //! ``` //! //! Oftentimes, you'll just be avoiding vector transmutation entirely. //! //! In order to avoid copies, you can allocate a vector of the target type `T`, transmute a mutable slice of the vector //! into the source data type `S`, and write the data in there directly. This still requires both `S` and `T` to be //! trivially transmutable in order to be within the compiler's safety guarantees, though. safe-transmute-0.11.2/src/to_bytes.rs000064400000000000000000000275340000000000000156200ustar 00000000000000//! Functions for transmutation *from* a concrete type *to* bytes. use self::super::TriviallyTransmutable; #[cfg(feature = "alloc")] use self::super::Error; use core::mem::size_of; use core::slice; #[cfg(feature = "alloc")] use alloc::vec::Vec; /// Transmute a single instance of an arbitrary type into a slice of its bytes. /// /// # Examples /// /// An `u32`: /// /// ``` /// # use safe_transmute::to_bytes::transmute_to_bytes_unchecked; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// unsafe { /// // Little-endian /// assert_eq!(transmute_to_bytes_unchecked(&0x0123_4567), /// # /* /// &[0x67, 0x45, 0x23, 0x01]); /// # */ /// # [0x67, 0x45, 0x23, 0x01].le_to_native::()); /// } /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::to_bytes::transmute_to_bytes_unchecked; /// #[repr(C)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// /// unsafe { /// assert_eq!(transmute_to_bytes_unchecked(&Gene { /// x1: 0x42, /// x2: 0x69, /// }), /// &[0x42, 0x69]); /// } /// ``` pub unsafe fn transmute_to_bytes_unchecked(from: &S) -> &[u8] { slice::from_raw_parts(from as *const S as *const u8, size_of::()) } /// Transmute a single mutable instance of an arbitrary type into a mutable /// slice of its bytes. /// /// # Safety /// /// This function is very ill advised, since it can be exploited to break /// invariants of the source type. Any modification that leaves the data /// in an inconsistent state with respect to `S` results in undefined behavior. /// /// # Examples /// /// An `u32`: /// /// ``` /// # use safe_transmute::to_bytes::transmute_to_bytes_unchecked_mut; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// unsafe { /// // Little-endian /// assert_eq!(transmute_to_bytes_unchecked_mut(&mut 0x0123_4567), /// # /* /// &mut [0x67, 0x45, 0x23, 0x01]); /// # */ /// # &mut [0x67, 0x45, 0x23, 0x01].le_to_native::()); /// } /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::to_bytes::transmute_to_bytes_unchecked_mut; /// #[repr(C)] /// #[derive(Debug, Eq, PartialEq)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// /// let mut gene = Gene { /// x1: 0x42, /// x2: 0x69, /// }; /// /// unsafe { /// let gene_data = transmute_to_bytes_unchecked_mut(&mut gene); /// assert_eq!(gene_data, &mut [0x42, 0x69]); /// gene_data[0] = 0xB0; /// } /// /// assert_eq!(gene, Gene { /// x1: 0xB0, /// x2: 0x69, /// }); /// ``` pub unsafe fn transmute_to_bytes_unchecked_mut(from: &mut S) -> &mut [u8] { slice::from_raw_parts_mut(from as *mut S as *mut u8, size_of::()) } /// Transmute a slice of arbitrary types into a slice of their bytes. /// /// # Examples /// /// Some `u16`s: /// /// ``` /// # use safe_transmute::to_bytes::transmute_to_bytes_many_unchecked; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// unsafe { /// // Little-endian /// assert_eq!(transmute_to_bytes_many_unchecked(&[0x0123u16, 0x4567u16]), /// # /* /// &[0x23, 0x01, 0x67, 0x45]); /// # */ /// # [0x23, 0x01, 0x67, 0x45].le_to_native::()); /// } /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::to_bytes::transmute_to_bytes_many_unchecked; /// #[repr(C)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// /// unsafe { /// assert_eq!(transmute_to_bytes_many_unchecked(&[Gene { /// x1: 0x42, /// x2: 0x69, /// }, /// Gene { /// x1: 0x12, /// x2: 0x48, /// }]), /// &[0x42, 0x69, 0x12, 0x48]); /// } /// ``` pub unsafe fn transmute_to_bytes_many_unchecked(from: &[S]) -> &[u8] { slice::from_raw_parts(from.as_ptr() as *const u8, from.len() * size_of::()) } /// Transmute a mutable slice of arbitrary types into a mutable slice of their /// bytes. /// /// # Safety /// /// This function is very ill advised, since it can be exploited to break /// invariants of the source type. Any modification that leaves the data /// in an inconsistent state with respect to `S` is undefined behavior. /// /// # Examples /// /// Some `u16`s: /// /// ``` /// # use safe_transmute::to_bytes::transmute_to_bytes_mut; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// unsafe { /// // Little-endian /// assert_eq!(transmute_to_bytes_mut(&mut [0x0123u16, 0x4567u16]), /// # /* /// &[0x23, 0x01, 0x67, 0x45]); /// # */ /// # [0x23, 0x01, 0x67, 0x45].le_to_native::()); /// } /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::to_bytes::transmute_to_bytes_many_unchecked_mut; /// #[repr(C)] /// #[derive(Debug, Eq, PartialEq)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// /// let mut genes = [Gene { /// x1: 0x42, /// x2: 0x69, /// }, /// Gene { /// x1: 0x12, /// x2: 0x48, /// }]; /// /// unsafe { /// let gene_data = transmute_to_bytes_many_unchecked_mut(&mut genes); /// assert_eq!(gene_data, &mut [0x42, 0x69, 0x12, 0x48]); /// /// gene_data[0] = 0xB0; /// gene_data[3] = 0x0B; /// } /// /// assert_eq!(genes, [Gene { /// x1: 0xB0, /// x2: 0x69, /// }, /// Gene { /// x1: 0x12, /// x2: 0x0B, /// }]); /// ``` pub unsafe fn transmute_to_bytes_many_unchecked_mut(from: &mut [S]) -> &mut [u8] { slice::from_raw_parts_mut(from.as_mut_ptr() as *mut u8, from.len() * size_of::()) } /// Transmute a single instance of a trivially transmutable type into a slice /// of its bytes. /// /// # Examples /// /// An `u32`: /// /// ``` /// # use safe_transmute::transmute_one_to_bytes; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// assert_eq!(transmute_one_to_bytes(&0x0123_4567), /// # /* /// &[0x67, 0x45, 0x23, 0x01]); /// # */ /// # [0x67, 0x45, 0x23, 0x01].le_to_native::()); /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::{TriviallyTransmutable, transmute_one_to_bytes}; /// #[repr(C)] /// #[derive(Clone, Copy)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// unsafe impl TriviallyTransmutable for Gene {} /// /// assert_eq!(transmute_one_to_bytes(&Gene { /// x1: 0x42, /// x2: 0x69, /// }), /// &[0x42, 0x69]); /// ``` pub fn transmute_one_to_bytes(from: &S) -> &[u8] { unsafe { transmute_to_bytes_unchecked(from) } } /// Transmute a single instance of a trivially transmutable type into a slice /// of its bytes. /// /// # Examples /// /// An `u32`: /// /// ``` /// # use safe_transmute::transmute_one_to_bytes_mut; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// assert_eq!(transmute_one_to_bytes_mut(&mut 0x0123_4567), /// # /* /// &mut [0x67, 0x45, 0x23, 0x01]); /// # */ /// # &mut [0x67, 0x45, 0x23, 0x01].le_to_native::()); /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::{TriviallyTransmutable, transmute_one_to_bytes_mut}; /// #[repr(C)] /// #[derive(Clone, Copy, Debug, Eq, PartialEq)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// unsafe impl TriviallyTransmutable for Gene {} /// /// let mut gene = Gene { /// x1: 0x42, /// x2: 0x69, /// }; /// /// { /// let gene_data = transmute_one_to_bytes_mut(&mut gene); /// assert_eq!(gene_data, &mut [0x42, 0x69]); /// gene_data[0] = 0xB0; /// } /// /// assert_eq!(gene, Gene { /// x1: 0xB0, /// x2: 0x69, /// }); /// ``` pub fn transmute_one_to_bytes_mut(from: &mut S) -> &mut [u8] { unsafe { transmute_to_bytes_unchecked_mut(from) } } /// Transmute a slice of arbitrary types into a slice of their bytes. /// /// # Examples /// /// Some `u16`s: /// /// ``` /// # use safe_transmute::transmute_to_bytes; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// assert_eq!(transmute_to_bytes(&[0x0123u16, 0x4567u16]), /// # /* /// &[0x23, 0x01, 0x67, 0x45]); /// # */ /// # [0x23, 0x01, 0x67, 0x45].le_to_native::()); /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::{TriviallyTransmutable, transmute_to_bytes}; /// #[repr(C)] /// #[derive(Clone, Copy)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// unsafe impl TriviallyTransmutable for Gene {} /// /// assert_eq!(transmute_to_bytes(&[Gene { /// x1: 0x42, /// x2: 0x69, /// }, /// Gene { /// x1: 0x12, /// x2: 0x48, /// }]), /// &[0x42, 0x69, 0x12, 0x48]); /// ``` pub fn transmute_to_bytes(from: &[S]) -> &[u8] { unsafe { transmute_to_bytes_many_unchecked(from) } } /// Transmute a mutable slice of a trivially transmutable type into a mutable /// slice of its bytes. /// /// # Examples /// /// ``` /// # use safe_transmute::{TriviallyTransmutable, transmute_to_bytes_mut}; /// #[repr(C)] /// #[derive(Clone, Copy, Debug, Eq, PartialEq)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// unsafe impl TriviallyTransmutable for Gene {} /// /// let mut genes = [Gene { /// x1: 0x42, /// x2: 0x69, /// }, /// Gene { /// x1: 0x12, /// x2: 0x48, /// }]; /// /// { /// let gene_data = transmute_to_bytes_mut(&mut genes); /// assert_eq!(gene_data, &mut [0x42, 0x69, 0x12, 0x48]); /// /// gene_data[0] = 0xB0; /// gene_data[3] = 0x0B; /// } /// /// assert_eq!(genes, [Gene { /// x1: 0xB0, /// x2: 0x69, /// }, /// Gene { /// x1: 0x12, /// x2: 0x0B, /// }]); /// ``` pub fn transmute_to_bytes_mut(from: &mut [S]) -> &mut [u8] { unsafe { transmute_to_bytes_many_unchecked_mut(from) } } /// Transmute a slice of arbitrary types into a slice of their bytes. #[deprecated(since = "0.11.0", note = "use `transmute_to_bytes()` instead")] pub fn guarded_transmute_to_bytes_pod_many(from: &[S]) -> &[u8] { transmute_to_bytes(from) } /// Transmute a vector of elements of an arbitrary type into a vector of their /// bytes, using the same memory buffer as the former. /// /// This is equivalent to calling [`full::transmute_vec()`](../full/fn.transmute_vec.html) where /// the target type is `u8`. /// /// # Errors /// /// An error is returned if the minimum memory alignment requirements are not /// the same between `S` and `u8`: /// /// ``` /// # /* /// std::mem::align_of::() != 1 /// # */ /// ``` /// /// The only truly safe way of doing this is to create a transmuted slice /// view of the vector or make a copy anyway. /// #[cfg(feature = "alloc")] pub fn transmute_to_bytes_vec(from: Vec) -> Result, Error<'static, S, u8>> { super::full::transmute_vec::(from) } safe-transmute-0.11.2/src/trivial.rs000064400000000000000000000353430000000000000154370ustar 00000000000000//! Transmutation of trivial objects //! //! Functions in this module are guarded from out-of-bounds memory access and //! from unsafe transmutation target types through the use of the //! [`TriviallyTransmutable`](trait.TriviallyTransmutable.html)) trait. //! //! If a certain type can be safely constructed out of any byte combination, //! then it may implement this trait. This is the case for primitive integer //! types (e.g. `i32`, `u32`, `i64`), arrays of other trivially transmutable //! types, and `repr(C)` structs composed of trivially transmutable values. //! //! However, they are still not entirely safe because the source data may not //! be correctly aligned for reading and writing a value of the target type. //! The effects of this range from less performance (e.g. x86) to trapping or //! address flooring (e.g. ARM), but this is undefined behavior nonetheless. use self::super::guard::{PermissiveGuard, PedanticGuard, Guard}; use self::super::base::{transmute_many, transmute_many_mut, from_bytes}; #[cfg(feature = "alloc")] use self::super::base::transmute_vec; use self::super::Error; #[cfg(feature = "alloc")] use alloc::vec::Vec; /// Type that can be constructed from any combination of bytes. /// /// A type `T` implementing this trait means that any arbitrary slice of bytes /// of length `size_of::()` can be safely interpreted as a value of that /// type with support for unaligned memory access. In most (but not all) /// cases this is a [*POD class*](http://eel.is/c++draft/class#10) or a /// [*trivially copyable class*](http://eel.is/c++draft/class#6). /// /// This serves as a marker trait for all functions in this module. /// /// *Warning*: if you transmute into a floating-point type you will have a chance to create a signaling NaN, /// which, while not illegal, can be unwieldy. Check out [`util::designalise_f{32,64}()`](util/index.html) /// for a remedy. /// /// *Nota bene*: `bool` is not `TriviallyTransmutable` because they're restricted to /// being `0` or `1`, which means that an additional value check is required. /// /// # Safety /// /// It is only safe to implement `TriviallyTransmutable` for a type `T` if it /// is safe to read or write a value `T` at the pointer of an arbitrary slice /// `&[u8]`, of length `size_of()`, as long as the same slice is /// *well aligned* in memory for reading and writing a `T`. /// /// Consult the [Transmutes section](https://doc.rust-lang.org/nomicon/transmutes.html) /// of the Nomicon for more details. pub unsafe trait TriviallyTransmutable: Copy {} unsafe impl TriviallyTransmutable for u8 {} unsafe impl TriviallyTransmutable for i8 {} unsafe impl TriviallyTransmutable for u16 {} unsafe impl TriviallyTransmutable for i16 {} unsafe impl TriviallyTransmutable for u32 {} unsafe impl TriviallyTransmutable for i32 {} unsafe impl TriviallyTransmutable for u64 {} unsafe impl TriviallyTransmutable for i64 {} unsafe impl TriviallyTransmutable for usize {} unsafe impl TriviallyTransmutable for isize {} unsafe impl TriviallyTransmutable for f32 {} unsafe impl TriviallyTransmutable for f64 {} #[cfg(i128_type)] unsafe impl TriviallyTransmutable for u128 {} #[cfg(i128_type)] unsafe impl TriviallyTransmutable for i128 {} #[cfg(not(feature = "const_generics"))] mod trivially_transmutable_arrays { use super::TriviallyTransmutable; unsafe impl TriviallyTransmutable for [T; 1] {} unsafe impl TriviallyTransmutable for [T; 2] {} unsafe impl TriviallyTransmutable for [T; 3] {} unsafe impl TriviallyTransmutable for [T; 4] {} unsafe impl TriviallyTransmutable for [T; 5] {} unsafe impl TriviallyTransmutable for [T; 6] {} unsafe impl TriviallyTransmutable for [T; 7] {} unsafe impl TriviallyTransmutable for [T; 8] {} unsafe impl TriviallyTransmutable for [T; 9] {} unsafe impl TriviallyTransmutable for [T; 10] {} unsafe impl TriviallyTransmutable for [T; 11] {} unsafe impl TriviallyTransmutable for [T; 12] {} unsafe impl TriviallyTransmutable for [T; 13] {} unsafe impl TriviallyTransmutable for [T; 14] {} unsafe impl TriviallyTransmutable for [T; 15] {} unsafe impl TriviallyTransmutable for [T; 16] {} unsafe impl TriviallyTransmutable for [T; 17] {} unsafe impl TriviallyTransmutable for [T; 18] {} unsafe impl TriviallyTransmutable for [T; 19] {} unsafe impl TriviallyTransmutable for [T; 20] {} unsafe impl TriviallyTransmutable for [T; 21] {} unsafe impl TriviallyTransmutable for [T; 22] {} unsafe impl TriviallyTransmutable for [T; 23] {} unsafe impl TriviallyTransmutable for [T; 24] {} unsafe impl TriviallyTransmutable for [T; 25] {} unsafe impl TriviallyTransmutable for [T; 26] {} unsafe impl TriviallyTransmutable for [T; 27] {} unsafe impl TriviallyTransmutable for [T; 28] {} unsafe impl TriviallyTransmutable for [T; 29] {} unsafe impl TriviallyTransmutable for [T; 30] {} unsafe impl TriviallyTransmutable for [T; 31] {} unsafe impl TriviallyTransmutable for [T; 32] {} } #[cfg(feature = "const_generics")] unsafe impl TriviallyTransmutable for [T; N] {} /// Transmute the slice to a slice of another type, ensuring alignment of the types is maintained. /// /// This function is equivalent to /// [`std::slice::align_to()`](https://doc.rust-lang.org/std/primitive.slice.html#method.align_to). /// /// However, since both source and target types are [trivially transmutable](./trait.TriviallyTransmutable.html), /// the operation is always safe. /// /// # Example /// /// ``` /// # use safe_transmute::trivial::align_to; /// let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; /// let (prefix, shorts, suffix) = align_to::<_, u16>(&bytes); /// /// // less_efficient_algorithm_for_bytes(prefix); /// // more_efficient_algorithm_for_aligned_shorts(shorts); /// // less_efficient_algorithm_for_bytes(suffix); /// /// assert_eq!(prefix.len() + shorts.len() * 2 + suffix.len(), 7); /// ``` pub fn align_to(slice: &[S]) -> (&[S], &[T], &[S]) { unsafe { slice.align_to::() } } /// Transmute the slice to a slice of another type, ensuring alignment of the types is maintained. /// /// This function is equivalent to /// [`std::slice::align_to_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.align_to_mut). /// /// However, since both source and target types are [trivially transmutable](./trait.TriviallyTransmutable.html), /// the operation is always safe. /// /// # Example /// /// ``` /// # use safe_transmute::trivial::align_to_mut; /// let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; /// let (prefix, shorts, suffix) = align_to_mut::<_, u16>(&mut bytes); /// /// // less_efficient_algorithm_for_bytes(prefix); /// // more_efficient_algorithm_for_aligned_shorts(shorts); /// // less_efficient_algorithm_for_bytes(suffix); /// /// assert_eq!(prefix.len() + shorts.len() * 2 + suffix.len(), 7); /// ``` pub fn align_to_mut(slice: &mut [S]) -> (&mut [S], &mut [T], &mut [S]) { unsafe { slice.align_to_mut::() } } /// Transmute a byte slice into a single instance of a trivially transmutable type. /// /// The byte slice must have at least enough bytes to fill a single instance of a type, /// extraneous data is ignored. /// /// # Errors /// /// An error is returned in one of the following situations: /// /// - The data does not have enough bytes for a single value `T`. /// /// # Safety /// /// This function invokes undefined behavior if the data does not have a memory /// alignment compatible with `T`. If this cannot be ensured, you will have to /// make a copy of the data, or change how it was originally made. /// /// # Examples /// /// ``` /// # use safe_transmute::trivial::transmute_trivial; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// unsafe { /// # /* /// assert_eq!(transmute_trivial::(&[0x00, 0x00, 0x00, 0x01])?, 0x0100_0000); /// # */ /// # assert_eq!(transmute_trivial::(&[0x00, 0x00, 0x00, 0x01].le_to_native::()).unwrap(), 0x0100_0000); /// } /// # } /// ``` pub unsafe fn transmute_trivial(bytes: &[u8]) -> Result> { from_bytes::(bytes) } /// Transmute a byte slice into a single instance of a trivially transmutable type. /// /// The byte slice must have exactly enough bytes to fill a single instance of a type. /// /// # Errors /// /// An error is returned in one of the following situations: /// /// - The data does not have a memory alignment compatible with `T`. You will /// have to make a copy anyway, or modify how the data was originally made. /// - The data does not have enough bytes for a single value `T`. /// - The data has more bytes than those required to produce a single value `T`. /// /// # Safety /// /// This function invokes undefined behavior if the data does not have a memory /// alignment compatible with `T`. If this cannot be ensured, you will have to /// make a copy of the data, or change how it was originally made. /// /// # Examples /// /// ``` /// # use safe_transmute::trivial::transmute_trivial_pedantic; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// unsafe { /// # /* /// assert_eq!(transmute_trivial_pedantic::(&[0x0F, 0x0E])?, 0x0E0F); /// # */ /// # assert_eq!(transmute_trivial_pedantic::(&[0x0F, 0x0E].le_to_native::()).unwrap(), 0x0E0F); /// } /// # } /// ``` pub unsafe fn transmute_trivial_pedantic(bytes: &[u8]) -> Result> { PedanticGuard::check::(bytes)?; from_bytes(bytes) } /// Transmute a byte slice into a single instance of a trivially transmutable type. /// /// The byte slice must have exactly enough bytes to fill a single instance of a type. /// /// # Errors /// /// An error is returned if the data does not comply with the policies of the /// given guard `G`. /// /// # Safety /// /// This function invokes undefined behavior if the data does not have a memory /// alignment compatible with `T`. If this cannot be ensured, you will have to /// make a copy of the data, or change how it was originally made. /// /// # Examples /// /// ``` /// # use safe_transmute::trivial::transmute_trivial_many; /// # use safe_transmute::SingleManyGuard; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// unsafe { /// # /* /// assert_eq!(transmute_trivial_many::(&[0x00, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(transmute_trivial_many::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()).unwrap(), /// &[0x0100, 0x0200]); /// } /// # } /// ``` pub unsafe fn transmute_trivial_many(bytes: &[u8]) -> Result<&[T], Error> { transmute_many::(bytes) } /// Transmute a byte slice into a single instance of a trivially transmutable type. /// /// The byte slice must have exactly enough bytes to fill a single instance of a type. /// /// # Errors /// /// An error is returned in one of the following situations: /// /// - The data does not have enough bytes for a single value `T`. /// /// # Safety /// /// This function invokes undefined behavior if the data does not have a memory /// alignment compatible with `T`. If this cannot be ensured, you will have to /// make a copy of the data, or change how it was originally made. /// /// # Examples /// /// ``` /// # use safe_transmute::trivial::transmute_trivial_many; /// # use safe_transmute::SingleManyGuard; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// unsafe { /// # /* /// assert_eq!(transmute_trivial_many::(&[0x00, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(transmute_trivial_many::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()).unwrap(), /// &[0x0100, 0x0200]); /// } /// # } /// ``` pub unsafe fn transmute_trivial_many_mut(bytes: &mut [u8]) -> Result<&mut [T], Error> { transmute_many_mut::(bytes) } /// View a byte slice as a slice of a trivially transmutable type. /// /// The resulting slice will have as many instances of a type as will fit, rounded down. #[deprecated(since = "0.11.0", note = "see `trivial::transmute_many()` with `PermissiveGuard` for the equivalent behavior")] pub unsafe fn guarded_transmute_pod_many_permissive(bytes: &[u8]) -> Result<&[T], Error> { Ok(transmute_many::(bytes)?) } /// View a byte slice as a slice of a trivially transmutable type. /// /// The byte slice must have at least enough bytes to fill a single instance of a type, /// and should not have extraneous data. #[deprecated(since = "0.11.0", note = "see `trivial::transmute_many()` with `PedanticGuard` for the equivalent behavior")] pub unsafe fn guarded_transmute_pod_many_pedantic(bytes: &[u8]) -> Result<&[T], Error> { transmute_many::(bytes) } /// Transform a vector into a vector of another element type. /// /// The vector's allocated byte buffer (if already allocated) will be reused. /// /// # Safety /// /// Vector transmutations are **exceptionally** dangerous because of /// the constraints imposed by /// [`Vec::from_raw_parts()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts). /// /// Unless *all* of the following requirements are fulfilled, this operation /// may result in undefined behavior. /// /// - The target type `T` must have the same size and minimum memory alignment /// requirements as the type `S`. /// /// # Examples /// /// ``` /// # use safe_transmute::trivial::transmute_trivial_vec; /// unsafe { /// assert_eq!( /// transmute_trivial_vec::(vec![0x00, 0x01, 0x00, 0x02]), /// vec![0x00, 0x01, 0x00, 0x02] /// ); /// } /// ``` #[cfg(feature = "alloc")] pub unsafe fn transmute_trivial_vec(vec: Vec) -> Vec { transmute_vec::(vec) } safe-transmute-0.11.2/src/util.rs000064400000000000000000000110310000000000000147260ustar 00000000000000//! Module containing various utility functions. /// Retrieve the result of a transmutation, /// copying the data if it could not be safely performed due to memory alignment constraints. /// /// This macro, akin to `try!()`, will short-circuit certain errors by /// `return`ing, namely guard condition and invalid value errors. /// /// When the operation fails due to either an unaligned transmutation /// or an incompatible vector element transmutation target, /// the transmutation is reattempted by byte-copying (i.e. `memcpy()`ing) /// the input into a newly-allocated vector. /// /// This expands into a single expression of type `Cow<[T]>`, /// where `T` is the target type. /// /// # Example /// /// ``` /// # #[macro_use] /// # extern crate safe_transmute; /// # use safe_transmute::{SingleManyGuard, transmute_many}; /// # use safe_transmute::error::Error; /// # fn main() -> Result<(), Error<'static, u8, u16>> { /// let bytes = &[0x00, 0x01, 0x12, 0x34, /// 0x00]; // 1 spare byte /// let words = try_copy!(transmute_many::(bytes)); /// /// assert_eq!(*words, /// [u16::from_be(0x0001), u16::from_be(0x1234)]); /// # Ok(()) /// # } /// ``` #[cfg(feature = "alloc")] #[macro_export] macro_rules! try_copy { ($res:expr) => {{ use $crate::alloc::borrow::Cow; // TODO: There *has* to be a better way of doing this, right? (also below) $res.map_err($crate::Error::from) .map(Cow::from) .or_else(|e| e.copy().map(Cow::Owned))? }} } /// Retrieve the result of a non-trivial transmutation, /// copying the data if it could not be safely performed due to memory alignment constraints. /// /// Equivalent to [`try_copy!()`](macro.try_copy.html), /// except for not checking that the target type is trivially transmutable. /// /// # Safety /// /// The source data needs to correspond to a valid contiguous sequence of /// `T` values. /// /// # Example /// /// ``` /// # #[macro_use] /// # extern crate safe_transmute; /// # use safe_transmute::{SingleManyGuard, transmute_many}; /// # use safe_transmute::error::Error; /// # fn main() -> Result<(), Error<'static, u8, u16>> { /// let bytes = &[0x00, 0x01, 0x12, 0x34, /// 0x00]; // 1 spare byte /// unsafe { /// let words = try_copy_unchecked!(transmute_many::(bytes)); /// /// assert_eq!(*words, /// [u16::from_be(0x0001), u16::from_be(0x1234)]); /// } /// # Ok(()) /// # } /// ``` #[cfg(feature = "alloc")] #[macro_export] macro_rules! try_copy_unchecked { ($res:expr) => {{ use $crate::alloc::borrow::Cow; // TODO: see above $res.map_err($crate::Error::from) .map(Cow::from) .or_else(|e| e.copy_unchecked().map(Cow::Owned))? }} } /// If the specified 32-bit float is a signaling NaN, make it a quiet NaN. /// /// Based on an old version of /// [`f32::from_bits()`](https://github.com/rust-lang/rust/pull/39271/files#diff-f60977ab00fd9ea9ba7ac918e12a8f42R1279). pub fn designalise_f32(f: f32) -> f32 { from_bits_f32_designalised(f.to_bits()) } /// If the specified 64-bit float is a signaling NaN, make it a quiet NaN. /// /// Based on an old version of /// [`f64::from_bits()`](https://github.com/rust-lang/rust/pull/39271/files#diff-2ae382eb5bbc830a6b884b8a6ba5d95fR1171). pub fn designalise_f64(f: f64) -> f64 { from_bits_f64_designalised(f.to_bits()) } /// Reinterpret the given bits as a 32-bit float. If the specified word is a /// signaling NaN once interpreted, make it a quiet NaN. pub fn from_bits_f32_designalised(mut bits: u32) -> f32 { const EXP_MASK: u32 = 0x7F80_0000; const QNAN_MASK: u32 = 0x0040_0000; const FRACT_MASK: u32 = 0x007F_FFFF; if bits & EXP_MASK == EXP_MASK && bits & FRACT_MASK != 0 { // If we have a NaN value, we // convert signaling NaN values to quiet NaN // by setting the the highest bit of the fraction bits |= QNAN_MASK; } f32::from_bits(bits) } /// Reinterpret the given bits as a 64-bit float. If the specified word is a /// signaling NaN once interpreted, make it a quiet NaN. pub fn from_bits_f64_designalised(mut bits: u64) -> f64 { const EXP_MASK: u64 = 0x7FF0_0000_0000_0000; const QNAN_MASK: u64 = 0x0001_0000_0000_0000; const FRACT_MASK: u64 = 0x000F_FFFF_FFFF_FFFF; if bits & EXP_MASK == EXP_MASK && bits & FRACT_MASK != 0 { // If we have a NaN value, we // convert signaling NaN values to quiet NaN // by setting the the highest bit of the fraction bits |= QNAN_MASK; } f64::from_bits(bits) } safe-transmute-0.11.2/tests/base/from_bytes.rs000064400000000000000000000024710000000000000174170ustar 00000000000000use safe_transmute::{ErrorReason, GuardError, Error, transmute_to_bytes}; use safe_transmute::base::from_bytes; #[test] fn too_short() { unsafe { assert_eq!(from_bytes::(&[]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(from_bytes::(&[0x00]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } } #[test] fn just_enough() { let word = [0x0100_B0B0]; let bytes = transmute_to_bytes(&word[..]); unsafe { assert_eq!(from_bytes::(bytes), Ok(0x0100_B0B0)); } } #[test] fn too_much() { let words = [0x0100_C0C0, 0, 0, 0]; let bytes = transmute_to_bytes(&words[..]); unsafe { assert_eq!(from_bytes::(&bytes[..5]), Ok(0x0100_C0C0)); assert_eq!(from_bytes::(&bytes[..6]), Ok(0x0100_C0C0)); assert_eq!(from_bytes::(&bytes[..7]), Ok(0x0100_C0C0)); assert_eq!(from_bytes::(&bytes[..8]), Ok(0x0100_C0C0)); assert_eq!(from_bytes::(&bytes[..9]), Ok(0x0100_C0C0)); } } safe-transmute-0.11.2/tests/base/from_bytes_pedantic.rs000064400000000000000000000023170000000000000212650ustar 00000000000000use safe_transmute::{ErrorReason, GuardError, Error, transmute_to_bytes}; use safe_transmute::base::from_bytes_pedantic; #[test] fn too_short() { unsafe { assert_eq!(from_bytes_pedantic::(&[]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 0, reason: ErrorReason::InexactByteCount, }))); assert_eq!(from_bytes_pedantic::(&[0x00]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 1, reason: ErrorReason::InexactByteCount, }))); } } #[test] fn just_enough() { let word = [0x0100_0020]; let bytes = transmute_to_bytes(&word); unsafe { assert_eq!(from_bytes_pedantic::(bytes), Ok(0x0100_0020)); } } #[test] fn too_much() { unsafe { assert_eq!(from_bytes_pedantic::(&[0x00, 0x00, 0x00, 0x01, 0x00]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 5, reason: ErrorReason::InexactByteCount, }))); } } safe-transmute-0.11.2/tests/base/mod.rs000064400000000000000000000007010000000000000160170ustar 00000000000000mod transmute_many_permissive; mod transmute_many_pedantic; mod from_bytes_pedantic; mod transmute_many; mod from_bytes; #[cfg(feature = "alloc")] use safe_transmute::base; #[cfg(feature = "alloc")] #[test] fn transmute_vec() { unsafe { assert_eq!(base::transmute_vec::(vec![0x0100u16]), vec![0x0100i16]); assert_eq!(base::transmute_vec::(vec![0x0100u16, 0x0200u16]), vec![0x0100i16, 0x0200i16]); } } safe-transmute-0.11.2/tests/base/transmute_many.rs000064400000000000000000000061410000000000000203120ustar 00000000000000use safe_transmute::{SingleManyGuard, ErrorReason, GuardError, Error, transmute_to_bytes, transmute_to_bytes_mut}; use safe_transmute::base::{transmute_many, transmute_many_mut}; #[test] fn too_short() { unsafe { assert_eq!(transmute_many::(&[]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(transmute_many::(&[0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } } #[test] fn just_enough() { let words: &[u16] = &[0x0100, 0x0200, 0x0300]; let bytes = transmute_to_bytes(words); unsafe { assert_eq!(transmute_many::(&bytes[..2]), Ok(&words[..1])); assert_eq!(transmute_many::(bytes), Ok(words)); } } #[test] fn too_much() { let words: &[u16] = &[0x0100, 0x0200, 0x0300, 0]; let bytes = transmute_to_bytes(words); unsafe { assert_eq!(transmute_many::(&bytes[..3]), Ok(&words[..1])); assert_eq!(transmute_many::(&bytes[..5]), Ok(&words[..2])); assert_eq!(transmute_many::(&bytes[..7]), Ok(&words[..3])); } } #[test] fn too_short_mut() { unsafe { assert_eq!(transmute_many_mut::(&mut []), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(transmute_many_mut::(&mut [0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } } #[test] fn just_enough_mut() { let words: &mut [u16] = &mut [0x0100, 0x0200, 0x0300]; let bytes = transmute_to_bytes_mut(words); // make an independent version of `words` for eq testing let words: &mut [u16] = &mut [0x0100, 0x0200, 0x0300]; unsafe { assert_eq!(transmute_many_mut::(&mut bytes[..2]), Ok(&mut words[..1])); assert_eq!(transmute_many_mut::(bytes), Ok(words)); } } #[test] fn too_much_mut() { let words: &mut [u16] = &mut [0x0100, 0x0200, 0x0300, 0]; let bytes = transmute_to_bytes_mut(words); // make an independent version of `words` for eq testing let words: &mut [u16] = &mut [0x0100, 0x0200, 0x0300]; unsafe { assert_eq!(transmute_many_mut::(&mut bytes[..3]), Ok(&mut words[..1])); assert_eq!(transmute_many_mut::(&mut bytes[..5]), Ok(&mut words[..2])); assert_eq!(transmute_many_mut::(&mut bytes[..7]), Ok(&mut words[..3])); } } safe-transmute-0.11.2/tests/base/transmute_many_pedantic.rs000064400000000000000000000032520000000000000221610ustar 00000000000000use safe_transmute::{PedanticGuard, ErrorReason, GuardError, Error, transmute_to_bytes}; use safe_transmute::base::transmute_many; #[test] fn too_short() { unsafe { assert_eq!(transmute_many::(&[]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(transmute_many::(&[0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } } #[test] fn just_enough() { let words: &[u16] = &[0x0100, 0x0200, 0x0300]; let bytes = transmute_to_bytes(words); unsafe { assert_eq!(transmute_many::(&bytes[..2]), Ok(&words[..1])); assert_eq!(transmute_many::(bytes), Ok(words)); } } #[test] fn too_much() { unsafe { assert_eq!(transmute_many::(&[0x00, 0x01, 0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 3, reason: ErrorReason::InexactByteCount, }))); assert_eq!(transmute_many::(&[0x00, 0x01, 0x00, 0x02, 0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 5, reason: ErrorReason::InexactByteCount, }))); } } safe-transmute-0.11.2/tests/base/transmute_many_permissive.rs000064400000000000000000000023250000000000000225600ustar 00000000000000use safe_transmute::{PermissiveGuard, transmute_to_bytes}; use safe_transmute::base::transmute_many; #[test] fn too_short() { let words: &[u16] = &[0x0100, 0x0200, 0x0300]; let bytes = transmute_to_bytes(words); unsafe { assert_eq!(transmute_many::(&bytes[..0]), Ok(&[][..])); assert_eq!(transmute_many::(&bytes[..1]), Ok(&[][..])); } } #[test] fn just_enough() { let words: &[u16] = &[0x0100, 0x0200, 0x0300]; let bytes = transmute_to_bytes(words); unsafe { assert_eq!(transmute_many::(&bytes[..2]), Ok(&words[..1])); assert_eq!(transmute_many::(bytes), Ok(words)); } } #[test] fn too_much() { let words: &[u16] = &[0x0100, 0x0200, 0x0300, 0]; let bytes = transmute_to_bytes(words); unsafe { assert_eq!(transmute_many::(&bytes[..3]), Ok(&words[..1])); assert_eq!(transmute_many::(&bytes[..5]), Ok(&words[..2])); assert_eq!(transmute_many::(&bytes[..7]), Ok(&words[..3])); } } safe-transmute-0.11.2/tests/bool/mod.rs000064400000000000000000000001040000000000000160350ustar 00000000000000mod vec_permissive; mod vec_pedantic; mod permissive; mod pedantic; safe-transmute-0.11.2/tests/bool/pedantic.rs000064400000000000000000000016020000000000000170510ustar 00000000000000use safe_transmute::{ErrorReason, GuardError, Error, transmute_bool_pedantic}; #[test] fn too_short() { assert_eq!(transmute_bool_pedantic([].as_ref()), Err(Error::Guard(GuardError { required: 1, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { assert_eq!(transmute_bool_pedantic([0x00, 0x01].as_ref()), Ok(&[false, true][..])); assert_eq!(transmute_bool_pedantic([0x01, 0x01, 0x00, 0x01].as_ref()), Ok(&[true, true, false, true][..])); } #[test] fn invalid_bytes() { assert_eq!(transmute_bool_pedantic([0x00, 0x01, 0x02].as_ref()), Err(Error::InvalidValue)); assert_eq!(transmute_bool_pedantic([0x05, 0x01, 0x00].as_ref()), Err(Error::InvalidValue)); assert_eq!(transmute_bool_pedantic([0xFF].as_ref()), Err(Error::InvalidValue)); } safe-transmute-0.11.2/tests/bool/permissive.rs000064400000000000000000000013320000000000000174500ustar 00000000000000use safe_transmute::{Error, transmute_bool_permissive}; #[test] fn too_short() { assert_eq!(transmute_bool_permissive([].as_ref()), Ok([].as_ref())); } #[test] fn just_enough() { assert_eq!(transmute_bool_permissive([0x00, 0x01].as_ref()), Ok([false, true].as_ref())); assert_eq!(transmute_bool_permissive([0x00, 0x01, 0x00, 0x01].as_ref()), Ok([false, true, false, true].as_ref())); } #[test] fn invalid_bytes() { assert_eq!(transmute_bool_permissive([0x00, 0x01, 0x02].as_ref()), Err(Error::InvalidValue)); assert_eq!(transmute_bool_permissive([0x05, 0x01, 0x00].as_ref()), Err(Error::InvalidValue)); assert_eq!(transmute_bool_permissive([0xFF].as_ref()), Err(Error::InvalidValue)); } safe-transmute-0.11.2/tests/bool/vec_pedantic.rs000064400000000000000000000016340000000000000177130ustar 00000000000000#![cfg(feature = "alloc")] use safe_transmute::{ErrorReason, GuardError, Error, transmute_bool_vec_pedantic}; #[test] fn too_short() { assert_eq!(transmute_bool_vec_pedantic(vec![]), Err(Error::Guard(GuardError { required: 1, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { assert_eq!(transmute_bool_vec_pedantic(vec![0x00, 0x01]), Ok(vec![false, true])); assert_eq!(transmute_bool_vec_pedantic(vec![0x00, 0x01, 0x00, 0x01]), Ok(vec![false, true, false, true])); } #[test] fn invalid_bytes() { assert_eq!(transmute_bool_vec_pedantic(vec![0x00, 0x01, 0x02]), Err(Error::InvalidValue)); assert_eq!(transmute_bool_vec_pedantic(vec![0x05, 0x01, 0x00]), Err(Error::InvalidValue)); assert_eq!(transmute_bool_vec_pedantic(vec![0xFF]), Err(Error::InvalidValue)); } safe-transmute-0.11.2/tests/bool/vec_permissive.rs000064400000000000000000000013460000000000000203120ustar 00000000000000#![cfg(feature = "alloc")] use safe_transmute::{Error, transmute_bool_vec_permissive}; #[test] fn too_short() { assert_eq!(transmute_bool_vec_permissive(vec![]), Ok(vec![])); } #[test] fn just_enough() { assert_eq!(transmute_bool_vec_permissive(vec![0x00, 0x01]), Ok(vec![false, true])); assert_eq!(transmute_bool_vec_permissive(vec![0x00, 0x01, 0x00, 0x01]), Ok(vec![false, true, false, true])); } #[test] fn invalid_bytes() { assert_eq!(transmute_bool_vec_permissive(vec![0x00, 0x01, 0x02]), Err(Error::InvalidValue)); assert_eq!(transmute_bool_vec_permissive(vec![0x05, 0x01, 0x00]), Err(Error::InvalidValue)); assert_eq!(transmute_bool_vec_permissive(vec![0xFF]), Err(Error::InvalidValue)); } safe-transmute-0.11.2/tests/error/mod.rs000064400000000000000000000000170000000000000162360ustar 00000000000000mod unaligned; safe-transmute-0.11.2/tests/error/unaligned.rs000064400000000000000000000067410000000000000174370ustar 00000000000000use safe_transmute::{transmute_many_permissive, transmute_to_bytes}; use safe_transmute::error::{UnalignedError, Error}; #[cfg(feature = "alloc")] use core::mem::align_of; #[cfg(feature = "alloc")] use alloc::vec::Vec; #[test] fn unaligned_slicing_integers() { let words = [0x01FF, 0x02EE, 0x03DD, 0x04CC, 0x05BB, 0x06AA]; let bytes = transmute_to_bytes(&words); assert_eq!(transmute_many_permissive::(bytes), Ok(words.as_ref())); assert_eq!(transmute_many_permissive::(&bytes[1..]), Err(Error::Unaligned(UnalignedError::new(1, &bytes[1..])))); assert_eq!(transmute_many_permissive::(&bytes[2..]), Ok(&words[1..])); assert_eq!(transmute_many_permissive::(&bytes[3..]), Err(Error::Unaligned(UnalignedError::new(1, &bytes[3..])))); let words = [0x02EE_01FF, 0x04CC_03DD, 0x06AA_05BB]; let bytes = transmute_to_bytes(&words); assert_eq!(transmute_many_permissive::(bytes), Ok(words.as_ref())); assert_eq!(transmute_many_permissive::(&bytes[1..]), Err(Error::Unaligned(UnalignedError::new(3, &bytes[1..])))); assert_eq!(transmute_many_permissive::(&bytes[2..]), Err(Error::Unaligned(UnalignedError::new(2, &bytes[2..])))); assert_eq!(transmute_many_permissive::(&bytes[3..]), Err(Error::Unaligned(UnalignedError::new(1, &bytes[3..])))); assert_eq!(transmute_many_permissive::(&bytes[4..]), Ok(&words[1..])); assert_eq!(transmute_many_permissive::(&bytes[5..]), Err(Error::Unaligned(UnalignedError::new(3, &bytes[5..])))); let words = [0x02EE_01FF_04CC_03DD, 0x06EE_05FF_08CC_07DD]; let bytes = transmute_to_bytes(&words); // transmute aligned content assert_eq!(transmute_many_permissive::(bytes), Ok(&words[..])); assert_eq!(transmute_many_permissive::(&bytes[8..]), Ok(&words[1..])); // without try_copy! for i in 1..4 { // transmute unaligned content by copying let outcome = transmute_many_permissive::(&bytes[i..]); assert_eq!(outcome, Err(Error::Unaligned(UnalignedError::new(8 - i, &bytes[i..])))); #[cfg(feature = "alloc")] { let copied_data: Vec<_> = match outcome { Ok(_) => unreachable!(), Err(Error::Unaligned(e)) => e.copy(), Err(e) => panic!("Expected `UnalignedError`, got {}", e), }; assert_eq!(copied_data.len(), 1); let expected_word: u64 = (0..8) .map(|k| u64::from(bytes[i + k]) << (8 * k)) .sum(); assert_eq!(u64::to_le(copied_data[0]), expected_word); } } // with try_copy! #[cfg(feature = "alloc")] unaligned_slicing_integers_with_try_copy(bytes).unwrap(); } #[cfg(feature = "alloc")] fn unaligned_slicing_integers_with_try_copy<'a>(bytes: &'a [u8]) -> Result<(), Error<'a, u8, u64>> { if align_of::() != 8 { // i686 return Ok(()); } for i in 4..8 { // transmute unaligned content by copying let outcome = transmute_many_permissive::(&bytes[i..]); assert_eq!(outcome, Err(Error::Unaligned(UnalignedError::new(8 - i, &bytes[i..])))); let copied_data = try_copy!(outcome); assert_eq!(copied_data.len(), 1); let expected_word: u64 = (0..8) .map(|k| u64::from(bytes[i + k]) << (8 * k)) .sum(); assert_eq!(u64::to_le(copied_data[0]), expected_word); } Ok(()) } safe-transmute-0.11.2/tests/full/many.rs000064400000000000000000000025110000000000000162350ustar 00000000000000use safe_transmute::{SingleManyGuard, ErrorReason, GuardError, Error, transmute_to_bytes, transmute_many}; #[test] fn too_short() { assert_eq!(transmute_many::(transmute_to_bytes::(&[])), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(transmute_many::(&transmute_to_bytes::(&[0])[..1]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { let words: &[u16] = &[0x0100, 0x0200]; let bytes = transmute_to_bytes(words); assert_eq!(transmute_many::(&bytes[..2]), Ok(&words[..1])); assert_eq!(transmute_many::(bytes), Ok(words)); } #[test] fn too_much() { let words: &[u16] = &[0x0100, 0x0200, 0x0300, 0]; let bytes = transmute_to_bytes(words); assert_eq!(transmute_many::(&bytes[..3]), Ok(&words[..1])); assert_eq!(transmute_many::(&bytes[..5]), Ok(&words[..2])); assert_eq!(transmute_many::(&bytes[..7]), Ok(&words[..3])); } safe-transmute-0.11.2/tests/full/many_pedantic.rs000064400000000000000000000030210000000000000201010ustar 00000000000000use safe_transmute::{ErrorReason, GuardError, Error, transmute_many_pedantic, transmute_to_bytes}; #[test] fn too_short() { assert_eq!(transmute_many_pedantic::(transmute_to_bytes::(&[])), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(transmute_many_pedantic::(&transmute_to_bytes::(&[0])[..1]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { let words: &[u16] = &[0x1000, 0x2000]; let bytes = transmute_to_bytes(words); assert_eq!(transmute_many_pedantic::(&bytes[..2]), Ok(&words[..1])); assert_eq!(transmute_many_pedantic::(bytes), Ok(words)); } #[test] fn too_much() { let words: &[u16] = &[0x1000, 0x2000, 0x300]; let bytes = transmute_to_bytes(words); assert_eq!(transmute_many_pedantic::(&bytes[..3]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 3, reason: ErrorReason::InexactByteCount, }))); assert_eq!(transmute_many_pedantic::(&bytes[..5]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 5, reason: ErrorReason::InexactByteCount, }))); } safe-transmute-0.11.2/tests/full/many_permissive.rs000064400000000000000000000016700000000000000205100ustar 00000000000000use safe_transmute::{transmute_many_permissive, transmute_to_bytes}; #[test] fn too_short() { assert_eq!(transmute_many_permissive::(transmute_to_bytes::(&[])), Ok([].as_ref())); assert_eq!(transmute_many_permissive::(&transmute_to_bytes::(&[0])[..1]), Ok([].as_ref())); } #[test] fn just_enough() { let words: &[u16] = &[0x0100u16, 0x0200u16]; let bytes = transmute_to_bytes(words); assert_eq!(transmute_many_permissive::(&bytes[..2]), Ok(&words[..1])); assert_eq!(transmute_many_permissive::(bytes), Ok(words)); } #[test] fn too_much() { let words: &[u16] = &[0x0100, 0x0200, 0x0300, 0]; let bytes = transmute_to_bytes(words); assert_eq!(transmute_many_permissive::(&bytes[..3]), Ok(&words[..1])); assert_eq!(transmute_many_permissive::(&bytes[..5]), Ok(&words[..2])); assert_eq!(transmute_many_permissive::(&bytes[..7]), Ok(&words[..3])); } safe-transmute-0.11.2/tests/full/mod.rs000064400000000000000000000001260000000000000160500ustar 00000000000000mod many_permissive; mod many_pedantic; mod one_pedantic; mod many; mod one; mod vec; safe-transmute-0.11.2/tests/full/one.rs000064400000000000000000000023360000000000000160570ustar 00000000000000use safe_transmute::{ErrorReason, GuardError, Error, transmute_to_bytes, transmute_one}; #[test] fn too_short() { assert_eq!(transmute_one::(transmute_to_bytes::(&[])), Err(Error::Guard(GuardError { required: 32 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(transmute_one::(&transmute_to_bytes::(&[0])[..1]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { let words: &[u32] = &[0x1234_5678]; assert_eq!(transmute_one::(transmute_to_bytes(words)), Ok(words[0])); } #[test] fn too_much() { let words: &[u32] = &[0x0100_0000, 0, 0]; let bytes = transmute_to_bytes(words); assert_eq!(transmute_one::(&bytes[..5]), Ok(0x0100_0000)); assert_eq!(transmute_one::(&bytes[..6]), Ok(0x0100_0000)); assert_eq!(transmute_one::(&bytes[..7]), Ok(0x0100_0000)); assert_eq!(transmute_one::(&bytes[..8]), Ok(0x0100_0000)); assert_eq!(transmute_one::(&bytes[..9]), Ok(0x0100_0000)); } safe-transmute-0.11.2/tests/full/one_pedantic.rs000064400000000000000000000021650000000000000177260ustar 00000000000000use safe_transmute::{ErrorReason, GuardError, Error, transmute_one_pedantic, transmute_to_bytes}; #[test] fn too_short() { assert_eq!(transmute_one_pedantic::(transmute_to_bytes::(&[])), Err(Error::Guard(GuardError { required: 32 / 8, actual: 0, reason: ErrorReason::InexactByteCount, }))); assert_eq!(transmute_one_pedantic::(&transmute_to_bytes::(&[0])[..1]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 1, reason: ErrorReason::InexactByteCount, }))); } #[test] fn just_enough() { assert_eq!(transmute_one_pedantic::(&transmute_to_bytes::(&[0x0100_0000])), Ok(0x0100_0000)); } #[test] fn too_much() { assert_eq!(transmute_one_pedantic::(&transmute_to_bytes::(&[0x0100_0000, 0])[..5]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 5, reason: ErrorReason::InexactByteCount, }))); } safe-transmute-0.11.2/tests/full/vec.rs000064400000000000000000000020120000000000000160420ustar 00000000000000#![cfg(feature = "alloc")] use safe_transmute::error::IncompatibleVecTargetError; use safe_transmute::{transmute_vec, Error}; #[test] fn bad_size() { assert_eq!(transmute_vec::(vec![]), Err(Error::IncompatibleVecTarget(IncompatibleVecTargetError::new(vec![])))); assert_eq!(transmute_vec::(vec![1, 2, 3]), Err(Error::IncompatibleVecTarget(IncompatibleVecTargetError::new(vec![1, 2, 3])))); } #[test] fn just_enough() { assert_eq!(transmute_vec::(vec![0x00, 0x01]), Ok(vec![0x00i8, 0x01i8])); assert_eq!(transmute_vec::(vec![0x0100u16, 0x0200u16]), Ok(vec![0x0100i16, 0x0200i16])); } #[test] fn bad_alignment() { assert_eq!(transmute_vec::(vec![8, 8, 8]), Err(Error::IncompatibleVecTarget(IncompatibleVecTargetError::new(vec![8, 8, 8])))); assert_eq!(transmute_vec::(vec![3, 2, 1]), Err(Error::IncompatibleVecTarget(IncompatibleVecTargetError::new(vec![3, 2, 1])))); } safe-transmute-0.11.2/tests/guard/mod.rs000064400000000000000000000000200000000000000162010ustar 00000000000000mod zero_sized; safe-transmute-0.11.2/tests/guard/zero_sized.rs000064400000000000000000000074770000000000000176260ustar 00000000000000use safe_transmute::guard::{AllOrNothingGuard, SingleValueGuard, PermissiveGuard, SingleManyGuard, PedanticGuard, Guard}; use safe_transmute::error::{ErrorReason, GuardError}; #[test] fn single_value_guard() { assert_eq!(SingleValueGuard::check::<()>(&[]), Ok(())); assert_eq!(SingleValueGuard::check::<()>(&[0]), Err(GuardError { required: 0, actual: 1, reason: ErrorReason::InexactByteCount, })); assert_eq!(SingleValueGuard::check::<()>(&[0, 1]), Err(GuardError { required: 0, actual: 2, reason: ErrorReason::InexactByteCount, })); assert_eq!(SingleValueGuard::check::<()>(&[0, 1, 2]), Err(GuardError { required: 0, actual: 3, reason: ErrorReason::InexactByteCount, })); assert_eq!(SingleValueGuard::check::<()>(&[0, 1, 2, 3]), Err(GuardError { required: 0, actual: 4, reason: ErrorReason::InexactByteCount, })); } #[test] fn pedantic_guard() { assert_eq!(PedanticGuard::check::<()>(&[]), Ok(())); assert_eq!(PedanticGuard::check::<()>(&[0]), Err(GuardError { required: 0, actual: 1, reason: ErrorReason::InexactByteCount, })); assert_eq!(PedanticGuard::check::<()>(&[0, 1]), Err(GuardError { required: 0, actual: 2, reason: ErrorReason::InexactByteCount, })); assert_eq!(PedanticGuard::check::<()>(&[0, 1, 2]), Err(GuardError { required: 0, actual: 3, reason: ErrorReason::InexactByteCount, })); assert_eq!(PedanticGuard::check::<()>(&[0, 1, 2, 3]), Err(GuardError { required: 0, actual: 4, reason: ErrorReason::InexactByteCount, })); } #[test] fn all_or_nothing_guard() { assert_eq!(AllOrNothingGuard::check::<()>(&[]), Ok(())); assert_eq!(AllOrNothingGuard::check::<()>(&[0]), Err(GuardError { required: 0, actual: 1, reason: ErrorReason::InexactByteCount, })); assert_eq!(AllOrNothingGuard::check::<()>(&[0, 1]), Err(GuardError { required: 0, actual: 2, reason: ErrorReason::InexactByteCount, })); assert_eq!(AllOrNothingGuard::check::<()>(&[0, 1, 2]), Err(GuardError { required: 0, actual: 3, reason: ErrorReason::InexactByteCount, })); assert_eq!(AllOrNothingGuard::check::<()>(&[0, 1, 2, 3]), Err(GuardError { required: 0, actual: 4, reason: ErrorReason::InexactByteCount, })); } #[test] fn single_many_guard() { assert_eq!(SingleManyGuard::check::<()>(&[]), Ok(())); assert_eq!(SingleManyGuard::check::<()>(&[0]), Ok(())); assert_eq!(SingleManyGuard::check::<()>(&[0, 1]), Ok(())); assert_eq!(SingleManyGuard::check::<()>(&[0, 1, 2]), Ok(())); assert_eq!(SingleManyGuard::check::<()>(&[0, 1, 2, 3]), Ok(())); } #[test] fn permissive_guard() { assert_eq!(PermissiveGuard::check::<()>(&[]), Ok(())); assert_eq!(PermissiveGuard::check::<()>(&[0]), Ok(())); assert_eq!(PermissiveGuard::check::<()>(&[0, 1]), Ok(())); assert_eq!(PermissiveGuard::check::<()>(&[0, 1, 2]), Ok(())); assert_eq!(PermissiveGuard::check::<()>(&[0, 1, 2, 3]), Ok(())); } safe-transmute-0.11.2/tests/lib.rs000064400000000000000000000005530000000000000151010ustar 00000000000000#![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "std")] extern crate core; #[macro_use] #[cfg(feature = "alloc")] extern crate alloc; #[cfg_attr(feature = "alloc", macro_use)] extern crate safe_transmute; mod guard; mod error; mod base; mod bool; mod full; mod util; include!("test_util/le_to_native.rs"); include!("test_util/aligned_vec.rs"); safe-transmute-0.11.2/tests/test_util/aligned_vec.rs000064400000000000000000000037700000000000000206130ustar 00000000000000#[cfg(feature = "alloc")] use core::mem::{align_of, size_of, forget}; #[cfg(feature = "alloc")] use alloc::vec::Vec; /// Create a new vector that contains the given bytes and is sure to have a /// memory alignment compatible with `T` at creation time. /// /// # Examples /// /// ``` /// let data: &[u8] = &[0xFF, 0xFF, 0x03, 0x00]; /// let vev = aligned_vec::(data); /// // the vector's data is guaranteed to be aligned for access as a u32 /// assert_eq!((vec.as_ptr() as usize) % align_of::(), 0); /// ``` /// /// # Safety /// /// The resulting vector must then be deallocated with /// `dealloc_aligned_vec()`, and the exact same `T` parameter. /// /// Modifying or not moving into `dealloc_aligned_vec()` *will* yield UB. #[cfg(feature = "alloc")] unsafe fn aligned_vec(bytes: &[u8]) -> Vec { let vec_len_offset = bytes.len() % size_of::(); let vec_len = bytes.len() / size_of::(); let capacity = if vec_len_offset > 0 { vec_len + 1 } else { vec_len }; // The following code allocates a `Vec` and turns it into // a `Vec`. Assuming that this vector will not be dropped // in this state, reading bytes from it is safe. #[allow(unused_unsafe)] unsafe { let mut v: Vec = Vec::with_capacity(capacity); let ptr = v.as_mut_ptr() as *mut u8; bytes.as_ptr().copy_to_nonoverlapping(ptr, bytes.len()); forget(v); let vec = Vec::from_raw_parts(ptr, bytes.len(), capacity * size_of::()); assert_eq!((vec.as_ptr() as usize) % align_of::(), 0); assert_eq!(vec.len(), bytes.len()); assert!(vec.capacity() >= vec.len()); vec } } /// Deallocate a vector created by `aligned_vec`. /// /// # Safety /// /// Shall not be called on a vector not created by `aligned_vec()`. /// The `T` parameter must also match the one used to /// create the vector. #[cfg(feature = "alloc")] unsafe fn dealloc_aligned_vec(vec: Vec) { safe_transmute::base::transmute_vec::<_, T>(vec); } safe-transmute-0.11.2/tests/test_util/le_to_native.rs000064400000000000000000000051330000000000000210160ustar 00000000000000extern crate core as le_to_native_core; /// Test aids: rustc has started placing static byte arrays at odd offsets #[repr(align(64))] #[allow(dead_code)] struct Le2NAl2([u8; 2]); #[repr(align(64))] #[allow(dead_code)] struct Le2NAl4([u8; 4]); #[repr(align(64))] #[allow(dead_code)] struct Le2NAl8([u8; 8]); /// Verify: http://play.integer32.com/?gist=4cd795d6f45898c876a754cd3f3c2aaa&version=stable trait LeToNative { fn le_to_native(self) -> Self; } impl<'a> LeToNative for &'a mut [u8] { #[cfg(target_endian = "little")] fn le_to_native(self) -> Self { self } #[cfg(target_endian = "big")] fn le_to_native(self) -> Self { use le_to_native_core::mem::size_of; for elem in self.chunks_mut(size_of::()) { elem.reverse(); } self } } #[cfg(feature = "alloc")] impl LeToNative for Vec { #[cfg(target_endian = "little")] fn le_to_native(self) -> Self { self } #[cfg(target_endian = "big")] fn le_to_native(mut self) -> Self { (&mut self[..]).le_to_native::(); self } } macro_rules! impl_le_to_native_array_u8 { ($n:expr) => { impl LeToNative for [u8; $n] { #[cfg(target_endian = "little")] fn le_to_native(self) -> Self { self } #[cfg(target_endian = "big")] fn le_to_native(mut self) -> Self { (&mut self[..]).le_to_native::(); self } } } } impl_le_to_native_array_u8!(1); impl_le_to_native_array_u8!(2); impl_le_to_native_array_u8!(3); impl_le_to_native_array_u8!(4); impl_le_to_native_array_u8!(5); impl_le_to_native_array_u8!(6); impl_le_to_native_array_u8!(7); impl_le_to_native_array_u8!(8); impl_le_to_native_array_u8!(9); impl_le_to_native_array_u8!(10); impl_le_to_native_array_u8!(11); impl_le_to_native_array_u8!(12); impl_le_to_native_array_u8!(13); impl_le_to_native_array_u8!(14); impl_le_to_native_array_u8!(15); impl_le_to_native_array_u8!(16); impl_le_to_native_array_u8!(17); impl_le_to_native_array_u8!(18); impl_le_to_native_array_u8!(19); impl_le_to_native_array_u8!(20); impl_le_to_native_array_u8!(21); impl_le_to_native_array_u8!(22); impl_le_to_native_array_u8!(23); impl_le_to_native_array_u8!(24); impl_le_to_native_array_u8!(25); impl_le_to_native_array_u8!(26); impl_le_to_native_array_u8!(27); impl_le_to_native_array_u8!(28); impl_le_to_native_array_u8!(29); impl_le_to_native_array_u8!(30); impl_le_to_native_array_u8!(31); impl_le_to_native_array_u8!(32); safe-transmute-0.11.2/tests/util/mod.rs000064400000000000000000000045450000000000000160740ustar 00000000000000#[cfg(feature = "alloc")] use self::super::{dealloc_aligned_vec, aligned_vec}; use safe_transmute::align::check_alignment; use safe_transmute::util; use core::mem::align_of; use core::{f32, f64}; #[cfg(feature = "alloc")] use alloc::vec::Vec; #[test] fn designalise_f32() { assert_eq!(util::designalise_f32(12.34125121), 12.34125121); assert!(util::designalise_f32(f32::NAN).is_nan()); // I'm not quite sure how to make an sNaN to test this so... } #[test] fn designalise_f64() { assert_eq!(util::designalise_f64(12.34125121), 12.34125121); assert!(util::designalise_f64(f64::NAN).is_nan()); // I'm not quite sure how to make an sNaN to test this, either } #[test] fn smoke_check_alignment_from_4() { let x: [i32; 5] = [0x5555_5555; 5]; assert_eq!(align_of::<[i32; 5]>(), 4); assert_eq!(check_alignment::<_, u8>(&x[..]), Ok(())); assert_eq!(check_alignment::<_, i8>(&x[..]), Ok(())); assert_eq!(check_alignment::<_, u16>(&x[..]), Ok(())); assert_eq!(check_alignment::<_, i16>(&x[..]), Ok(())); assert_eq!(check_alignment::<_, u32>(&x[..]), Ok(())); } #[test] fn smoke_check_alignment_from_8() { let x: [i64; 5] = [0x5555_5555_5555_5555; 5]; // assert_eq!(align_of::<[i64; 5]>(), 8); // False on i686, holds on amd64. assert_eq!(check_alignment::<_, u8>(&x[..]), Ok(())); assert_eq!(check_alignment::<_, i8>(&x[..]), Ok(())); assert_eq!(check_alignment::<_, u16>(&x[..]), Ok(())); assert_eq!(check_alignment::<_, i16>(&x[..]), Ok(())); assert_eq!(check_alignment::<_, u32>(&x[..]), Ok(())); assert_eq!(check_alignment::<_, i32>(&x[..]), Ok(())); assert_eq!(check_alignment::<_, u64>(&x[..]), Ok(())); } #[cfg(feature = "alloc")] #[test] fn test_aligned_vec() { check_aligned_vec_with::(&[0xFF, 0xFF, 0x03, 0x00]); check_aligned_vec_with::(&[]); check_aligned_vec_with::(&[]); check_aligned_vec_with::(&[]); check_aligned_vec_with::(&[0]); check_aligned_vec_with::(&[1, 2]); check_aligned_vec_with::(&[1, 2, 3]); check_aligned_vec_with::(&[0xAA; 20]); } #[cfg(feature = "alloc")] fn check_aligned_vec_with(bytes: &[u8]) { unsafe { let vec: Vec = aligned_vec::(bytes); assert_eq!((vec.as_ptr() as usize) % align_of::(), 0); assert_eq!(&*vec, bytes); dealloc_aligned_vec::(vec); } }