#![allow(non_camel_case_types)]
use num_traits::{PrimInt, ToPrimitive, float::FloatCore};
#[cfg(feature = "audio")]
use audio_core::Sample;
#[derive(Debug, Clone, Copy)]
pub struct I16_LE([u8; 2]);
#[derive(Debug, Clone, Copy)]
pub struct I16_BE([u8; 2]);
#[derive(Debug, Clone, Copy)]
pub struct U16_LE([u8; 2]);
#[derive(Debug, Clone, Copy)]
pub struct U16_BE([u8; 2]);
#[derive(Debug, Clone, Copy)]
pub struct I24_LE([u8; 3]);
#[derive(Debug, Clone, Copy)]
pub struct I24_4LJ_LE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct I24_4RJ_LE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct I24_BE([u8; 3]);
#[derive(Debug, Clone, Copy)]
pub struct I24_4LJ_BE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct I24_4RJ_BE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct U24_LE([u8; 3]);
#[derive(Debug, Clone, Copy)]
pub struct U24_4LJ_LE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct U24_4RJ_LE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct U24_BE([u8; 3]);
#[derive(Debug, Clone, Copy)]
pub struct U24_4LJ_BE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct U24_4RJ_BE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct I32_LE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct I32_BE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct U32_LE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct U32_BE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct I64_LE([u8; 8]);
#[derive(Debug, Clone, Copy)]
pub struct I64_BE([u8; 8]);
#[derive(Debug, Clone, Copy)]
pub struct U64_LE([u8; 8]);
#[derive(Debug, Clone, Copy)]
pub struct U64_BE([u8; 8]);
#[derive(Debug, Clone, Copy)]
pub struct F32_LE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct F32_BE([u8; 4]);
#[derive(Debug, Clone, Copy)]
pub struct F64_LE([u8; 8]);
#[derive(Debug, Clone, Copy)]
pub struct F64_BE([u8; 8]);
fn to_clamped_int<T: FloatCore + ToPrimitive, U: PrimInt>(
value: T,
converted: Option<U>,
) -> ConversionResult<U> {
if let Some(val) = converted {
return ConversionResult {
clipped: false,
value: val,
};
}
if value.is_nan() {
return ConversionResult {
clipped: true,
value: U::zero(),
};
}
if value > T::zero() {
return ConversionResult {
clipped: true,
value: U::max_value(),
};
}
ConversionResult {
clipped: true,
value: U::min_value(),
}
}
pub struct ConversionResult<T> {
pub clipped: bool,
pub value: T,
}
pub trait RawSample
where
Self: Sized,
{
fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T;
fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self>;
}
pub trait BytesSample {
type NumericType: Copy;
const BYTES_PER_SAMPLE: usize;
fn from_slice(bytes: &[u8]) -> Self;
fn as_slice(&self) -> &[u8];
fn as_mut_slice(&mut self) -> &mut [u8];
fn to_number(&self) -> Self::NumericType;
fn from_number(value: Self::NumericType) -> Self;
}
macro_rules! rawsample_for_int {
($type:ident, $to:ident) => {
impl RawSample for $type {
fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
T::from(*self).unwrap() / (T::from($type::MAX).unwrap() + T::one())
}
fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
let scaled = value * (T::from($type::MAX).unwrap() + T::one());
let converted = scaled.$to();
to_clamped_int(scaled, converted)
}
}
};
}
rawsample_for_int!(i8, to_i8);
rawsample_for_int!(i16, to_i16);
rawsample_for_int!(i32, to_i32);
rawsample_for_int!(i64, to_i64);
macro_rules! rawsample_for_uint {
($type:ident, $to:ident) => {
impl RawSample for $type {
fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
let max_ampl = (T::from($type::MAX).unwrap() + T::one()) / T::from(2).unwrap();
(T::from(*self).unwrap() - max_ampl) / max_ampl
}
fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
let max_ampl = (T::from($type::MAX).unwrap() + T::one()) / T::from(2).unwrap();
let scaled = value * max_ampl + max_ampl;
let converted = scaled.$to();
to_clamped_int(scaled, converted)
}
}
};
}
rawsample_for_uint!(u8, to_u8);
rawsample_for_uint!(u16, to_u16);
rawsample_for_uint!(u32, to_u32);
rawsample_for_uint!(u64, to_u64);
macro_rules! rawsample_for_float {
($type:ident, $to:ident) => {
impl RawSample for $type {
fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
T::from(*self).unwrap_or(T::zero())
}
fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
ConversionResult {
clipped: false,
value: value.$to().unwrap_or(0.0),
}
}
}
};
}
rawsample_for_float!(f32, to_f32);
rawsample_for_float!(f64, to_f64);
impl BytesSample for I24_4RJ_LE {
type NumericType = i32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..4].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [0, self.0[0], self.0[1], self.0[2]];
i32::from_le_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_le_bytes();
Self([bytes[1], bytes[2], bytes[3], 0])
}
}
impl BytesSample for I24_4LJ_LE {
type NumericType = i32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..4].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [0, self.0[1], self.0[2], self.0[3]];
i32::from_le_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_le_bytes();
Self([0, bytes[1], bytes[2], bytes[3]])
}
}
impl BytesSample for I24_LE {
type NumericType = i32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..3].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [0, self.0[0], self.0[1], self.0[2]];
i32::from_le_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_le_bytes();
Self([bytes[1], bytes[2], bytes[3]])
}
}
impl BytesSample for I24_4RJ_BE {
type NumericType = i32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..4].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [self.0[1], self.0[2], self.0[3], 0];
i32::from_be_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_be_bytes();
Self([0, bytes[0], bytes[1], bytes[2]])
}
}
impl BytesSample for I24_4LJ_BE {
type NumericType = i32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..4].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [self.0[0], self.0[1], self.0[2], 0];
i32::from_be_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_be_bytes();
Self([bytes[0], bytes[1], bytes[2], 0])
}
}
impl BytesSample for I24_BE {
type NumericType = i32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..3].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [self.0[0], self.0[1], self.0[2], 0];
i32::from_be_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_be_bytes();
Self([bytes[0], bytes[1], bytes[2]])
}
}
impl BytesSample for U24_4RJ_LE {
type NumericType = u32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..4].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [0, self.0[0], self.0[1], self.0[2]];
u32::from_le_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_le_bytes();
Self([bytes[1], bytes[2], bytes[3], 0])
}
}
impl BytesSample for U24_4LJ_LE {
type NumericType = u32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..4].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [0, self.0[1], self.0[2], self.0[3]];
u32::from_le_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_le_bytes();
Self([0, bytes[1], bytes[2], bytes[3]])
}
}
impl BytesSample for U24_LE {
type NumericType = u32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..3].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [0, self.0[0], self.0[1], self.0[2]];
u32::from_le_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_le_bytes();
Self([bytes[1], bytes[2], bytes[3]])
}
}
impl BytesSample for U24_4RJ_BE {
type NumericType = u32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..4].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [self.0[1], self.0[2], self.0[3], 0];
u32::from_be_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_be_bytes();
Self([0, bytes[0], bytes[1], bytes[2]])
}
}
impl BytesSample for U24_4LJ_BE {
type NumericType = u32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..4].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [self.0[0], self.0[1], self.0[2], 0];
u32::from_be_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_be_bytes();
Self([bytes[0], bytes[1], bytes[2], 0])
}
}
impl BytesSample for U24_BE {
type NumericType = u32;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes[0..3].try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
let padded = [self.0[0], self.0[1], self.0[2], 0];
u32::from_be_bytes(padded)
}
fn from_number(value: Self::NumericType) -> Self {
let bytes = value.to_be_bytes();
Self([bytes[0], bytes[1], bytes[2]])
}
}
macro_rules! bytessample_for_newtype {
($type:ident, $newtype:ident, $from:ident, $to:ident) => {
impl BytesSample for $newtype {
type NumericType = $type;
const BYTES_PER_SAMPLE: usize = core::mem::size_of::<$type>();
fn from_slice(bytes: &[u8]) -> Self {
Self(bytes.try_into().unwrap())
}
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
fn to_number(&self) -> Self::NumericType {
$type::$from(self.0)
}
fn from_number(value: Self::NumericType) -> Self {
Self(value.$to())
}
}
};
}
bytessample_for_newtype!(i64, I64_LE, from_le_bytes, to_le_bytes);
bytessample_for_newtype!(u64, U64_LE, from_le_bytes, to_le_bytes);
bytessample_for_newtype!(i64, I64_BE, from_be_bytes, to_be_bytes);
bytessample_for_newtype!(u64, U64_BE, from_be_bytes, to_be_bytes);
bytessample_for_newtype!(i16, I16_LE, from_le_bytes, to_le_bytes);
bytessample_for_newtype!(u16, U16_LE, from_le_bytes, to_le_bytes);
bytessample_for_newtype!(i16, I16_BE, from_be_bytes, to_be_bytes);
bytessample_for_newtype!(u16, U16_BE, from_be_bytes, to_be_bytes);
bytessample_for_newtype!(i32, I32_LE, from_le_bytes, to_le_bytes);
bytessample_for_newtype!(u32, U32_LE, from_le_bytes, to_le_bytes);
bytessample_for_newtype!(i32, I32_BE, from_be_bytes, to_be_bytes);
bytessample_for_newtype!(u32, U32_BE, from_be_bytes, to_be_bytes);
bytessample_for_newtype!(f32, F32_LE, from_le_bytes, to_le_bytes);
bytessample_for_newtype!(f32, F32_BE, from_be_bytes, to_be_bytes);
bytessample_for_newtype!(f64, F64_LE, from_le_bytes, to_le_bytes);
bytessample_for_newtype!(f64, F64_BE, from_be_bytes, to_be_bytes);
impl<V> RawSample for V
where
V: BytesSample,
<V as BytesSample>::NumericType: RawSample,
{
fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
let value = self.to_number();
value.to_scaled_float()
}
fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
let value = <V as BytesSample>::NumericType::from_scaled_float(value);
ConversionResult {
clipped: value.clipped,
value: V::from_number(value.value),
}
}
}
#[cfg(feature = "audio")]
macro_rules! impl_sample_for_newtype {
($newtype:ident, $bytes:expr) => {
unsafe impl Sample for $newtype {
const ZERO: $newtype = $newtype([0; $bytes]);
}
};
}
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I16_LE, 2);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U16_LE, 2);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I16_BE, 2);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U16_BE, 2);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I24_LE, 3);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I24_4LJ_LE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I24_4RJ_LE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U24_LE, 3);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U24_4LJ_LE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U24_4RJ_LE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I24_BE, 3);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I24_4LJ_BE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I24_4RJ_BE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U24_BE, 3);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U24_4LJ_BE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U24_4RJ_BE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I32_LE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U32_LE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I32_BE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U32_BE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I64_LE, 8);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U64_LE, 8);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(I64_BE, 8);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(U64_BE, 8);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(F32_LE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(F32_BE, 4);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(F64_LE, 8);
#[cfg(feature = "audio")]
impl_sample_for_newtype!(F64_BE, 8);
#[cfg(test)]
mod tests {
use super::*;
macro_rules! assert_conversion_eq {
($result:expr, $value:expr, $clipped:expr, $desc:expr) => {
assert_eq!($result.value, $value, $desc);
assert_eq!($result.clipped, $clipped, $desc);
};
}
macro_rules! test_to_signed_int {
($fname:ident, $float:ty, $int:ident, $bits:expr) => {
#[test]
fn $fname() {
let val: $float = 0.25;
assert_conversion_eq!(
$int::from_scaled_float(val),
1 << ($bits - 3),
false,
"check +0.25"
);
let val: $float = -0.25;
assert_conversion_eq!(
$int::from_scaled_float(val),
-1 << ($bits - 3),
false,
"check -0.25"
);
let val: $float = 1.1;
assert_conversion_eq!(
$int::from_scaled_float(val),
$int::MAX,
true,
"clipped positive"
);
let val: $float = -1.1;
assert_conversion_eq!(
$int::from_scaled_float(val),
$int::MIN,
true,
"clipped negative"
);
}
};
}
macro_rules! test_to_unsigned_int {
($fname:ident, $float:ty, $int:ident, $bits:expr) => {
#[test]
fn $fname() {
let val: $float = -0.5;
assert_conversion_eq!(
$int::from_scaled_float(val),
1 << ($bits - 2),
false,
"check -0.5"
);
let val: $float = 0.5;
assert_conversion_eq!(
$int::from_scaled_float(val),
$int::MAX - (1 << ($bits - 2)) + 1,
false,
"check 0.5"
);
let val: $float = 1.1;
assert_conversion_eq!(
$int::from_scaled_float(val),
$int::MAX,
true,
"clipped positive"
);
let val: $float = -1.1;
assert_conversion_eq!(
$int::from_scaled_float(val),
$int::MIN,
true,
"clipped negative"
);
}
};
}
test_to_signed_int!(convert_f32_to_i8, f32, i8, 8);
test_to_signed_int!(convert_642_to_i8, f64, i8, 8);
test_to_signed_int!(convert_f32_to_i16, f32, i16, 16);
test_to_signed_int!(convert_f64_to_i16, f64, i16, 16);
test_to_signed_int!(convert_f32_to_i32, f32, i32, 32);
test_to_signed_int!(convert_f64_to_i32, f64, i32, 32);
test_to_signed_int!(convert_f32_to_i64, f32, i64, 64);
test_to_signed_int!(convert_f64_to_i64, f64, i64, 64);
test_to_unsigned_int!(convert_f32_to_u8, f32, u8, 8);
test_to_unsigned_int!(convert_f64_to_u8, f64, u8, 8);
test_to_unsigned_int!(convert_f32_to_u16, f32, u16, 16);
test_to_unsigned_int!(convert_f64_to_u16, f64, u16, 16);
test_to_unsigned_int!(convert_f32_to_u32, f32, u32, 32);
test_to_unsigned_int!(convert_f64_to_u32, f64, u32, 32);
test_to_unsigned_int!(convert_f32_to_u64, f32, u64, 64);
test_to_unsigned_int!(convert_f64_to_u64, f64, u64, 64);
macro_rules! test_from_signed_int {
($fname:ident, $float:ty, $int:ident, $bits:expr) => {
#[test]
fn $fname() {
let val: $int = -1 << ($bits - 2);
assert_eq!(val.to_scaled_float::<$float>(), -0.5, "check -0.5");
let val: $int = 1 << ($bits - 2);
assert_eq!(val.to_scaled_float::<$float>(), 0.5, "check 0.5");
let val: $int = $int::MIN;
assert_eq!(val.to_scaled_float::<$float>(), -1.0, "negative limit");
}
};
}
macro_rules! test_from_unsigned_int {
($fname:ident, $float:ty, $int:ident, $bits:expr) => {
#[test]
fn $fname() {
let val: $int = 1 << ($bits - 2);
assert_eq!(val.to_scaled_float::<$float>(), -0.5, "check -0.5");
let val: $int = $int::MAX - (1 << ($bits - 2)) + 1;
assert_eq!(val.to_scaled_float::<$float>(), 0.5, "check 0.5");
let val: $int = 0;
assert_eq!(val.to_scaled_float::<$float>(), -1.0, "negative limit");
}
};
}
test_from_signed_int!(convert_f32_from_i8, f32, i8, 8);
test_from_signed_int!(convert_f64_from_i8, f64, i8, 8);
test_from_signed_int!(convert_f32_from_i16, f32, i16, 16);
test_from_signed_int!(convert_f64_from_i16, f64, i16, 16);
test_from_signed_int!(convert_f32_from_i32, f32, i32, 32);
test_from_signed_int!(convert_f64_from_i32, f64, i32, 32);
test_from_signed_int!(convert_f32_from_i64, f32, i64, 64);
test_from_signed_int!(convert_f64_from_i64, f64, i64, 64);
test_from_unsigned_int!(convert_f32_from_u8, f32, u8, 8);
test_from_unsigned_int!(convert_f64_from_u8, f64, u8, 8);
test_from_unsigned_int!(convert_f32_from_u16, f32, u16, 16);
test_from_unsigned_int!(convert_f64_from_u16, f64, u16, 16);
test_from_unsigned_int!(convert_f32_from_u32, f32, u32, 32);
test_from_unsigned_int!(convert_f64_from_u32, f64, u32, 32);
test_from_unsigned_int!(convert_f32_from_u64, f32, u64, 64);
test_from_unsigned_int!(convert_f64_from_u64, f64, u64, 64);
#[test]
fn test_to_clamped_int() {
let converted = to_clamped_int::<f32, i32>(12345.0, Some(12345));
assert_conversion_eq!(converted, 12345, false, "in range f32 i32");
let converted = to_clamped_int::<f32, i32>(1.0e10, None);
assert_conversion_eq!(converted, i32::MAX, true, "above range f32 i32");
let converted = to_clamped_int::<f32, i32>(-1.0e10, None);
assert_conversion_eq!(converted, i32::MIN, true, "below range f32 i32");
let converted = to_clamped_int::<f64, i32>(12345.0, Some(12345));
assert_conversion_eq!(converted, 12345, false, "in range f64 i32");
let converted = to_clamped_int::<f64, i32>(1.0e10, None);
assert_conversion_eq!(converted, i32::MAX, true, "above range f64 i32");
let converted = to_clamped_int::<f64, i32>(-1.0e10, None);
assert_conversion_eq!(converted, i32::MIN, true, "below range f64 i32");
}
#[test]
fn test_to_clamped_uint() {
let converted = to_clamped_int::<f32, u32>(12345.0, Some(12345));
assert_conversion_eq!(converted, 12345, false, "in range f32 u32");
let converted = to_clamped_int::<f32, u32>(1.0e10, None);
assert_conversion_eq!(converted, u32::MAX, true, "above range f32 u32");
let converted = to_clamped_int::<f32, u32>(-1.0, None);
assert_conversion_eq!(converted, u32::MIN, true, "below range f32 u32");
let converted = to_clamped_int::<f64, u32>(12345.0, Some(12345));
assert_conversion_eq!(converted, 12345, false, "in range f64 u32");
let converted = to_clamped_int::<f64, u32>(1.0e10, None);
assert_conversion_eq!(converted, u32::MAX, true, "above range f64 u32");
let converted = to_clamped_int::<f64, u32>(-1.0, None);
assert_conversion_eq!(converted, u32::MIN, true, "below range f64 u32");
}
macro_rules! test_simple_int_bytes {
($fname:ident, $number:ty, $wrapper:ident, $to_bytes_fn:ident) => {
#[test]
#[allow(non_snake_case)]
fn $fname() {
let number: $number = <$number>::MAX / 5 * 4;
let wrapped = $wrapper(number.$to_bytes_fn());
assert_eq!(number, wrapped.to_number());
}
};
}
macro_rules! test_float_bytes {
($fname:ident, $number:ty, $wrapper:ident, $to_bytes_fn:ident) => {
#[test]
#[allow(non_snake_case)]
fn $fname() {
let number: $number = 12345.0;
let wrapped = $wrapper(number.$to_bytes_fn());
assert_eq!(number, wrapped.to_number());
}
};
}
test_simple_int_bytes!(convert_i16_from_I16_LE, i16, I16_LE, to_le_bytes);
test_simple_int_bytes!(convert_i16_from_I16_BE, i16, I16_BE, to_be_bytes);
test_simple_int_bytes!(convert_i32_from_I32_LE, i32, I32_LE, to_le_bytes);
test_simple_int_bytes!(convert_i32_from_I32_BE, i32, I32_BE, to_be_bytes);
test_simple_int_bytes!(convert_i64_from_I64_LE, i64, I64_LE, to_le_bytes);
test_simple_int_bytes!(convert_i64_from_I64_BE, i64, I64_BE, to_be_bytes);
test_simple_int_bytes!(convert_u16_from_U16_LE, u16, U16_LE, to_le_bytes);
test_simple_int_bytes!(convert_u16_from_U16_BE, u16, U16_BE, to_be_bytes);
test_simple_int_bytes!(convert_u32_from_U32_LE, u32, U32_LE, to_le_bytes);
test_simple_int_bytes!(convert_u32_from_U32_BE, u32, U32_BE, to_be_bytes);
test_simple_int_bytes!(convert_u64_from_U64_LE, u64, U64_LE, to_le_bytes);
test_simple_int_bytes!(convert_u64_from_U64_BE, u64, U64_BE, to_be_bytes);
test_float_bytes!(convert_f32_fom_F32_LE, f32, F32_LE, to_le_bytes);
test_float_bytes!(convert_f32_fom_F32_BE, f32, F32_BE, to_be_bytes);
test_float_bytes!(convert_f64_fom_F64_LE, f64, F64_LE, to_le_bytes);
test_float_bytes!(convert_f64_fom_F64_BE, f64, F64_BE, to_be_bytes);
#[test]
#[allow(non_snake_case)]
fn test_I24_LE() {
let number = i32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_le_bytes();
let bytes = [allbytes[1], allbytes[2], allbytes[3]];
let wrapped = I24_LE(bytes);
assert_eq!(number, wrapped.to_number());
}
#[test]
#[allow(non_snake_case)]
fn test_I24_BE() {
let number = i32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_be_bytes();
let bytes = [allbytes[0], allbytes[1], allbytes[2]];
let wrapped = I24_BE(bytes);
assert_eq!(number, wrapped.to_number());
}
#[test]
#[allow(non_snake_case)]
fn test_I24_4RJ_LE() {
let number = i32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_le_bytes();
let bytes = [allbytes[1], allbytes[2], allbytes[3], 0];
let wrapped = I24_4RJ_LE(bytes);
assert_eq!(number, wrapped.to_number());
}
#[test]
#[allow(non_snake_case)]
fn test_I24_4RJ_BE() {
let number = i32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_be_bytes();
let bytes = [0, allbytes[0], allbytes[1], allbytes[2]];
let wrapped = I24_4RJ_BE(bytes);
assert_eq!(number, wrapped.to_number());
}
#[test]
#[allow(non_snake_case)]
fn test_I24_4LJ_LE() {
let number = i32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_le_bytes();
let bytes = [0, allbytes[1], allbytes[2], allbytes[3]];
let wrapped = I24_4LJ_LE(bytes);
assert_eq!(number, wrapped.to_number());
}
#[test]
#[allow(non_snake_case)]
fn test_I24_4LJ_BE() {
let number = i32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_be_bytes();
let bytes = [allbytes[0], allbytes[1], allbytes[2], 0];
let wrapped = I24_4LJ_BE(bytes);
assert_eq!(number, wrapped.to_number());
}
#[test]
#[allow(non_snake_case)]
fn test_U24_LE() {
let number = u32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_le_bytes();
let bytes = [allbytes[1], allbytes[2], allbytes[3]];
let wrapped = U24_LE(bytes);
assert_eq!(number, wrapped.to_number());
}
#[test]
#[allow(non_snake_case)]
fn test_U24_BE() {
let number = u32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_be_bytes();
let bytes = [allbytes[0], allbytes[1], allbytes[2]];
let wrapped = U24_BE(bytes);
assert_eq!(number, wrapped.to_number());
}
#[test]
#[allow(non_snake_case)]
fn test_U24_4RJ_LE() {
let number = u32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_le_bytes();
let bytes = [allbytes[1], allbytes[2], allbytes[3], 0];
let wrapped = U24_4RJ_LE(bytes);
assert_eq!(number, wrapped.to_number());
}
#[test]
#[allow(non_snake_case)]
fn test_U24_4RJ_BE() {
let number = u32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_be_bytes();
let bytes = [0, allbytes[0], allbytes[1], allbytes[2]];
let wrapped = U24_4RJ_BE(bytes);
assert_eq!(number, wrapped.to_number());
}
#[test]
#[allow(non_snake_case)]
fn test_U24_4LJ_LE() {
let number = u32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_le_bytes();
let bytes = [0, allbytes[1], allbytes[2], allbytes[3]];
let wrapped = U24_4LJ_LE(bytes);
assert_eq!(number, wrapped.to_number());
}
#[test]
#[allow(non_snake_case)]
fn test_U24_4LJ_BE() {
let number = u32::MAX / 5 * 4;
let number = number >> 8;
let number = number << 8;
let allbytes = number.to_be_bytes();
let bytes = [allbytes[0], allbytes[1], allbytes[2], 0];
let wrapped = U24_4LJ_BE(bytes);
assert_eq!(number, wrapped.to_number());
}
}