safe-transmute-0.10.1/.gitignore000064400000000000000000000002171300766371400147140ustar0000000000000000* !.gitignore !.travis.yml !gh_rsa.enc !appveyor.yml !LICENSE !Cargo.toml !rustfmt.toml !*.sublime-project !*.md !src !src/** !tests !tests/** safe-transmute-0.10.1/.travis.yml000064400000000000000000000054571337224757600150610ustar0000000000000000sudo: 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 CARGO_DEFAULT_FEATURES=--no-default-features 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 script: - cargo build --verbose - if [ ! -z "$CROSS_TARGET" ]; then cross test --verbose --target $CROSS_TARGET $CARGO_DEFAULT_FEATURES --features test-unaligned; else cargo test --verbose $CARGO_DEFAULT_FEATURES --features test-unaligned; fi - if [ "$CLIPPY" ]; then cargo install -f clippy; 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.10.1/appveyor.yml000064400000000000000000000014231337727316500153230ustar0000000000000000version: 0.10.1-{build} skip_tags: false platform: x64 configuration: Release clone_folder: C:\cargo-update install: - set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%;C:\Users\appveyor\.cargo\bin - bash -lc "pacman --needed --noconfirm -Sy pacman-mirrors" - 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 test: off test_script: - cargo test --verbose --release artifacts: - path: cargo-install-update-v0.10.1.exe notifications: - provider: Email to: - nabijaczleweli@gmail.com on_build_status_changed: true safe-transmute-0.10.1/Cargo.toml.orig000064400000000000000000000012151337727316700156230ustar0000000000000000[package] name = "safe-transmute" description = "A safeguarded transmute() for Rust" documentation = "https://cdn.rawgit.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.10.1" authors = ["nabijaczleweli ", "Eduardo Pinho "] exclude = ["*.enc"] [features] default = ["std"] "std" = [] "test-unaligned" = [] safe-transmute-0.10.1/Cargo.toml0000644000000021400000000000000121030ustar00# 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.10.1" authors = ["nabijaczleweli ", "Eduardo Pinho "] exclude = ["*.enc"] description = "A safeguarded transmute() for Rust" documentation = "https://cdn.rawgit.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] default = ["std"] std = [] test-unaligned = [] safe-transmute-0.10.1/LICENSE000064400000000000000000000020711300766371400137310ustar0000000000000000The 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.10.1/README.md000064400000000000000000000013111326744021400141730ustar0000000000000000# 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://cdn.rawgit.com/nabijaczleweli/safe-transmute-rs/doc/safe_transmute/index.html) safe-transmute-0.10.1/rustfmt.toml000064400000000000000000000003241300766371500153250ustar0000000000000000max_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.10.1/safe-transmute-rs.sublime-project000064400000000000000000000014641301022043500213160ustar0000000000000000{ "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.tmLanguage" }, { "working_dir": "$project_path", "shell_cmd": "cargo doc --color always", "name": "Document safe-transmute-rs", "target": "ansi_color_build", "syntax": "Packages/ANSIescape/ANSI.tmLanguage" } ], "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.10.1/src/bool.rs000064400000000000000000000106331337560243500150200ustar0000000000000000//! 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. use self::super::{Error, guarded_transmute_many_permissive, guarded_transmute_many_pedantic}; #[cfg(feature = "std")] use self::super::{guarded_transmute_vec_permissive, guarded_transmute_vec_pedantic}; use core::mem::{size_of, transmute}; /// Makes sure that the bytes represent a sequence of valid boolean values. /// /// # Panics /// /// This shouldn't happen on all currently supported platforms, but this /// function panics if the size of `bool` isn't 1. #[inline] pub fn bytes_are_bool(v: &[u8]) -> bool { // TODO make this a static assert once available assert_eq!(size_of::(), 1, "unsupported platform due to invalid bool size {}, please report over at https://github.com/nabijaczleweli/safe-transmute-rs/issues/new", size_of::()); v.iter().cloned().all(byte_is_bool) } #[inline] fn byte_is_bool(b: u8) -> bool { unsafe { b == transmute::<_, u8>(false) || b == transmute::<_, u8>(true) } } /// 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, guarded_transmute_bool_permissive}; /// # fn run() -> Result<(), Error> { /// assert_eq!(guarded_transmute_bool_permissive(&[0x00, 0x01, 0x00, 0x01])?, /// &[false, true, false, true]); /// assert_eq!(guarded_transmute_bool_permissive(&[])?, &[]); /// # Ok(()) /// # } /// # run().unwrap() /// ``` pub fn guarded_transmute_bool_permissive(bytes: &[u8]) -> Result<&[bool], Error> { check_bool(bytes)?; unsafe { Ok(guarded_transmute_many_permissive(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, guarded_transmute_bool_pedantic}; /// # fn run() -> Result<(), Error> { /// assert_eq!(guarded_transmute_bool_pedantic(&[0x01, 0x01, 0x01, 0x01])?, /// &[true, true, true, true]); /// assert!(guarded_transmute_bool_pedantic(&[]).is_err()); /// # Ok(()) /// # } /// # run().unwrap() /// ``` pub fn guarded_transmute_bool_pedantic(bytes: &[u8]) -> Result<&[bool], Error> { check_bool(bytes)?; unsafe { guarded_transmute_many_pedantic(bytes) } } /// Trasform a byte vector into a vector of bool. /// /// The vector's allocated byte buffer will be reused when possible, and /// have as many instances of a type as will fit, rounded down. /// /// # Examples /// /// ``` /// # use safe_transmute::{Error, guarded_transmute_bool_vec_permissive}; /// # fn run() -> Result<(), Error> { /// assert_eq!(guarded_transmute_bool_vec_permissive(vec![0x00, 0x01, 0x00, 0x01])?, /// vec![false, true, false, true]); /// assert_eq!(guarded_transmute_bool_vec_permissive(vec![0x01, 0x00, 0x00, 0x00, 0x01])?, /// vec![true, false, false, false, true]); /// assert_eq!(guarded_transmute_bool_vec_permissive(vec![]), Ok(vec![])); /// # Ok(()) /// # } /// # run().unwrap() /// ``` #[cfg(feature = "std")] pub fn guarded_transmute_bool_vec_permissive(bytes: Vec) -> Result, Error> { check_bool(&bytes)?; unsafe { Ok(guarded_transmute_vec_permissive(bytes)) } } /// Transform a byte vector into a vector of bool. /// /// The vector's allocated byte buffer will be reused when possible, and /// should not have extraneous data. /// /// # Examples /// /// ``` /// # use safe_transmute::{Error, guarded_transmute_bool_vec_pedantic}; /// # fn run() -> Result<(), Error> { /// assert_eq!(guarded_transmute_bool_vec_pedantic(vec![0x00, 0x01, 0x00, 0x01])?, /// vec![false, true, false, true]); /// /// assert!(guarded_transmute_bool_vec_pedantic(vec![]).is_err()); /// /// assert!(guarded_transmute_bool_vec_pedantic(vec![0x04, 0x00, 0xED]).is_err()); /// # Ok(()) /// # } /// # run().unwrap() /// ``` #[cfg(feature = "std")] pub fn guarded_transmute_bool_vec_pedantic(bytes: Vec) -> Result, Error> { check_bool(&bytes)?; unsafe { guarded_transmute_vec_pedantic(bytes) } } fn check_bool(bytes: &[u8]) -> Result<(), Error> { if bytes_are_bool(bytes) { Ok(()) } else { Err(Error::InvalidValue) } } safe-transmute-0.10.1/src/error.rs000064400000000000000000000071551337560243500152230ustar0000000000000000#[cfg(feature = "std")] use std::error::Error as StdError; use core::fmt; /// A transmutation error. This type describes possible errors originating /// from operations in this crate. /// /// # Examples /// /// ``` /// # use safe_transmute::{ErrorReason, Error, guarded_transmute_bool_pedantic}; /// # unsafe { /// assert_eq!(guarded_transmute_bool_pedantic(&[0x05]), /// Err(Error::InvalidValue)); /// # } /// ``` #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Error { /// The data does not respect the target type's boundaries. Guard(GuardError), /// 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. /// /// This is currently unused. Unaligned { offset: usize, }, /// The data contains an invalid value for the target type. InvalidValue, } #[cfg(feature = "std")] impl StdError for Error { fn description(&self) -> &str { match *self { Error::Guard(ref e) => e.description(), Error::Unaligned { .. } => "Unaligned data slice", Error::InvalidValue => "Invalid target value", } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::Guard(ref e) => e.fmt(f), Error::Unaligned { offset } => write!(f, "Unaligned data slice (off by {} bytes)", offset), Error::InvalidValue => f.write_str("Invalid target value"), } } } impl From for Error { fn from(o: GuardError) -> Error { Error::Guard(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, } 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", } } } #[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) } } safe-transmute-0.10.1/src/guard.rs000064400000000000000000000121001337560243500151560ustar0000000000000000//! The `guard` module exposes an API for memory boundary checking. //! //! # Examples: //! //! In order to check whether a value would fit in the given //! slice without extraneous space: //! //! ``` //! # use safe_transmute::Error; //! # use safe_transmute::guard::{SingleValueGuard, Guard}; //! # fn run() -> Result<(), Error> { //! 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; //! # use safe_transmute::guard::{PedanticGuard, Guard}; //! # fn run() -> Result<(), Error> { //! 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; //! # use safe_transmute::guard::{PermissiveGuard, Guard}; //! # fn run() -> Result<(), Error> { //! 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, //! })); //! ``` //! //! Regardless of the chosen strategy, guarded transmutation functions will //! always ensure that no out of bounds access is attempted, usually by //! restricting the output to spatially safe portions of the input. 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 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 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.10.1/src/lib.rs000064400000000000000000000273031337727273200146420ustar0000000000000000//! This crate contains checked implementations of `transmute()`. //! //! The base functions in this crate are not inherently safe, but just guarded against common simple mistakes //! (like trying to create an 8-byte type from 7 bytes). //! These functions are exactly as safe as the data passed to them - creating a null pointer, //! for example, is not unsafe in and of itself, but dereferencing it certainly *is*, //! but they don't do that (see [here](https://github.com/nabijaczleweli/safe-transmute-rs/issues/1) //! for extended discussion). //! //! Other functions in this crate, on the other hand, provide enough safety measures to ensure safety in //! all circumstances. This is the case for those found in the `pod` and `bool` modules. //! //! Take note, however, that alignment is *unaccounted for*: you may, in the course of using this crate, //! invoke unaligned access, which some CPUs *may* trap on; that did not, however, happen in any of our tests on //! MIPS64 (BE), x86_64 (LE), nor armv6l (LE). //! //! This crate can be used in a no-`std` environment by disabling the `std` feature through specifying //! `default-features = false` on import. //! //! # Examples //! //! View bytes as a series of `u16`s: //! //! ``` //! # use safe_transmute::guarded_transmute_many; //! # include!("../tests/test_util/le_to_native.rs"); //! # fn main() { //! # unsafe { //! assert_eq!(guarded_transmute_many::(&[0x00, 0x01, //! 0x12, 0x34, //! // Spare byte, unused //! # /* //! 0x00])?, //! # */ //! # 0x00].le_to_native::()).unwrap(), //! &[0x0100, 0x3412]); //! # } //! # } //! ``` //! //! View all bytes as a series of `u16`s: //! //! ``` //! # use safe_transmute::guarded_transmute_many_pedantic; //! # include!("../tests/test_util/le_to_native.rs"); //! # fn main() { //! # unsafe { //! assert_eq!(guarded_transmute_many_pedantic::(&[0x00, 0x01, //! # /* //! 0x12, 0x34])?, //! # */ //! # 0x12, 0x34].le_to_native::()).unwrap(), //! &[0x0100, 0x3412]); //! # } //! # } //! ``` //! //! View bytes as an `f64`: //! //! ``` //! # use safe_transmute::guarded_transmute; //! # include!("../tests/test_util/le_to_native.rs"); //! # fn main() { //! # unsafe { //! assert_eq!(guarded_transmute::(&[0x00, 0x00, 0x00, 0x00, //! # /* //! 0x00, 0x00, 0x00, 0x40])?, //! # */ //! # 0x00, 0x00, 0x00, 0x40].le_to_native::()).unwrap(), //! 2.0); //! # } //! # } //! ``` //! //! View a series of `u16`s as bytes: //! //! ``` //! # use safe_transmute::guarded_transmute_to_bytes_pod_many; //! # include!("../tests/test_util/le_to_native.rs"); //! # fn main() { //! # unsafe { //! assert_eq!(guarded_transmute_to_bytes_pod_many(&[0x0001u16, //! 0x1234u16]), //! # /* //! &[0x01, 0x00, 0x34, 0x12].le_to_native::()); //! # */ //! # &[0x01, 0x00, 0x34, 0x12].le_to_native::()); //! # } //! # } //! ``` #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "std")] extern crate core; mod pod; mod bool; mod error; mod to_bytes; use core::slice; use core::mem::size_of; #[cfg(feature = "std")] use core::mem::forget; use guard::{SingleValueGuard, PermissiveGuard, SingleManyGuard, PedanticGuard, Guard}; pub mod util; pub mod guard; pub use self::error::{ErrorReason, GuardError, Error}; pub use self::to_bytes::{guarded_transmute_to_bytes_pod_many, guarded_transmute_to_bytes_many, guarded_transmute_to_bytes_pod, guarded_transmute_to_bytes}; #[cfg(feature = "std")] pub use self::to_bytes::{guarded_transmute_to_bytes_vec, guarded_transmute_to_bytes_pod_vec}; pub use self::pod::{PodTransmutable, guarded_transmute_pod_many_permissive, guarded_transmute_pod_many_pedantic, guarded_transmute_pod_pedantic, guarded_transmute_pod_many, guarded_transmute_pod}; #[cfg(feature = "std")] pub use self::pod::{guarded_transmute_pod_vec_permissive, guarded_transmute_pod_vec_pedantic, guarded_transmute_pod_vec}; #[cfg(feature = "std")] pub use self::bool::{guarded_transmute_bool_vec_permissive, guarded_transmute_bool_vec_pedantic}; pub use self::bool::{guarded_transmute_bool_permissive, guarded_transmute_bool_pedantic}; /// Transmute 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. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # unsafe { /// # /* /// assert_eq!(guarded_transmute::(&[0x00, 0x00, 0x00, 0x01])?, 0x01000000); /// # */ /// # assert_eq!(guarded_transmute::(&[0x00, 0x00, 0x00, 0x01].le_to_native::()).unwrap(), 0x01000000); /// # } /// # } /// ``` pub unsafe fn guarded_transmute(bytes: &[u8]) -> Result { SingleManyGuard::check::(bytes)?; Ok(slice::from_raw_parts(bytes.as_ptr() as *const T, 1)[0]) } /// Transmute a byte slice into a single instance of a `Copy`able type. /// /// The byte slice must have exactly enough bytes to fill a single instance of a type. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_pedantic; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # unsafe { /// # /* /// assert_eq!(guarded_transmute_pedantic::(&[0x0F, 0x0E])?, 0x0E0F); /// # */ /// # assert_eq!(guarded_transmute_pedantic::(&[0x0F, 0x0E].le_to_native::()).unwrap(), 0x0E0F); /// # } /// # } /// ``` pub unsafe fn guarded_transmute_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 byte slice must have at least enough bytes to fill a single instance of a type, /// extraneous data is ignored. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_many; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # unsafe { /// # /* /// assert_eq!(guarded_transmute_many::(&[0x00, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(guarded_transmute_many::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()).unwrap(), /// &[0x0100, 0x0200]); /// # } /// # } /// ``` pub unsafe fn guarded_transmute_many(bytes: &[u8]) -> Result<&[T], Error> { SingleManyGuard::check::(bytes)?; Ok(slice::from_raw_parts(bytes.as_ptr() as *const 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. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_many_permissive; /// # unsafe { /// assert_eq!(guarded_transmute_many_permissive::(&[0x00]), &[]); /// # } /// ``` pub unsafe fn guarded_transmute_many_permissive(bytes: &[u8]) -> &[T] { PermissiveGuard::check::(bytes).unwrap(); slice::from_raw_parts(bytes.as_ptr() as *const T, bytes.len() / size_of::()) } /// View a byte slice as a slice of an arbitrary type. /// /// The byte slice must have at least enough bytes to fill a single instance of a type, /// and should not have extraneous data. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_many_pedantic; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # unsafe { /// # /* /// assert_eq!(guarded_transmute_many_pedantic::(&[0x0F, 0x0E, 0x0A, 0x0B])?, /// # */ /// # assert_eq!(guarded_transmute_many_pedantic::(&[0x0F, 0x0E, 0x0A, 0x0B].le_to_native::()).unwrap(), /// &[0x0E0F, 0x0B0A]); /// # } /// # } /// ``` pub unsafe fn guarded_transmute_many_pedantic(bytes: &[u8]) -> Result<&[T], Error> { PedanticGuard::check::(bytes)?; Ok(slice::from_raw_parts(bytes.as_ptr() as *const T, bytes.len() / size_of::())) } /// Trasform a byte vector into a vector of an arbitrary type. /// /// The resulting vec will reuse the allocated byte buffer when possible, and /// should have at least enough bytes to fill a single instance of a type. /// Extraneous data is ignored. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_vec; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # unsafe { /// # /* /// assert_eq!(guarded_transmute_vec::(vec![0x00, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(guarded_transmute_vec::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()).unwrap(), /// vec![0x0100, 0x0200]); /// # /* /// assert_eq!(guarded_transmute_vec::(vec![0x04, 0x00, 0x00, 0x00, 0xED])?, /// # */ /// # assert_eq!(guarded_transmute_vec::(vec![0x04, 0x00, 0x00, 0x00, 0xED].le_to_native::()).unwrap(), /// vec![0x00000004]); /// /// assert!(guarded_transmute_vec::(vec![0xED]).is_err()); /// # } /// # } /// ``` #[cfg(feature = "std")] pub unsafe fn guarded_transmute_vec(bytes: Vec) -> Result, Error> { SingleManyGuard::check::(&bytes)?; Ok(guarded_transmute_vec_permissive(bytes)) } /// Trasform a byte vector into a vector of an arbitrary type. /// /// The vector's allocated byte buffer will be reused when possible, and /// have as many instances of a type as will fit, rounded down. /// Extraneous data is ignored. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_vec_permissive; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # unsafe { /// # /* /// assert_eq!(guarded_transmute_vec_permissive::(vec![0x00, 0x01, 0x00, 0x02]), /// # */ /// # assert_eq!(guarded_transmute_vec_permissive::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()), /// vec![0x0100, 0x0200]); /// # /* /// assert_eq!(guarded_transmute_vec_permissive::(vec![0x04, 0x00, 0x00, 0x00, 0xED]), /// # */ /// # assert_eq!(guarded_transmute_vec_permissive::(vec![0x04, 0x00, 0x00, 0x00, 0xED].le_to_native::()), /// vec![0x00000004]); /// assert_eq!(guarded_transmute_vec_permissive::(vec![0xED]), vec![]); /// # } /// # } /// ``` #[cfg(feature = "std")] pub unsafe fn guarded_transmute_vec_permissive(mut bytes: Vec) -> Vec { PermissiveGuard::check::(&bytes).unwrap(); let ptr = bytes.as_mut_ptr(); let capacity = bytes.capacity() / size_of::(); let len = bytes.len() / size_of::(); forget(bytes); Vec::from_raw_parts(ptr as *mut T, len, capacity) } /// Trasform a byte vector into a vector of an arbitrary type. /// /// The vector's allocated byte buffer will be reused when possible, and /// should not have extraneous data. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_vec_pedantic; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # unsafe { /// # /* /// assert_eq!(guarded_transmute_vec_pedantic::(vec![0x00, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(guarded_transmute_vec_pedantic::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()).unwrap(), /// vec![0x0100, 0x0200]); /// /// assert!(guarded_transmute_vec_pedantic::(vec![0x04, 0x00, 0x00, 0x00, 0xED]).is_err()); /// # } /// # } /// ``` #[cfg(feature = "std")] pub unsafe fn guarded_transmute_vec_pedantic(bytes: Vec) -> Result, Error> { PedanticGuard::check::(&bytes)?; Ok(guarded_transmute_vec_permissive(bytes)) } safe-transmute-0.10.1/src/pod.rs000064400000000000000000000250601337560243500146470ustar0000000000000000use self::super::{Error, guarded_transmute_many_permissive, guarded_transmute_many_pedantic, guarded_transmute_pedantic, guarded_transmute_many, guarded_transmute}; #[cfg(feature = "std")] use self::super::{guarded_transmute_vec_permissive, guarded_transmute_vec_pedantic, guarded_transmute_vec}; /// Type that can be non-`unsafe`ly transmuted into /// /// In most 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). /// /// Marker trait for `guarded_transmute_pod_*()` functions. /// /// *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*: guarded transmutation to `bool`s is provided as separate functions, 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 `PodTransmutable` for a type `T` if it is safe for a slice of any arbitrary data /// `&[u8]` of length `sizeof()` to be [`transmute()`](https://doc.rust-lang.org/stable/std/mem/fn.transmute.html)d /// to a unit-length `&[T]`. /// /// Consult the [Transmutes section](https://doc.rust-lang.org/nomicon/transmutes.html) of the Nomicon for more details. pub unsafe trait PodTransmutable: Copy {} unsafe impl PodTransmutable for u8 {} unsafe impl PodTransmutable for i8 {} unsafe impl PodTransmutable for u16 {} unsafe impl PodTransmutable for i16 {} unsafe impl PodTransmutable for u32 {} unsafe impl PodTransmutable for i32 {} unsafe impl PodTransmutable for u64 {} unsafe impl PodTransmutable for i64 {} unsafe impl PodTransmutable for usize {} unsafe impl PodTransmutable for isize {} unsafe impl PodTransmutable for f32 {} unsafe impl PodTransmutable for f64 {} #[cfg(i128_type)] unsafe impl PodTransmutable for u128 {} #[cfg(i128_type)] unsafe impl PodTransmutable for i128 {} unsafe impl PodTransmutable for [T; 1] {} unsafe impl PodTransmutable for [T; 2] {} unsafe impl PodTransmutable for [T; 3] {} unsafe impl PodTransmutable for [T; 4] {} unsafe impl PodTransmutable for [T; 5] {} unsafe impl PodTransmutable for [T; 6] {} unsafe impl PodTransmutable for [T; 7] {} unsafe impl PodTransmutable for [T; 8] {} unsafe impl PodTransmutable for [T; 9] {} unsafe impl PodTransmutable for [T; 10] {} unsafe impl PodTransmutable for [T; 11] {} unsafe impl PodTransmutable for [T; 12] {} unsafe impl PodTransmutable for [T; 13] {} unsafe impl PodTransmutable for [T; 14] {} unsafe impl PodTransmutable for [T; 15] {} unsafe impl PodTransmutable for [T; 16] {} unsafe impl PodTransmutable for [T; 17] {} unsafe impl PodTransmutable for [T; 18] {} unsafe impl PodTransmutable for [T; 19] {} unsafe impl PodTransmutable for [T; 20] {} unsafe impl PodTransmutable for [T; 21] {} unsafe impl PodTransmutable for [T; 22] {} unsafe impl PodTransmutable for [T; 23] {} unsafe impl PodTransmutable for [T; 24] {} unsafe impl PodTransmutable for [T; 25] {} unsafe impl PodTransmutable for [T; 26] {} unsafe impl PodTransmutable for [T; 27] {} unsafe impl PodTransmutable for [T; 28] {} unsafe impl PodTransmutable for [T; 29] {} unsafe impl PodTransmutable for [T; 30] {} unsafe impl PodTransmutable for [T; 31] {} unsafe impl PodTransmutable for [T; 32] {} /// Transmute a byte slice into a single instance of a POD. /// /// The byte slice must have at least enough bytes to fill a single instance of a type, /// extraneous data is ignored. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_pod; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(guarded_transmute_pod::(&[0x00, 0x00, 0x00, 0x01])?, 0x01000000); /// # */ /// # assert_eq!(guarded_transmute_pod::(&[0x00, 0x00, 0x00, 0x01].le_to_native::()).unwrap(), 0x01000000); /// # } /// ``` pub fn guarded_transmute_pod(bytes: &[u8]) -> Result { unsafe { guarded_transmute(bytes) } } /// Transmute a byte slice into a single instance of a POD. /// /// The byte slice must have exactly enough bytes to fill a single instance of a type. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_pod_pedantic; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(guarded_transmute_pod_pedantic::(&[0x0F, 0x0E])?, 0x0E0F); /// # */ /// # assert_eq!(guarded_transmute_pod_pedantic::(&[0x0F, 0x0E].le_to_native::()).unwrap(), 0x0E0F); /// # } /// ``` pub fn guarded_transmute_pod_pedantic(bytes: &[u8]) -> Result { unsafe { guarded_transmute_pedantic(bytes) } } /// Transmute a byte slice into a single instance of a POD. /// /// The byte slice must have exactly enough bytes to fill a single instance of a type. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_pod_many; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(guarded_transmute_pod_many::(&[0x00, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(guarded_transmute_pod_many::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()).unwrap(), /// &[0x0100, 0x0200]); /// # } /// ``` pub fn guarded_transmute_pod_many(bytes: &[u8]) -> Result<&[T], Error> { unsafe { guarded_transmute_many(bytes) } } /// View a byte slice as a slice of a POD type. /// /// The resulting slice will have as many instances of a type as will fit, rounded down. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_pod_many_permissive; /// assert_eq!(guarded_transmute_pod_many_permissive::(&[0x00]), &[]); /// ``` pub fn guarded_transmute_pod_many_permissive(bytes: &[u8]) -> &[T] { unsafe { guarded_transmute_many_permissive(bytes) } } /// View a byte slice as a slice of POD. /// /// The byte slice must have at least enough bytes to fill a single instance of a type, /// and should not have extraneous data. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_pod_many_pedantic; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(guarded_transmute_pod_many_pedantic::(&[0x0F, 0x0E, 0x0A, 0x0B])?, /// # */ /// # assert_eq!(guarded_transmute_pod_many_pedantic::(&[0x0F, 0x0E, 0x0A, 0x0B].le_to_native::()).unwrap(), /// &[0x0E0F, 0x0B0A]); /// # } /// ``` pub fn guarded_transmute_pod_many_pedantic(bytes: &[u8]) -> Result<&[T], Error> { unsafe { guarded_transmute_many_pedantic(bytes) } } /// Trasform a byte vector into a vector of POD. /// /// The resulting vec will reuse the allocated byte buffer when possible, and /// should have at least enough bytes to fill a single instance of a type. /// Extraneous data is ignored. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_pod_vec; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(guarded_transmute_pod_vec::(vec![0x00, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(guarded_transmute_pod_vec::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()).unwrap(), /// vec![0x0100, 0x0200]); /// # /* /// assert_eq!(guarded_transmute_pod_vec::(vec![0x04, 0x00, 0x00, 0x00, 0xED])?, /// # */ /// # assert_eq!(guarded_transmute_pod_vec::(vec![0x04, 0x00, 0x00, 0x00, 0xED].le_to_native::()).unwrap(), /// vec![0x00000004]); /// /// assert!(guarded_transmute_pod_vec::(vec![0xED]).is_err()); /// # } /// ``` #[cfg(feature = "std")] pub fn guarded_transmute_pod_vec(bytes: Vec) -> Result, Error> { unsafe { guarded_transmute_vec(bytes) } } /// Trasform a byte vector into a vector of POD. /// /// The vector's allocated byte buffer will be reused when possible, and /// have as many instances of a type as will fit, rounded down. /// Extraneous data is ignored. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_pod_vec_permissive; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(guarded_transmute_pod_vec_permissive::(vec![0x00, 0x01, 0x00, 0x02]), /// # */ /// # assert_eq!(guarded_transmute_pod_vec_permissive::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()), /// vec![0x0100, 0x0200]); /// # /* /// assert_eq!(guarded_transmute_pod_vec_permissive::(vec![0x04, 0x00, 0x00, 0x00, 0xED]), /// # */ /// # assert_eq!(guarded_transmute_pod_vec_permissive::(vec![0x04, 0x00, 0x00, 0x00, 0xED].le_to_native::()), /// vec![0x00000004]); /// assert_eq!(guarded_transmute_pod_vec_permissive::(vec![0xED]), vec![]); /// # } /// ``` #[cfg(feature = "std")] pub fn guarded_transmute_pod_vec_permissive(bytes: Vec) -> Vec { unsafe { guarded_transmute_vec_permissive(bytes) } } /// Trasform a byte vector into a vector of POD. /// /// The vector's allocated byte buffer will be reused when possible, and /// should not have extraneous data. /// /// # Examples /// /// ``` /// # use safe_transmute::guarded_transmute_pod_vec_pedantic; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// // Little-endian /// # /* /// assert_eq!(guarded_transmute_pod_vec_pedantic::(vec![0x00, 0x01, 0x00, 0x02])?, /// # */ /// # assert_eq!(guarded_transmute_pod_vec_pedantic::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()).unwrap(), /// vec![0x0100, 0x0200]); /// /// assert!(guarded_transmute_pod_vec_pedantic::(vec![0x04, 0x00, 0x00, 0x00, 0xED]) /// .is_err()); /// # } /// ``` #[cfg(feature = "std")] pub fn guarded_transmute_pod_vec_pedantic(bytes: Vec) -> Result, Error> { unsafe { guarded_transmute_vec_pedantic(bytes) } } safe-transmute-0.10.1/src/to_bytes.rs000064400000000000000000000176731337727273200157350ustar0000000000000000//! Functions for transmutation *from* a concrete type *to* bytes. use self::super::PodTransmutable; #[cfg(feature = "std")] use core::mem::forget; use core::mem::size_of; use core::slice; /// Transmute a single instance of an arbitrary type into a slice of its bytes. /// /// # Examples /// /// An `u32`: /// /// ``` /// # use safe_transmute::guarded_transmute_to_bytes; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// # unsafe { /// assert_eq!(guarded_transmute_to_bytes(&0x01234567), /// # /* /// &[0x67, 0x45, 0x23, 0x01]); /// # */ /// # [0x67, 0x45, 0x23, 0x01].le_to_native::()); /// # } /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::guarded_transmute_to_bytes; /// #[repr(C)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// /// # unsafe { /// assert_eq!(guarded_transmute_to_bytes(&Gene { /// x1: 0x42, /// x2: 0x69, /// }), /// &[0x42, 0x69]); /// # } /// ``` pub unsafe fn guarded_transmute_to_bytes(from: &T) -> &[u8] { slice::from_raw_parts(from as *const T as *const u8, size_of::()) } /// Transmute a slice of arbitrary types into a slice of their bytes. /// /// # Examples /// /// Some `u16`s: /// /// ``` /// # use safe_transmute::guarded_transmute_to_bytes; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// # unsafe { /// assert_eq!(guarded_transmute_to_bytes(&[0x0123u16, 0x4567u16]), /// # /* /// &[0x23, 0x01, 0x67, 0x45]); /// # */ /// # [0x23, 0x01, 0x67, 0x45].le_to_native::()); /// # } /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::{PodTransmutable, guarded_transmute_to_bytes_many}; /// #[repr(C)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// /// # unsafe { /// assert_eq!(guarded_transmute_to_bytes_many(&[Gene { /// x1: 0x42, /// x2: 0x69, /// }, /// Gene { /// x1: 0x12, /// x2: 0x48, /// }]), /// &[0x42, 0x69, 0x12, 0x48]); /// # } /// ``` pub unsafe fn guarded_transmute_to_bytes_many(from: &[T]) -> &[u8] { slice::from_raw_parts(from.as_ptr() as *const u8, from.len() * size_of::()) } /// Transmute a single instance of a POD type into a slice of its bytes. /// /// # Examples /// /// An `u32`: /// /// ``` /// # use safe_transmute::guarded_transmute_to_bytes_pod; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// assert_eq!(guarded_transmute_to_bytes_pod(&0x01234567), /// # /* /// &[0x67, 0x45, 0x23, 0x01]); /// # */ /// # [0x67, 0x45, 0x23, 0x01].le_to_native::()); /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::{PodTransmutable, guarded_transmute_to_bytes_pod}; /// #[repr(C)] /// #[derive(Clone, Copy)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// unsafe impl PodTransmutable for Gene {} /// /// assert_eq!(guarded_transmute_to_bytes_pod(&Gene { /// x1: 0x42, /// x2: 0x69, /// }), /// &[0x42, 0x69]); /// ``` pub fn guarded_transmute_to_bytes_pod(from: &T) -> &[u8] { unsafe { guarded_transmute_to_bytes(from) } } /// Transmute a slice of arbitrary types into a slice of their bytes. /// /// # Examples /// /// Some `u16`s: /// /// ``` /// # use safe_transmute::guarded_transmute_to_bytes_pod_many; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// assert_eq!(guarded_transmute_to_bytes_pod_many(&[0x0123u16, 0x4567u16]), /// # /* /// &[0x23, 0x01, 0x67, 0x45]); /// # */ /// # [0x23, 0x01, 0x67, 0x45].le_to_native::()); /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::{PodTransmutable, guarded_transmute_to_bytes_pod_many}; /// #[repr(C)] /// #[derive(Clone, Copy)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// unsafe impl PodTransmutable for Gene {} /// /// assert_eq!(guarded_transmute_to_bytes_pod_many(&[Gene { /// x1: 0x42, /// x2: 0x69, /// }, /// Gene { /// x1: 0x12, /// x2: 0x48, /// }]), /// &[0x42, 0x69, 0x12, 0x48]); /// ``` pub fn guarded_transmute_to_bytes_pod_many(from: &[T]) -> &[u8] { unsafe { guarded_transmute_to_bytes_many(from) } } /// Transmute a vector of arbitrary types into a vector of their bytes, /// using the same memory buffer as the former. /// /// # Examples /// /// Some `u16`s: /// /// ``` /// # use safe_transmute::guarded_transmute_to_bytes_vec; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// # unsafe { /// assert_eq!(guarded_transmute_to_bytes_vec(vec![0x0123u16, 0x4567u16]), /// # /* /// vec![0x23, 0x01, 0x67, 0x45]); /// # */ /// # vec![0x23, 0x01, 0x67, 0x45].le_to_native::()); /// # } /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::guarded_transmute_to_bytes_vec; /// #[repr(C)] /// #[derive(Clone, Copy)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// /// # unsafe { /// assert_eq!(guarded_transmute_to_bytes_vec(vec![Gene { /// x1: 0x42, /// x2: 0x69, /// }, /// Gene { /// x1: 0x12, /// x2: 0x48, /// }]), /// vec![0x42, 0x69, 0x12, 0x48]); /// # } /// ``` #[cfg(feature = "std")] pub unsafe fn guarded_transmute_to_bytes_vec(mut from: Vec) -> Vec { let capacity = from.capacity() * size_of::(); let len = from.len() * size_of::(); let ptr = from.as_mut_ptr(); forget(from); Vec::from_raw_parts(ptr as *mut u8, len, capacity) } /// Transmute a vector of POD types into a vector of their bytes, /// using the same memory buffer as the former. /// /// # Examples /// /// Some `u16`s: /// /// ``` /// # use safe_transmute::guarded_transmute_to_bytes_pod_vec; /// # include!("../tests/test_util/le_to_native.rs"); /// # fn main() { /// assert_eq!(guarded_transmute_to_bytes_pod_vec(vec![0x0123u16, 0x4567u16]), /// # /* /// vec![0x23, 0x01, 0x67, 0x45]); /// # */ /// # vec![0x23, 0x01, 0x67, 0x45].le_to_native::()); /// # } /// ``` /// /// An arbitrary type: /// /// ``` /// # use safe_transmute::{PodTransmutable, guarded_transmute_to_bytes_pod_vec}; /// #[repr(C)] /// #[derive(Clone, Copy)] /// struct Gene { /// x1: u8, /// x2: u8, /// } /// unsafe impl PodTransmutable for Gene {} /// /// assert_eq!(guarded_transmute_to_bytes_pod_vec(vec![Gene { /// x1: 0x42, /// x2: 0x69, /// }, /// Gene { /// x1: 0x12, /// x2: 0x48, /// }]), /// vec![0x42, 0x69, 0x12, 0x48]); /// ``` #[cfg(feature = "std")] pub fn guarded_transmute_to_bytes_pod_vec(from: Vec) -> Vec { unsafe { guarded_transmute_to_bytes_vec(from) } } safe-transmute-0.10.1/src/util.rs000064400000000000000000000026701337560243500150440ustar0000000000000000//! Module containing various utility functions. use core::mem::transmute; /// If the specified 32-bit float is a signaling NaN, make it a quiet NaN. /// /// Based on [`f32::from_bits()`](https://github.com/rust-lang/rust/pull/39271/files#diff-f60977ab00fd9ea9ba7ac918e12a8f42R1279) pub fn designalise_f32(f: f32) -> f32 { const EXP_MASK: u32 = 0x7F800000; const QNAN_MASK: u32 = 0x00400000; const FRACT_MASK: u32 = 0x007FFFFF; let mut f: u32 = unsafe { transmute(f) }; if f & EXP_MASK == EXP_MASK && f & 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 f |= QNAN_MASK; } unsafe { transmute(f) } } /// If the specified 64-bit float is a signaling NaN, make it a quiet NaN. /// /// Based on [`f64::from_bits()`](https://github.com/rust-lang/rust/pull/39271/files#diff-2ae382eb5bbc830a6b884b8a6ba5d95fR1171) pub fn designalise_f64(f: f64) -> f64 { const EXP_MASK: u64 = 0x7FF0000000000000; const QNAN_MASK: u64 = 0x0001000000000000; const FRACT_MASK: u64 = 0x000FFFFFFFFFFFFF; let mut f: u64 = unsafe { transmute(f) }; if f & EXP_MASK == EXP_MASK && f & 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 f |= QNAN_MASK; } unsafe { transmute(f) } } safe-transmute-0.10.1/tests/guarded_transmute/mod.rs000064400000000000000000000030771326744021400207330ustar0000000000000000use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute}; use self::super::LeToNative; #[test] fn too_short() { unsafe { assert_eq!(guarded_transmute::(&[]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(guarded_transmute::(&[0x00]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } } #[test] fn just_enough() { unsafe { assert_eq!(guarded_transmute::(&[0x00, 0x00, 0x00, 0x01].le_to_native::()), Ok(0x01000000)); } } #[test] fn too_much() { unsafe { assert_eq!(guarded_transmute::(&[0x00, 0x00, 0x00, 0x01, 0x00].le_to_native::()), Ok(0x01000000)); assert_eq!(guarded_transmute::(&[0x00, 0x00, 0x00, 0x01, 0x00, 0x00].le_to_native::()), Ok(0x01000000)); assert_eq!(guarded_transmute::(&[0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00].le_to_native::()), Ok(0x01000000)); assert_eq!(guarded_transmute::(&[0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00].le_to_native::()), Ok(0x01000000)); assert_eq!(guarded_transmute::(&[0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00].le_to_native::()), Ok(0x01000000)); } } safe-transmute-0.10.1/tests/guarded_transmute_bool_pedantic/mod.rs000064400000000000000000000017361326744021400236150ustar0000000000000000use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_bool_pedantic}; #[test] fn too_short() { assert_eq!(guarded_transmute_bool_pedantic([].as_ref()), Err(Error::Guard(GuardError { required: 1, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { assert_eq!(guarded_transmute_bool_pedantic([0x00, 0x01].as_ref()), Ok([false, true].into_iter().as_slice())); assert_eq!(guarded_transmute_bool_pedantic([0x01, 0x01, 0x00, 0x01].as_ref()), Ok([true, true, false, true].into_iter().as_slice())); } #[test] fn invalid_bytes() { assert_eq!(guarded_transmute_bool_pedantic([0x00, 0x01, 0x02].as_ref()), Err(Error::InvalidValue)); assert_eq!(guarded_transmute_bool_pedantic([0x05, 0x01, 0x00].as_ref()), Err(Error::InvalidValue)); assert_eq!(guarded_transmute_bool_pedantic([0xFF].as_ref()), Err(Error::InvalidValue)); } safe-transmute-0.10.1/tests/guarded_transmute_bool_permissive/mod.rs000064400000000000000000000014221326744021400242040ustar0000000000000000use safe_transmute::{Error, guarded_transmute_bool_permissive}; #[test] fn too_short() { assert_eq!(guarded_transmute_bool_permissive([].as_ref()), Ok([].as_ref())); } #[test] fn just_enough() { assert_eq!(guarded_transmute_bool_permissive([0x00, 0x01].as_ref()), Ok([false, true].as_ref())); assert_eq!(guarded_transmute_bool_permissive([0x00, 0x01, 0x00, 0x01].as_ref()), Ok([false, true, false, true].as_ref())); } #[test] fn invalid_bytes() { assert_eq!(guarded_transmute_bool_permissive([0x00, 0x01, 0x02].as_ref()), Err(Error::InvalidValue)); assert_eq!(guarded_transmute_bool_permissive([0x05, 0x01, 0x00].as_ref()), Err(Error::InvalidValue)); assert_eq!(guarded_transmute_bool_permissive([0xFF].as_ref()), Err(Error::InvalidValue)); } safe-transmute-0.10.1/tests/guarded_transmute_bool_vec_pedantic/mod.rs000064400000000000000000000017201337224757600244600ustar0000000000000000#![cfg(feature = "std")] use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_bool_vec_pedantic}; #[test] fn too_short() { assert_eq!(guarded_transmute_bool_vec_pedantic(vec![]), Err(Error::Guard(GuardError { required: 1, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { assert_eq!(guarded_transmute_bool_vec_pedantic(vec![0x00, 0x01]), Ok(vec![false, true])); assert_eq!(guarded_transmute_bool_vec_pedantic(vec![0x00, 0x01, 0x00, 0x01]), Ok(vec![false, true, false, true])); } #[test] fn invalid_bytes() { assert_eq!(guarded_transmute_bool_vec_pedantic(vec![0x00, 0x01, 0x02]), Err(Error::InvalidValue)); assert_eq!(guarded_transmute_bool_vec_pedantic(vec![0x05, 0x01, 0x00]), Err(Error::InvalidValue)); assert_eq!(guarded_transmute_bool_vec_pedantic(vec![0xFF]), Err(Error::InvalidValue)); } safe-transmute-0.10.1/tests/guarded_transmute_bool_vec_permissive/mod.rs000064400000000000000000000014321337224757600250570ustar0000000000000000#![cfg(feature = "std")] use safe_transmute::{Error, guarded_transmute_bool_vec_permissive}; #[test] fn too_short() { assert_eq!(guarded_transmute_bool_vec_permissive(vec![]), Ok(vec![])); } #[test] fn just_enough() { assert_eq!(guarded_transmute_bool_vec_permissive(vec![0x00, 0x01]), Ok(vec![false, true])); assert_eq!(guarded_transmute_bool_vec_permissive(vec![0x00, 0x01, 0x00, 0x01]), Ok(vec![false, true, false, true])); } #[test] fn invalid_bytes() { assert_eq!(guarded_transmute_bool_vec_permissive(vec![0x00, 0x01, 0x02]), Err(Error::InvalidValue)); assert_eq!(guarded_transmute_bool_vec_permissive(vec![0x05, 0x01, 0x00]), Err(Error::InvalidValue)); assert_eq!(guarded_transmute_bool_vec_permissive(vec![0xFF]), Err(Error::InvalidValue)); } safe-transmute-0.10.1/tests/guarded_transmute_many/mod.rs000064400000000000000000000074251327070743300217630ustar0000000000000000use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_many}; use self::super::LeToNative; #[test] fn too_short() { unsafe { assert_eq!(guarded_transmute_many::(&[]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(guarded_transmute_many::(&[0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } } #[test] fn just_enough() { unsafe { assert_eq!(guarded_transmute_many::(&[0x00, 0x01].le_to_native::()), Ok([0x0100u16].into_iter().as_slice())); assert_eq!(guarded_transmute_many::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()), Ok([0x0100u16, 0x0200u16].into_iter().as_slice())); } } #[test] fn too_much() { unsafe { assert_eq!(guarded_transmute_many::(&[0x00, 0x01, 0x00].le_to_native::()), Ok([0x0100u16].into_iter().as_slice())); assert_eq!(guarded_transmute_many::(&[0x00, 0x01, 0x00, 0x02, 0x00].le_to_native::()), Ok([0x0100u16, 0x0200u16].into_iter().as_slice())); assert_eq!(guarded_transmute_many::(&[0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00].le_to_native::()), Ok([0x0100u16, 0x0200u16, 0x0300u16].into_iter().as_slice())); } } #[cfg(feature = "test-unaligned")] #[cfg(target_endian = "little")] #[test] fn unaligned_slicing() { let bytes = &[0xFF, 0x01, 0xEE, 0x02, 0xDD, 0x03, 0xCC]; unsafe { assert_eq!(guarded_transmute_many::(bytes), Ok([0x01FF, 0x02EE, 0x03DD].into_iter().as_slice())); assert_eq!(guarded_transmute_many::(&bytes[1..]), Ok([0xEE01, 0xDD02, 0xCC03].into_iter().as_slice())); } let bytes: &[u8] = &[0xFF, 0x01, 0xEE, 0x02, 0xDD, 0x03, 0xCC, 0x04, 0xBB, 0x05, 0xAA, 0x06]; unsafe { assert_eq!(guarded_transmute_many::(bytes), Ok([0x02EE01FF, 0x04CC03DD, 0x06AA05BB].into_iter().as_slice())); assert_eq!(guarded_transmute_many::(&bytes[1..]), Ok([0xDD02EE01, 0xBB04CC03].into_iter().as_slice())); assert_eq!(guarded_transmute_many::(&bytes[2..]), Ok([0x03DD02EE, 0x05BB04CC].into_iter().as_slice())); assert_eq!(guarded_transmute_many::(&bytes[3..]), Ok([0xCC03DD02, 0xAA05BB04].into_iter().as_slice())); } } #[cfg(feature = "test-unaligned")] #[cfg(target_endian = "big")] #[test] fn unaligned_slicing() { let bytes = &[0xFF, 0x01, 0xEE, 0x02, 0xDD, 0x03, 0xCC]; unsafe { assert_eq!(guarded_transmute_many::(bytes), Ok([0xFF01, 0xEE02, 0xDD03].into_iter().as_slice())); assert_eq!(guarded_transmute_many::(&bytes[1..]), Ok([0x01EE, 0x02DD, 0x03CC].into_iter().as_slice())); } let bytes: &[u8] = &[0xFF, 0x01, 0xEE, 0x02, 0xDD, 0x03, 0xCC, 0x04, 0xBB, 0x05, 0xAA, 0x06]; unsafe { assert_eq!(guarded_transmute_many::(bytes), Ok([0xFF01EE02, 0xDD03CC04, 0xBB05AA06].into_iter().as_slice())); assert_eq!(guarded_transmute_many::(&bytes[1..]), Ok([0x01EE02DD, 0x03CC04BB].into_iter().as_slice())); assert_eq!(guarded_transmute_many::(&bytes[2..]), Ok([0xEE02DD03, 0xCC04BB05].into_iter().as_slice())); assert_eq!(guarded_transmute_many::(&bytes[3..]), Ok([0x02DD03CC, 0x04BB05AA].into_iter().as_slice())); } } safe-transmute-0.10.1/tests/guarded_transmute_many_pedantic/mod.rs000064400000000000000000000033121326744021400236160ustar0000000000000000use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_many_pedantic}; use self::super::LeToNative; #[test] fn too_short() { unsafe { assert_eq!(guarded_transmute_many_pedantic::(&[]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(guarded_transmute_many_pedantic::(&[0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } } #[test] fn just_enough() { unsafe { assert_eq!(guarded_transmute_many_pedantic::(&[0x00, 0x01].le_to_native::()), Ok([0x0100u16].into_iter().as_slice())); assert_eq!(guarded_transmute_many_pedantic::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()), Ok([0x0100u16, 0x0200u16].into_iter().as_slice())); } } #[test] fn too_much() { unsafe { assert_eq!(guarded_transmute_many_pedantic::(&[0x00, 0x01, 0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 3, reason: ErrorReason::InexactByteCount, }))); assert_eq!(guarded_transmute_many_pedantic::(&[0x00, 0x01, 0x00, 0x02, 0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 5, reason: ErrorReason::InexactByteCount, }))); } } safe-transmute-0.10.1/tests/guarded_transmute_many_permissive/mod.rs000064400000000000000000000021461326125240400242150ustar0000000000000000use safe_transmute::guarded_transmute_many_permissive; use self::super::LeToNative; #[test] fn too_short() { unsafe { assert_eq!(guarded_transmute_many_permissive::(&[]), &[]); assert_eq!(guarded_transmute_many_permissive::(&[0x00]), &[]); } } #[test] fn just_enough() { unsafe { assert_eq!(guarded_transmute_many_permissive::(&[0x00, 0x01].le_to_native::()), &[0x0100u16]); assert_eq!(guarded_transmute_many_permissive::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()), &[0x0100u16, 0x0200u16]); } } #[test] fn too_much() { unsafe { assert_eq!(guarded_transmute_many_permissive::(&[0x00, 0x01, 0x00].le_to_native::()), &[0x0100u16]); assert_eq!(guarded_transmute_many_permissive::(&[0x00, 0x01, 0x00, 0x02, 0x00].le_to_native::()), &[0x0100u16, 0x0200u16]); assert_eq!(guarded_transmute_many_permissive::(&[0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00].le_to_native::()), &[0x0100u16, 0x0200u16, 0x0300u16]); } } safe-transmute-0.10.1/tests/guarded_transmute_pedantic/mod.rs000064400000000000000000000023231326744021400225730ustar0000000000000000use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_pedantic}; use self::super::LeToNative; #[test] fn too_short() { unsafe { assert_eq!(guarded_transmute_pedantic::(&[]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 0, reason: ErrorReason::InexactByteCount, }))); assert_eq!(guarded_transmute_pedantic::(&[0x00]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 1, reason: ErrorReason::InexactByteCount, }))); } } #[test] fn just_enough() { unsafe { assert_eq!(guarded_transmute_pedantic::(&[0x00, 0x00, 0x00, 0x01].le_to_native::()), Ok(0x01000000)); } } #[test] fn too_much() { unsafe { assert_eq!(guarded_transmute_pedantic::(&[0x00, 0x00, 0x00, 0x01, 0x00]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 5, reason: ErrorReason::InexactByteCount, }))); } } safe-transmute-0.10.1/tests/guarded_transmute_pod/mod.rs000064400000000000000000000027411326744021400215720ustar0000000000000000use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_pod}; use self::super::LeToNative; #[test] fn too_short() { assert_eq!(guarded_transmute_pod::(&[]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(guarded_transmute_pod::(&[0x00]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { assert_eq!(guarded_transmute_pod::(&[0x00, 0x00, 0x00, 0x01].le_to_native::()), Ok(0x01000000)); } #[test] fn too_much() { assert_eq!(guarded_transmute_pod::(&[0x00, 0x00, 0x00, 0x01, 0x00].le_to_native::()), Ok(0x01000000)); assert_eq!(guarded_transmute_pod::(&[0x00, 0x00, 0x00, 0x01, 0x00, 0x00].le_to_native::()), Ok(0x01000000)); assert_eq!(guarded_transmute_pod::(&[0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00].le_to_native::()), Ok(0x01000000)); assert_eq!(guarded_transmute_pod::(&[0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00].le_to_native::()), Ok(0x01000000)); assert_eq!(guarded_transmute_pod::(&[0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00].le_to_native::()), Ok(0x01000000)); } safe-transmute-0.10.1/tests/guarded_transmute_pod_many/mod.rs000064400000000000000000000027521326744021400226200ustar0000000000000000use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_pod_many}; use self::super::LeToNative; #[test] fn too_short() { assert_eq!(guarded_transmute_pod_many::(&[]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(guarded_transmute_pod_many::(&[0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { assert_eq!(guarded_transmute_pod_many::(&[0x00, 0x01].le_to_native::()), Ok([0x0100u16].into_iter().as_slice())); assert_eq!(guarded_transmute_pod_many::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()), Ok([0x0100u16, 0x0200u16].into_iter().as_slice())); } #[test] fn too_much() { assert_eq!(guarded_transmute_pod_many::(&[0x00, 0x01, 0x00].le_to_native::()), Ok([0x0100u16].into_iter().as_slice())); assert_eq!(guarded_transmute_pod_many::(&[0x00, 0x01, 0x00, 0x02, 0x00].le_to_native::()), Ok([0x0100u16, 0x0200u16].into_iter().as_slice())); assert_eq!(guarded_transmute_pod_many::(&[0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00].le_to_native::()), Ok([0x0100u16, 0x0200u16, 0x0300u16].into_iter().as_slice())); } safe-transmute-0.10.1/tests/guarded_transmute_pod_many_pedantic/mod.rs000064400000000000000000000030751326744021400244660ustar0000000000000000use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_pod_many_pedantic}; use self::super::LeToNative; #[test] fn too_short() { assert_eq!(guarded_transmute_pod_many_pedantic::(&[]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(guarded_transmute_pod_many_pedantic::(&[0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { assert_eq!(guarded_transmute_pod_many_pedantic::(&[0x00, 0x01].le_to_native::()), Ok([0x0100u16].into_iter().as_slice())); assert_eq!(guarded_transmute_pod_many_pedantic::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()), Ok([0x0100u16, 0x0200u16].into_iter().as_slice())); } #[test] fn too_much() { assert_eq!(guarded_transmute_pod_many_pedantic::(&[0x00, 0x01, 0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 3, reason: ErrorReason::InexactByteCount, }))); assert_eq!(guarded_transmute_pod_many_pedantic::(&[0x00, 0x01, 0x00, 0x02, 0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 5, reason: ErrorReason::InexactByteCount, }))); } safe-transmute-0.10.1/tests/guarded_transmute_pod_many_permissive/mod.rs000064400000000000000000000020411326125240400250510ustar0000000000000000use safe_transmute::guarded_transmute_pod_many_permissive; use self::super::LeToNative; #[test] fn too_short() { assert_eq!(guarded_transmute_pod_many_permissive::(&[]), &[]); assert_eq!(guarded_transmute_pod_many_permissive::(&[0x00]), &[]); } #[test] fn just_enough() { assert_eq!(guarded_transmute_pod_many_permissive::(&[0x00, 0x01].le_to_native::()), &[0x0100u16]); assert_eq!(guarded_transmute_pod_many_permissive::(&[0x00, 0x01, 0x00, 0x02].le_to_native::()), &[0x0100u16, 0x0200u16]); } #[test] fn too_much() { assert_eq!(guarded_transmute_pod_many_permissive::(&[0x00, 0x01, 0x00].le_to_native::()), &[0x0100u16]); assert_eq!(guarded_transmute_pod_many_permissive::(&[0x00, 0x01, 0x00, 0x02, 0x00].le_to_native::()), &[0x0100u16, 0x0200u16]); assert_eq!(guarded_transmute_pod_many_permissive::(&[0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00].le_to_native::()), &[0x0100u16, 0x0200u16, 0x0300u16]); } safe-transmute-0.10.1/tests/guarded_transmute_pod_pedantic/mod.rs000064400000000000000000000021361326744021400234370ustar0000000000000000use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_pod_pedantic}; use self::super::LeToNative; #[test] fn too_short() { assert_eq!(guarded_transmute_pod_pedantic::(&[]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 0, reason: ErrorReason::InexactByteCount, }))); assert_eq!(guarded_transmute_pod_pedantic::(&[0x00]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 1, reason: ErrorReason::InexactByteCount, }))); } #[test] fn just_enough() { assert_eq!(guarded_transmute_pod_pedantic::(&[0x00, 0x00, 0x00, 0x01].le_to_native::()), Ok(0x01000000)); } #[test] fn too_much() { assert_eq!(guarded_transmute_pod_pedantic::(&[0x00, 0x00, 0x00, 0x01, 0x00]), Err(Error::Guard(GuardError { required: 32 / 8, actual: 5, reason: ErrorReason::InexactByteCount, }))); } safe-transmute-0.10.1/tests/guarded_transmute_pod_vec/mod.rs000064400000000000000000000026421337224757600224440ustar0000000000000000#![cfg(feature = "std")] use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_pod_vec}; use self::super::LeToNative; #[test] fn too_short() { assert_eq!(guarded_transmute_pod_vec::(vec![]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(guarded_transmute_pod_vec::(vec![0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { assert_eq!(guarded_transmute_pod_vec::(vec![0x00, 0x01].le_to_native::()), Ok(vec![0x0100u16])); assert_eq!(guarded_transmute_pod_vec::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()), Ok(vec![0x0100u16, 0x0200u16])); } #[test] fn too_much() { assert_eq!(guarded_transmute_pod_vec::(vec![0x00, 0x01, 0x00].le_to_native::()), Ok(vec![0x0100u16])); assert_eq!(guarded_transmute_pod_vec::(vec![0x00, 0x01, 0x00, 0x02, 0x00].le_to_native::()), Ok(vec![0x0100u16, 0x0200u16])); assert_eq!(guarded_transmute_pod_vec::(vec![0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00].le_to_native::()), Ok(vec![0x0100u16, 0x0200u16, 0x0300u16])); } safe-transmute-0.10.1/tests/guarded_transmute_pod_vec_pedantic/mod.rs000064400000000000000000000030731337224757600243120ustar0000000000000000#![cfg(feature = "std")] use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_pod_vec_pedantic}; use self::super::LeToNative; #[test] fn too_short() { assert_eq!(guarded_transmute_pod_vec_pedantic::(vec![]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(guarded_transmute_pod_vec_pedantic::(vec![0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } #[test] fn just_enough() { assert_eq!(guarded_transmute_pod_vec_pedantic::(vec![0x00, 0x01].le_to_native::()), Ok(vec![0x0100u16])); assert_eq!(guarded_transmute_pod_vec_pedantic::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()), Ok(vec![0x0100u16, 0x0200u16])); } #[test] fn too_much() { assert_eq!(guarded_transmute_pod_vec_pedantic::(vec![0x00, 0x01, 0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 3, reason: ErrorReason::InexactByteCount, }))); assert_eq!(guarded_transmute_pod_vec_pedantic::(vec![0x00, 0x01, 0x00, 0x02, 0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 5, reason: ErrorReason::InexactByteCount, }))); } safe-transmute-0.10.1/tests/guarded_transmute_pod_vec_permissive/mod.rs000064400000000000000000000021531337224757600247070ustar0000000000000000#![cfg(feature = "std")] use safe_transmute::guarded_transmute_pod_vec_permissive; use self::super::LeToNative; #[test] fn too_short() { assert_eq!(guarded_transmute_pod_vec_permissive::(vec![]), vec![]); assert_eq!(guarded_transmute_pod_vec_permissive::(vec![0x00]), vec![]); } #[test] fn just_enough() { assert_eq!(guarded_transmute_pod_vec_permissive::(vec![0x00, 0x01].le_to_native::()), vec![0x0100u16]); assert_eq!(guarded_transmute_pod_vec_permissive::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()), vec![0x0100u16, 0x0200u16]); } #[test] fn too_much() { assert_eq!(guarded_transmute_pod_vec_permissive::(vec![0x00, 0x01, 0x00].le_to_native::()), vec![0x0100u16]); assert_eq!(guarded_transmute_pod_vec_permissive::(vec![0x00, 0x01, 0x00, 0x02, 0x00].le_to_native::()), vec![0x0100u16, 0x0200u16]); assert_eq!(guarded_transmute_pod_vec_permissive::(vec![0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00].le_to_native::()), vec![0x0100u16, 0x0200u16, 0x0300u16]); } safe-transmute-0.10.1/tests/guarded_transmute_vec/mod.rs000064400000000000000000000027741337224757600216100ustar0000000000000000#![cfg(feature = "std")] use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_vec}; use self::super::LeToNative; #[test] fn too_short() { unsafe { assert_eq!(guarded_transmute_vec::(vec![]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(guarded_transmute_vec::(vec![0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } } #[test] fn just_enough() { unsafe { assert_eq!(guarded_transmute_vec::(vec![0x00, 0x01].le_to_native::()), Ok(vec![0x0100u16])); assert_eq!(guarded_transmute_vec::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()), Ok(vec![0x0100u16, 0x0200u16])); } } #[test] fn too_much() { unsafe { assert_eq!(guarded_transmute_vec::(vec![0x00, 0x01, 0x00].le_to_native::()), Ok(vec![0x0100u16])); assert_eq!(guarded_transmute_vec::(vec![0x00, 0x01, 0x00, 0x02, 0x00].le_to_native::()), Ok(vec![0x0100u16, 0x0200u16])); assert_eq!(guarded_transmute_vec::(vec![0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00].le_to_native::()), Ok(vec![0x0100u16, 0x0200u16, 0x0300u16])); } } safe-transmute-0.10.1/tests/guarded_transmute_vec_pedantic/mod.rs000064400000000000000000000033101337224757600234420ustar0000000000000000#![cfg(feature = "std")] use safe_transmute::{ErrorReason, GuardError, Error, guarded_transmute_vec_pedantic}; use self::super::LeToNative; #[test] fn too_short() { unsafe { assert_eq!(guarded_transmute_vec_pedantic::(vec![]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 0, reason: ErrorReason::NotEnoughBytes, }))); assert_eq!(guarded_transmute_vec_pedantic::(vec![0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 1, reason: ErrorReason::NotEnoughBytes, }))); } } #[test] fn just_enough() { unsafe { assert_eq!(guarded_transmute_vec_pedantic::(vec![0x00, 0x01].le_to_native::()), Ok(vec![0x0100u16])); assert_eq!(guarded_transmute_vec_pedantic::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()), Ok(vec![0x0100u16, 0x0200u16])); } } #[test] fn too_much() { unsafe { assert_eq!(guarded_transmute_vec_pedantic::(vec![0x00, 0x01, 0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 3, reason: ErrorReason::InexactByteCount, }))); assert_eq!(guarded_transmute_vec_pedantic::(vec![0x00, 0x01, 0x00, 0x02, 0x00]), Err(Error::Guard(GuardError { required: 16 / 8, actual: 5, reason: ErrorReason::InexactByteCount, }))); } } safe-transmute-0.10.1/tests/guarded_transmute_vec_permissive/mod.rs000064400000000000000000000022411337224757600240430ustar0000000000000000#![cfg(feature = "std")] use safe_transmute::guarded_transmute_vec_permissive; use self::super::LeToNative; #[test] fn too_short() { unsafe { assert_eq!(guarded_transmute_vec_permissive::(vec![]), vec![]); assert_eq!(guarded_transmute_vec_permissive::(vec![0x00]), vec![]); } } #[test] fn just_enough() { unsafe { assert_eq!(guarded_transmute_vec_permissive::(vec![0x00, 0x01].le_to_native::()), vec![0x0100u16]); assert_eq!(guarded_transmute_vec_permissive::(vec![0x00, 0x01, 0x00, 0x02].le_to_native::()), vec![0x0100u16, 0x0200u16]); } } #[test] fn too_much() { unsafe { assert_eq!(guarded_transmute_vec_permissive::(vec![0x00, 0x01, 0x00].le_to_native::()), vec![0x0100u16]); assert_eq!(guarded_transmute_vec_permissive::(vec![0x00, 0x01, 0x00, 0x02, 0x00].le_to_native::()), vec![0x0100u16, 0x0200u16]); assert_eq!(guarded_transmute_vec_permissive::(vec![0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00].le_to_native::()), vec![0x0100u16, 0x0200u16, 0x0300u16]); } } safe-transmute-0.10.1/tests/lib.rs000064400000000000000000000015601337224757600152150ustar0000000000000000#![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "std")] extern crate core; extern crate safe_transmute; mod util; mod guarded_transmute; mod guarded_transmute_many; mod guarded_transmute_pedantic; mod guarded_transmute_many_pedantic; mod guarded_transmute_many_permissive; mod guarded_transmute_vec; mod guarded_transmute_vec_pedantic; mod guarded_transmute_vec_permissive; mod guarded_transmute_pod; mod guarded_transmute_pod_many; mod guarded_transmute_pod_pedantic; mod guarded_transmute_pod_many_pedantic; mod guarded_transmute_pod_many_permissive; mod guarded_transmute_pod_vec; mod guarded_transmute_pod_vec_pedantic; mod guarded_transmute_pod_vec_permissive; mod guarded_transmute_bool_pedantic; mod guarded_transmute_bool_permissive; mod guarded_transmute_bool_vec_pedantic; mod guarded_transmute_bool_vec_permissive; include!("test_util/le_to_native.rs"); safe-transmute-0.10.1/tests/test_util/le_to_native.rs000064400000000000000000000044541337224757600211400ustar0000000000000000#[cfg(target_endian = "big")] use core::mem::size_of; /// 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 { for elem in self.chunks_mut(size_of::()) { elem.reverse(); } self } } #[cfg(feature = "std")] 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.10.1/tests/util/mod.rs000064400000000000000000000007511337224757600162040ustar0000000000000000use safe_transmute::util; use core::{f32, f64}; #[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 } safe-transmute-0.10.1/.cargo_vcs_info.json0000644000000001120000000000000141020ustar00{ "git": { "sha1": "26ec6b7573c4dfec37109188095674c16f709d73" } }