1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
//! 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::<u16, SingleManyGuard>(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::<u16, SingleManyGuard>(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)
}