audioadapter_sample/
sample.rs

1use num_traits::{Float, PrimInt};
2
3#[cfg(feature = "audio")]
4use audio_core::Sample;
5
6/// 24 bit signed integer, little endian. 24 bits stored packed as as 3 bytes or padded as 4 bytes.
7#[derive(Debug, Clone, Copy)]
8pub struct I24LE<const N: usize>([u8; N]);
9
10/// 24 bit signed integer, big endian. 24 bits stored packed as as 3 bytes or padded as 4 bytes.
11#[derive(Debug, Clone, Copy)]
12pub struct I24BE<const N: usize>([u8; N]);
13
14/// 24 bit unsigned integer, little endian. 24 bits stored packed as as 3 bytes or padded as 4 bytes.
15#[derive(Debug, Clone, Copy)]
16pub struct U24LE<const N: usize>([u8; N]);
17
18/// 24 bit unsigned integer, big endian. 24 bits stored packed as as 3 bytes or padded as 4 bytes.
19#[derive(Debug, Clone, Copy)]
20pub struct U24BE<const N: usize>([u8; N]);
21
22/// 32 bit signed integer, little endian. Stored as 4 bytes.
23#[derive(Debug, Clone, Copy)]
24pub struct I32LE([u8; 4]);
25
26/// 32 bit signed integer, big endian. Stored as 4 bytes.
27#[derive(Debug, Clone, Copy)]
28pub struct I32BE([u8; 4]);
29
30/// 64 bit signed integer, little endian. Stored as 8 bytes.
31#[derive(Debug, Clone, Copy)]
32pub struct I64LE([u8; 8]);
33
34/// 64 bit signed integer, big endian. Stored as 8 bytes.
35#[derive(Debug, Clone, Copy)]
36pub struct I64BE([u8; 8]);
37
38/// 16 bit signed integer, little endian. Stored as 2 bytes.
39#[derive(Debug, Clone, Copy)]
40pub struct I16LE([u8; 2]);
41
42/// 16 bit signed integer, big endian. Stored as 2 bytes.
43#[derive(Debug, Clone, Copy)]
44pub struct I16BE([u8; 2]);
45
46/// 32 bit unsigned integer, little endian. Stored as 4 bytes.
47#[derive(Debug, Clone, Copy)]
48pub struct U32LE([u8; 4]);
49
50/// 32 bit unsigned integer, big endian. Stored as 4 bytes.
51#[derive(Debug, Clone, Copy)]
52pub struct U32BE([u8; 4]);
53
54/// 64 bit unsigned integer, little endian. Stored as 8 bytes.
55#[derive(Debug, Clone, Copy)]
56pub struct U64LE([u8; 8]);
57
58/// 64 bit unsigned integer, big endian. Stored as 8 bytes.
59#[derive(Debug, Clone, Copy)]
60pub struct U64BE([u8; 8]);
61
62/// 16 bit unsigned integer, little endian. Stored as 2 bytes.
63#[derive(Debug, Clone, Copy)]
64pub struct U16LE([u8; 2]);
65
66/// 16 bit unsigned integer, big endian. Stored as 2 bytes.
67#[derive(Debug, Clone, Copy)]
68pub struct U16BE([u8; 2]);
69
70/// 32 bit floating point, little endian. Stored as 4 bytes.
71#[derive(Debug, Clone, Copy)]
72pub struct F32LE([u8; 4]);
73
74/// 32 bit floating point, big endian. Stored as 4 bytes.
75#[derive(Debug, Clone, Copy)]
76pub struct F32BE([u8; 4]);
77
78/// 64 bit floating point, little endian. Stored as 8 bytes.
79#[derive(Debug, Clone, Copy)]
80pub struct F64LE([u8; 8]);
81
82/// 64 bit floating point, big endian. Stored as 8 bytes.
83#[derive(Debug, Clone, Copy)]
84pub struct F64BE([u8; 8]);
85
86/// Convert a float to an integer, clamp at the min and max limits of the integer.
87fn to_clamped_int<T: Float, U: PrimInt>(value: T, converted: Option<U>) -> ConversionResult<U> {
88    if let Some(val) = converted {
89        return ConversionResult {
90            clipped: false,
91            value: val,
92        };
93    }
94    if value.is_nan() {
95        return ConversionResult {
96            clipped: true,
97            value: U::zero(),
98        };
99    }
100    if value > T::zero() {
101        return ConversionResult {
102            clipped: true,
103            value: U::max_value(),
104        };
105    }
106    ConversionResult {
107        clipped: true,
108        value: U::min_value(),
109    }
110}
111
112/// A conversion result, containing the resulting value as `value`
113/// and a boolean `clipped` indicating if the value was clipped during conversion.
114pub struct ConversionResult<T> {
115    pub clipped: bool,
116    pub value: T,
117}
118
119/// A trait for converting a given sample type to and from floating point values.
120/// The floating point values use the range -1.0 to +1.0.
121/// When converting to/from signed integers, the range does not include +1.0.
122/// For example, an 8-bit signed integer supports the range -128 to +127.
123/// When these values are converted to float, 0 becomes 0.0,
124/// -128 becomes -1.0, and 127 becomes 127/128 ≈ 0.992.
125/// Unsigned integers are also converted to the same -1.0 to +1.0 range.
126/// For an 8-but unsigned integer, 128 is the center point and becomes 0.0.
127/// The value 0 becomes -1.0, and 255 becomes 127/128 ≈ 0.992.
128pub trait RawSample
129where
130    Self: Sized,
131{
132    /// Convert the sample value to a float in the range -1.0 .. +1.0.
133    fn to_scaled_float<T: Float>(&self) -> T;
134
135    /// Convert a float in the range -1.0 .. +1.0 to a sample value.
136    /// Values outside the allowed range are clipped to the nearest limit.
137    fn from_scaled_float<T: Float>(value: T) -> ConversionResult<Self>;
138}
139
140/// A trait for converting samples stored as raw bytes into a numerical type.
141/// Each implementation defines the associated type `NumericType`,
142/// which is the nearest matching numeric type for the original format.
143/// If a direct match exists, this is used.
144/// For example signed 16 bit integer samples use [i16].
145/// For formats that don't have a direct match,
146/// the next larger numeric type is used.
147/// For example for 24 bit signed integers,
148/// this means [i32].
149/// The values are scaled to use the full range of the `NumericType`
150/// associated type.
151pub trait BytesSample {
152    /// The closest matching numeric type.
153    type NumericType: Copy;
154
155    /// The number of bytes making up each sample value.
156    const BYTES_PER_SAMPLE: usize;
157
158    /// Create a new ByteSample from a slice of raw bytes.
159    /// The slice length must be at least the number of bytes
160    /// for a sample value.
161    fn from_slice(bytes: &[u8]) -> Self;
162
163    /// Return the raw bytes as a slice.
164    fn as_slice(&self) -> &[u8];
165
166    /// Return the raw bytes as a mutable slice.
167    fn as_mut_slice(&mut self) -> &mut [u8];
168
169    /// Convert the raw bytes to a numerical value.
170    fn to_number(&self) -> Self::NumericType;
171
172    /// Convert a numerical value to raw bytes.
173    fn from_number(value: Self::NumericType) -> Self;
174}
175
176macro_rules! rawsample_for_int {
177    ($type:ident, $to:ident) => {
178        impl RawSample for $type {
179            fn to_scaled_float<T: Float>(&self) -> T {
180                T::from(*self).unwrap() / (T::from($type::MAX).unwrap() + T::one())
181            }
182
183            fn from_scaled_float<T: Float>(value: T) -> ConversionResult<Self> {
184                let scaled = value * (T::from($type::MAX).unwrap() + T::one());
185                let converted = scaled.$to();
186                to_clamped_int(scaled, converted)
187            }
188        }
189    };
190}
191
192rawsample_for_int!(i8, to_i8);
193rawsample_for_int!(i16, to_i16);
194rawsample_for_int!(i32, to_i32);
195rawsample_for_int!(i64, to_i64);
196
197macro_rules! rawsample_for_uint {
198    ($type:ident, $to:ident) => {
199        impl RawSample for $type {
200            fn to_scaled_float<T: Float>(&self) -> T {
201                let max_ampl = (T::from($type::MAX).unwrap() + T::one()) / T::from(2).unwrap();
202                (T::from(*self).unwrap() - max_ampl) / max_ampl
203            }
204
205            fn from_scaled_float<T: Float>(value: T) -> ConversionResult<Self> {
206                let max_ampl = (T::from($type::MAX).unwrap() + T::one()) / T::from(2).unwrap();
207                let scaled = value * max_ampl + max_ampl;
208                let converted = scaled.$to();
209                to_clamped_int(scaled, converted)
210            }
211        }
212    };
213}
214
215rawsample_for_uint!(u8, to_u8);
216rawsample_for_uint!(u16, to_u16);
217rawsample_for_uint!(u32, to_u32);
218rawsample_for_uint!(u64, to_u64);
219
220macro_rules! rawsample_for_float {
221    ($type:ident, $to:ident) => {
222        impl RawSample for $type {
223            fn to_scaled_float<T: Float>(&self) -> T {
224                T::from(*self).unwrap_or(T::zero())
225            }
226
227            fn from_scaled_float<T: Float>(value: T) -> ConversionResult<Self> {
228                // TODO clip here
229                ConversionResult {
230                    clipped: false,
231                    value: value.$to().unwrap_or(0.0),
232                }
233            }
234        }
235    };
236}
237
238rawsample_for_float!(f32, to_f32);
239rawsample_for_float!(f64, to_f64);
240
241// 24 bit formats, needs more work than others
242// because they don't map directly to a normal numerical type,
243
244/// 24 bit signed integer, little endian, stored as 4 bytes. The data is in the lower 3 bytes and the most significant byte is padding.
245impl BytesSample for I24LE<4> {
246    type NumericType = i32;
247    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
248
249    fn from_slice(bytes: &[u8]) -> Self {
250        Self(bytes[0..4].try_into().unwrap())
251    }
252
253    fn as_slice(&self) -> &[u8] {
254        &self.0
255    }
256
257    fn as_mut_slice(&mut self) -> &mut [u8] {
258        &mut self.0
259    }
260
261    fn to_number(&self) -> Self::NumericType {
262        let padded = [0, self.0[0], self.0[1], self.0[2]];
263        i32::from_le_bytes(padded)
264    }
265
266    fn from_number(value: Self::NumericType) -> Self {
267        let bytes = value.to_le_bytes();
268        Self([bytes[1], bytes[2], bytes[3], 0])
269    }
270}
271
272/// 24 bit signed integer, little endian, stored as 3 bytes without padding.
273impl BytesSample for I24LE<3> {
274    type NumericType = i32;
275    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
276
277    fn from_slice(bytes: &[u8]) -> Self {
278        Self(bytes[0..3].try_into().unwrap())
279    }
280
281    fn as_slice(&self) -> &[u8] {
282        &self.0
283    }
284
285    fn as_mut_slice(&mut self) -> &mut [u8] {
286        &mut self.0
287    }
288
289    fn to_number(&self) -> Self::NumericType {
290        let padded = [0, self.0[0], self.0[1], self.0[2]];
291        i32::from_le_bytes(padded)
292    }
293
294    fn from_number(value: Self::NumericType) -> Self {
295        let bytes = value.to_le_bytes();
296        Self([bytes[1], bytes[2], bytes[3]])
297    }
298}
299
300/// 24 bit signed integer, big endian, stored as 4 bytes. The data is in the lower 3 bytes and the most significant byte is padding.
301impl BytesSample for I24BE<4> {
302    type NumericType = i32;
303    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
304
305    fn from_slice(bytes: &[u8]) -> Self {
306        Self(bytes[0..4].try_into().unwrap())
307    }
308
309    fn as_slice(&self) -> &[u8] {
310        &self.0
311    }
312
313    fn as_mut_slice(&mut self) -> &mut [u8] {
314        &mut self.0
315    }
316
317    fn to_number(&self) -> Self::NumericType {
318        let padded = [self.0[1], self.0[2], self.0[3], 0];
319        i32::from_be_bytes(padded)
320    }
321
322    fn from_number(value: Self::NumericType) -> Self {
323        let bytes = value.to_be_bytes();
324        Self([0, bytes[0], bytes[1], bytes[2]])
325    }
326}
327
328/// 24 bit signed integer, big endian, stored as 3 bytes without padding.
329impl BytesSample for I24BE<3> {
330    type NumericType = i32;
331    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
332
333    fn from_slice(bytes: &[u8]) -> Self {
334        Self(bytes[0..3].try_into().unwrap())
335    }
336
337    fn as_slice(&self) -> &[u8] {
338        &self.0
339    }
340
341    fn as_mut_slice(&mut self) -> &mut [u8] {
342        &mut self.0
343    }
344
345    fn to_number(&self) -> Self::NumericType {
346        let padded = [self.0[0], self.0[1], self.0[2], 0];
347        i32::from_be_bytes(padded)
348    }
349
350    fn from_number(value: Self::NumericType) -> Self {
351        let bytes = value.to_be_bytes();
352        Self([bytes[0], bytes[1], bytes[2]])
353    }
354}
355
356/// 24 bit unsigned integer, little endian, stored as 4 bytes. The data is in the lower 3 bytes and the most significant byte is padding.
357impl BytesSample for U24LE<4> {
358    type NumericType = u32;
359    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
360
361    fn from_slice(bytes: &[u8]) -> Self {
362        Self(bytes[0..4].try_into().unwrap())
363    }
364
365    fn as_slice(&self) -> &[u8] {
366        &self.0
367    }
368
369    fn as_mut_slice(&mut self) -> &mut [u8] {
370        &mut self.0
371    }
372
373    fn to_number(&self) -> Self::NumericType {
374        let padded = [0, self.0[0], self.0[1], self.0[2]];
375        u32::from_le_bytes(padded)
376    }
377
378    fn from_number(value: Self::NumericType) -> Self {
379        let bytes = value.to_le_bytes();
380        Self([bytes[1], bytes[2], bytes[3], 0])
381    }
382}
383
384/// 24 bit unsigned integer, little endian, stored as 3 bytes without padding.
385impl BytesSample for U24LE<3> {
386    type NumericType = u32;
387    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
388
389    fn from_slice(bytes: &[u8]) -> Self {
390        Self(bytes[0..3].try_into().unwrap())
391    }
392
393    fn as_slice(&self) -> &[u8] {
394        &self.0
395    }
396
397    fn as_mut_slice(&mut self) -> &mut [u8] {
398        &mut self.0
399    }
400
401    fn to_number(&self) -> Self::NumericType {
402        let padded = [0, self.0[0], self.0[1], self.0[2]];
403        u32::from_le_bytes(padded)
404    }
405
406    fn from_number(value: Self::NumericType) -> Self {
407        let bytes = value.to_le_bytes();
408        Self([bytes[1], bytes[2], bytes[3]])
409    }
410}
411
412/// 24 bit unsigned integer, big endian, stored as 4 bytes. The data is in the lower 3 bytes and the most significant byte is padding.
413impl BytesSample for U24BE<4> {
414    type NumericType = u32;
415    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
416
417    fn from_slice(bytes: &[u8]) -> Self {
418        Self(bytes[0..4].try_into().unwrap())
419    }
420
421    fn as_slice(&self) -> &[u8] {
422        &self.0
423    }
424
425    fn as_mut_slice(&mut self) -> &mut [u8] {
426        &mut self.0
427    }
428
429    fn to_number(&self) -> Self::NumericType {
430        let padded = [self.0[1], self.0[2], self.0[3], 0];
431        u32::from_be_bytes(padded)
432    }
433
434    fn from_number(value: Self::NumericType) -> Self {
435        let bytes = value.to_be_bytes();
436        Self([0, bytes[0], bytes[1], bytes[2]])
437    }
438}
439
440/// 24 bit unsigned integer, big endian, stored as 3 bytes without padding.
441impl BytesSample for U24BE<3> {
442    type NumericType = u32;
443    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
444
445    fn from_slice(bytes: &[u8]) -> Self {
446        Self(bytes[0..3].try_into().unwrap())
447    }
448
449    fn as_slice(&self) -> &[u8] {
450        &self.0
451    }
452
453    fn as_mut_slice(&mut self) -> &mut [u8] {
454        &mut self.0
455    }
456
457    fn to_number(&self) -> Self::NumericType {
458        let padded = [self.0[0], self.0[1], self.0[2], 0];
459        u32::from_be_bytes(padded)
460    }
461
462    fn from_number(value: Self::NumericType) -> Self {
463        let bytes = value.to_be_bytes();
464        Self([bytes[0], bytes[1], bytes[2]])
465    }
466}
467
468macro_rules! bytessample_for_newtype {
469    ($type:ident, $newtype:ident, $from:ident, $to:ident) => {
470        impl BytesSample for $newtype {
471            type NumericType = $type;
472            const BYTES_PER_SAMPLE: usize = core::mem::size_of::<$type>();
473
474            fn from_slice(bytes: &[u8]) -> Self {
475                Self(bytes.try_into().unwrap())
476            }
477
478            fn as_slice(&self) -> &[u8] {
479                &self.0
480            }
481
482            fn as_mut_slice(&mut self) -> &mut [u8] {
483                &mut self.0
484            }
485
486            fn to_number(&self) -> Self::NumericType {
487                $type::$from(self.0)
488            }
489
490            fn from_number(value: Self::NumericType) -> Self {
491                Self(value.$to())
492            }
493        }
494    };
495}
496
497bytessample_for_newtype!(i64, I64LE, from_le_bytes, to_le_bytes);
498bytessample_for_newtype!(u64, U64LE, from_le_bytes, to_le_bytes);
499bytessample_for_newtype!(i64, I64BE, from_be_bytes, to_be_bytes);
500bytessample_for_newtype!(u64, U64BE, from_be_bytes, to_be_bytes);
501
502bytessample_for_newtype!(i16, I16LE, from_le_bytes, to_le_bytes);
503bytessample_for_newtype!(u16, U16LE, from_le_bytes, to_le_bytes);
504bytessample_for_newtype!(i16, I16BE, from_be_bytes, to_be_bytes);
505bytessample_for_newtype!(u16, U16BE, from_be_bytes, to_be_bytes);
506
507bytessample_for_newtype!(i32, I32LE, from_le_bytes, to_le_bytes);
508bytessample_for_newtype!(u32, U32LE, from_le_bytes, to_le_bytes);
509bytessample_for_newtype!(i32, I32BE, from_be_bytes, to_be_bytes);
510bytessample_for_newtype!(u32, U32BE, from_be_bytes, to_be_bytes);
511
512bytessample_for_newtype!(f32, F32LE, from_le_bytes, to_le_bytes);
513bytessample_for_newtype!(f32, F32BE, from_be_bytes, to_be_bytes);
514bytessample_for_newtype!(f64, F64LE, from_le_bytes, to_le_bytes);
515bytessample_for_newtype!(f64, F64BE, from_be_bytes, to_be_bytes);
516
517impl<V> RawSample for V
518where
519    V: BytesSample,
520    <V as BytesSample>::NumericType: RawSample,
521{
522    fn to_scaled_float<T: Float>(&self) -> T {
523        let value = self.to_number();
524        value.to_scaled_float()
525    }
526
527    fn from_scaled_float<T: Float>(value: T) -> ConversionResult<Self> {
528        let value = <V as BytesSample>::NumericType::from_scaled_float(value);
529        ConversionResult {
530            clipped: value.clipped,
531            value: V::from_number(value.value),
532        }
533    }
534}
535
536// Implement Sample for the audioadapter types
537#[cfg(feature = "audio")]
538macro_rules! impl_sample_for_newtype {
539    ($newtype:ident, $bytes:expr) => {
540        unsafe impl Sample for $newtype {
541            const ZERO: $newtype = $newtype([0; $bytes]);
542        }
543    };
544}
545
546#[cfg(feature = "audio")]
547impl_sample_for_newtype!(I64LE, 8);
548#[cfg(feature = "audio")]
549impl_sample_for_newtype!(U64LE, 8);
550#[cfg(feature = "audio")]
551impl_sample_for_newtype!(I64BE, 8);
552#[cfg(feature = "audio")]
553impl_sample_for_newtype!(U64BE, 8);
554#[cfg(feature = "audio")]
555impl_sample_for_newtype!(I16LE, 2);
556#[cfg(feature = "audio")]
557impl_sample_for_newtype!(U16LE, 2);
558#[cfg(feature = "audio")]
559impl_sample_for_newtype!(I16BE, 2);
560#[cfg(feature = "audio")]
561impl_sample_for_newtype!(U16BE, 2);
562#[cfg(feature = "audio")]
563impl_sample_for_newtype!(I32LE, 4);
564#[cfg(feature = "audio")]
565impl_sample_for_newtype!(U32LE, 4);
566#[cfg(feature = "audio")]
567impl_sample_for_newtype!(I32BE, 4);
568#[cfg(feature = "audio")]
569impl_sample_for_newtype!(U32BE, 4);
570#[cfg(feature = "audio")]
571impl_sample_for_newtype!(F32LE, 4);
572#[cfg(feature = "audio")]
573impl_sample_for_newtype!(F32BE, 4);
574#[cfg(feature = "audio")]
575impl_sample_for_newtype!(F64LE, 8);
576#[cfg(feature = "audio")]
577impl_sample_for_newtype!(F64BE, 8);
578
579#[cfg(feature = "audio")]
580macro_rules! impl_sample_for_generic_newtype {
581    ($newtype:ident, $bytes:expr) => {
582        unsafe impl Sample for $newtype<$bytes> {
583            const ZERO: $newtype<$bytes> = $newtype([0; $bytes]);
584        }
585    };
586}
587#[cfg(feature = "audio")]
588impl_sample_for_generic_newtype!(I24BE, 3);
589#[cfg(feature = "audio")]
590impl_sample_for_generic_newtype!(I24LE, 3);
591#[cfg(feature = "audio")]
592impl_sample_for_generic_newtype!(U24BE, 3);
593#[cfg(feature = "audio")]
594impl_sample_for_generic_newtype!(U24LE, 3);
595#[cfg(feature = "audio")]
596impl_sample_for_generic_newtype!(I24BE, 4);
597#[cfg(feature = "audio")]
598impl_sample_for_generic_newtype!(I24LE, 4);
599#[cfg(feature = "audio")]
600impl_sample_for_generic_newtype!(U24BE, 4);
601#[cfg(feature = "audio")]
602impl_sample_for_generic_newtype!(U24LE, 4);
603
604#[cfg(test)]
605mod tests {
606    use super::*;
607
608    macro_rules! assert_conversion_eq {
609        ($result:expr, $value:expr, $clipped:expr, $desc:expr) => {
610            assert_eq!($result.value, $value, $desc);
611            assert_eq!($result.clipped, $clipped, $desc);
612        };
613    }
614
615    macro_rules! test_to_signed_int {
616        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
617            #[test]
618            fn $fname() {
619                let val: $float = 0.25;
620                assert_conversion_eq!(
621                    $int::from_scaled_float(val),
622                    1 << ($bits - 3),
623                    false,
624                    "check +0.25"
625                );
626                let val: $float = -0.25;
627                assert_conversion_eq!(
628                    $int::from_scaled_float(val),
629                    -1 << ($bits - 3),
630                    false,
631                    "check -0.25"
632                );
633                let val: $float = 1.1;
634                assert_conversion_eq!(
635                    $int::from_scaled_float(val),
636                    $int::MAX,
637                    true,
638                    "clipped positive"
639                );
640                let val: $float = -1.1;
641                assert_conversion_eq!(
642                    $int::from_scaled_float(val),
643                    $int::MIN,
644                    true,
645                    "clipped negative"
646                );
647            }
648        };
649    }
650
651    macro_rules! test_to_unsigned_int {
652        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
653            #[test]
654            fn $fname() {
655                let val: $float = -0.5;
656                assert_conversion_eq!(
657                    $int::from_scaled_float(val),
658                    1 << ($bits - 2),
659                    false,
660                    "check -0.5"
661                );
662                let val: $float = 0.5;
663                assert_conversion_eq!(
664                    $int::from_scaled_float(val),
665                    $int::MAX - (1 << ($bits - 2)) + 1,
666                    false,
667                    "check 0.5"
668                );
669                let val: $float = 1.1;
670                assert_conversion_eq!(
671                    $int::from_scaled_float(val),
672                    $int::MAX,
673                    true,
674                    "clipped positive"
675                );
676                let val: $float = -1.1;
677                assert_conversion_eq!(
678                    $int::from_scaled_float(val),
679                    $int::MIN,
680                    true,
681                    "clipped negative"
682                );
683            }
684        };
685    }
686
687    test_to_signed_int!(convert_f32_to_i8, f32, i8, 8);
688    test_to_signed_int!(convert_642_to_i8, f64, i8, 8);
689    test_to_signed_int!(convert_f32_to_i16, f32, i16, 16);
690    test_to_signed_int!(convert_f64_to_i16, f64, i16, 16);
691    test_to_signed_int!(convert_f32_to_i32, f32, i32, 32);
692    test_to_signed_int!(convert_f64_to_i32, f64, i32, 32);
693    test_to_signed_int!(convert_f32_to_i64, f32, i64, 64);
694    test_to_signed_int!(convert_f64_to_i64, f64, i64, 64);
695
696    test_to_unsigned_int!(convert_f32_to_u8, f32, u8, 8);
697    test_to_unsigned_int!(convert_f64_to_u8, f64, u8, 8);
698    test_to_unsigned_int!(convert_f32_to_u16, f32, u16, 16);
699    test_to_unsigned_int!(convert_f64_to_u16, f64, u16, 16);
700    test_to_unsigned_int!(convert_f32_to_u32, f32, u32, 32);
701    test_to_unsigned_int!(convert_f64_to_u32, f64, u32, 32);
702    test_to_unsigned_int!(convert_f32_to_u64, f32, u64, 64);
703    test_to_unsigned_int!(convert_f64_to_u64, f64, u64, 64);
704
705    macro_rules! test_from_signed_int {
706        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
707            #[test]
708            fn $fname() {
709                let val: $int = -1 << ($bits - 2);
710                assert_eq!(val.to_scaled_float::<$float>(), -0.5, "check -0.5");
711                let val: $int = 1 << ($bits - 2);
712                assert_eq!(val.to_scaled_float::<$float>(), 0.5, "check 0.5");
713                let val: $int = $int::MIN;
714                assert_eq!(val.to_scaled_float::<$float>(), -1.0, "negative limit");
715            }
716        };
717    }
718
719    macro_rules! test_from_unsigned_int {
720        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
721            #[test]
722            fn $fname() {
723                let val: $int = 1 << ($bits - 2);
724                assert_eq!(val.to_scaled_float::<$float>(), -0.5, "check -0.5");
725                let val: $int = $int::MAX - (1 << ($bits - 2)) + 1;
726                assert_eq!(val.to_scaled_float::<$float>(), 0.5, "check 0.5");
727                let val: $int = 0;
728                assert_eq!(val.to_scaled_float::<$float>(), -1.0, "negative limit");
729            }
730        };
731    }
732
733    test_from_signed_int!(convert_f32_from_i8, f32, i8, 8);
734    test_from_signed_int!(convert_f64_from_i8, f64, i8, 8);
735    test_from_signed_int!(convert_f32_from_i16, f32, i16, 16);
736    test_from_signed_int!(convert_f64_from_i16, f64, i16, 16);
737    test_from_signed_int!(convert_f32_from_i32, f32, i32, 32);
738    test_from_signed_int!(convert_f64_from_i32, f64, i32, 32);
739    test_from_signed_int!(convert_f32_from_i64, f32, i64, 64);
740    test_from_signed_int!(convert_f64_from_i64, f64, i64, 64);
741
742    test_from_unsigned_int!(convert_f32_from_u8, f32, u8, 8);
743    test_from_unsigned_int!(convert_f64_from_u8, f64, u8, 8);
744    test_from_unsigned_int!(convert_f32_from_u16, f32, u16, 16);
745    test_from_unsigned_int!(convert_f64_from_u16, f64, u16, 16);
746    test_from_unsigned_int!(convert_f32_from_u32, f32, u32, 32);
747    test_from_unsigned_int!(convert_f64_from_u32, f64, u32, 32);
748    test_from_unsigned_int!(convert_f32_from_u64, f32, u64, 64);
749    test_from_unsigned_int!(convert_f64_from_u64, f64, u64, 64);
750
751    #[test]
752    fn test_to_clamped_int() {
753        let converted = to_clamped_int::<f32, i32>(12345.0, Some(12345));
754        assert_conversion_eq!(converted, 12345, false, "in range f32 i32");
755
756        let converted = to_clamped_int::<f32, i32>(1.0e10, None);
757        assert_conversion_eq!(converted, i32::MAX, true, "above range f32 i32");
758
759        let converted = to_clamped_int::<f32, i32>(-1.0e10, None);
760        assert_conversion_eq!(converted, i32::MIN, true, "below range f32 i32");
761
762        let converted = to_clamped_int::<f64, i32>(12345.0, Some(12345));
763        assert_conversion_eq!(converted, 12345, false, "in range f64 i32");
764
765        let converted = to_clamped_int::<f64, i32>(1.0e10, None);
766        assert_conversion_eq!(converted, i32::MAX, true, "above range f64 i32");
767
768        let converted = to_clamped_int::<f64, i32>(-1.0e10, None);
769        assert_conversion_eq!(converted, i32::MIN, true, "below range f64 i32");
770    }
771
772    #[test]
773    fn test_to_clamped_uint() {
774        let converted = to_clamped_int::<f32, u32>(12345.0, Some(12345));
775        assert_conversion_eq!(converted, 12345, false, "in range f32 u32");
776
777        let converted = to_clamped_int::<f32, u32>(1.0e10, None);
778        assert_conversion_eq!(converted, u32::MAX, true, "above range f32 u32");
779
780        let converted = to_clamped_int::<f32, u32>(-1.0, None);
781        assert_conversion_eq!(converted, u32::MIN, true, "below range f32 u32");
782
783        let converted = to_clamped_int::<f64, u32>(12345.0, Some(12345));
784        assert_conversion_eq!(converted, 12345, false, "in range f64 u32");
785
786        let converted = to_clamped_int::<f64, u32>(1.0e10, None);
787        assert_conversion_eq!(converted, u32::MAX, true, "above range f64 u32");
788
789        let converted = to_clamped_int::<f64, u32>(-1.0, None);
790        assert_conversion_eq!(converted, u32::MIN, true, "below range f64 u32");
791    }
792
793    macro_rules! test_simple_int_bytes {
794        ($fname:ident, $number:ty, $wrapper:ident, $to_bytes_fn:ident) => {
795            #[test]
796            #[allow(non_snake_case)]
797            fn $fname() {
798                let number: $number = <$number>::MAX / 5 * 4;
799                let wrapped = $wrapper(number.$to_bytes_fn());
800                assert_eq!(number, wrapped.to_number());
801            }
802        };
803    }
804
805    macro_rules! test_float_bytes {
806        ($fname:ident, $number:ty, $wrapper:ident, $to_bytes_fn:ident) => {
807            #[test]
808            #[allow(non_snake_case)]
809            fn $fname() {
810                let number: $number = 12345.0;
811                let wrapped = $wrapper(number.$to_bytes_fn());
812                assert_eq!(number, wrapped.to_number());
813            }
814        };
815    }
816
817    test_simple_int_bytes!(convert_i16_from_I16LE, i16, I16LE, to_le_bytes);
818    test_simple_int_bytes!(convert_i16_from_I16BE, i16, I16BE, to_be_bytes);
819    test_simple_int_bytes!(convert_i32_from_I32LE, i32, I32LE, to_le_bytes);
820    test_simple_int_bytes!(convert_i32_from_I32BE, i32, I32BE, to_be_bytes);
821    test_simple_int_bytes!(convert_i64_from_I64LE, i64, I64LE, to_le_bytes);
822    test_simple_int_bytes!(convert_i64_from_I64BE, i64, I64BE, to_be_bytes);
823
824    test_simple_int_bytes!(convert_u16_from_U16LE, u16, U16LE, to_le_bytes);
825    test_simple_int_bytes!(convert_u16_from_U16BE, u16, U16BE, to_be_bytes);
826    test_simple_int_bytes!(convert_u32_from_U32LE, u32, U32LE, to_le_bytes);
827    test_simple_int_bytes!(convert_u32_from_U32BE, u32, U32BE, to_be_bytes);
828    test_simple_int_bytes!(convert_u64_from_U64LE, u64, U64LE, to_le_bytes);
829    test_simple_int_bytes!(convert_u64_from_U64BE, u64, U64BE, to_be_bytes);
830
831    test_float_bytes!(convert_f32_fom_F32LE, f32, F32LE, to_le_bytes);
832    test_float_bytes!(convert_f32_fom_F32BE, f32, F32BE, to_be_bytes);
833    test_float_bytes!(convert_f64_fom_F64LE, f64, F64LE, to_le_bytes);
834    test_float_bytes!(convert_f64_fom_F64BE, f64, F64BE, to_be_bytes);
835
836    #[test]
837    #[allow(non_snake_case)]
838    fn test_I24LE_3bytes() {
839        let number = i32::MAX / 5 * 4;
840
841        // make sure LSB is zero
842        let number = number >> 8;
843        let number = number << 8;
844
845        let allbytes = number.to_le_bytes();
846        // Little-endian stores the LSB at the smallest address.
847        // Drop the LSB!
848        let bytes = [allbytes[1], allbytes[2], allbytes[3]];
849
850        let wrapped = I24LE(bytes);
851        assert_eq!(number, wrapped.to_number());
852    }
853
854    #[test]
855    #[allow(non_snake_case)]
856    fn test_I24BE_3bytes() {
857        let number = i32::MAX / 5 * 4;
858
859        // make sure LSB is zero
860        let number = number >> 8;
861        let number = number << 8;
862
863        let allbytes = number.to_be_bytes();
864        // Big-endian stores the LSB at the largest address.
865        // Drop the LSB!
866        let bytes = [allbytes[0], allbytes[1], allbytes[2]];
867
868        let wrapped = I24BE(bytes);
869        assert_eq!(number, wrapped.to_number());
870    }
871
872    #[test]
873    #[allow(non_snake_case)]
874    fn test_I24LE_4bytes() {
875        let number = i32::MAX / 5 * 4;
876
877        // make sure LSB is zero
878        let number = number >> 8;
879        let number = number << 8;
880
881        let allbytes = number.to_le_bytes();
882        // Little-endian stores the LSB at the smallest address.
883        // Drop the LSB and insert padding at MSB!
884        let bytes = [allbytes[1], allbytes[2], allbytes[3], 0];
885
886        let wrapped = I24LE(bytes);
887        assert_eq!(number, wrapped.to_number());
888    }
889
890    #[test]
891    #[allow(non_snake_case)]
892    fn test_I24BE_4bytes() {
893        let number = i32::MAX / 5 * 4;
894
895        // make sure LSB is zero
896        let number = number >> 8;
897        let number = number << 8;
898
899        let allbytes = number.to_be_bytes();
900        // Big-endian stores the LSB at the largest address.
901        // Drop the LSB and insert padding at MSB!
902        let bytes = [0, allbytes[0], allbytes[1], allbytes[2]];
903
904        let wrapped = I24BE(bytes);
905        assert_eq!(number, wrapped.to_number());
906    }
907
908    #[test]
909    #[allow(non_snake_case)]
910    fn test_U24LE_3bytes() {
911        let number = u32::MAX / 5 * 4;
912
913        // make sure LSB is zero
914        let number = number >> 8;
915        let number = number << 8;
916
917        let allbytes = number.to_le_bytes();
918        // Little-endian stores the LSB at the smallest address.
919        // Drop the LSB!
920        let bytes = [allbytes[1], allbytes[2], allbytes[3]];
921
922        let wrapped = U24LE(bytes);
923        assert_eq!(number, wrapped.to_number());
924    }
925
926    #[test]
927    #[allow(non_snake_case)]
928    fn test_U24BE_3bytes() {
929        let number = u32::MAX / 5 * 4;
930
931        // make sure LSB is zero
932        let number = number >> 8;
933        let number = number << 8;
934
935        let allbytes = number.to_be_bytes();
936        // Big-endian stores the LSB at the largest address.
937        // Drop the LSB!
938        let bytes = [allbytes[0], allbytes[1], allbytes[2]];
939
940        let wrapped = U24BE(bytes);
941        assert_eq!(number, wrapped.to_number());
942    }
943
944    #[test]
945    #[allow(non_snake_case)]
946    fn test_U24LE_4bytes() {
947        let number = u32::MAX / 5 * 4;
948
949        // make sure LSB is zero
950        let number = number >> 8;
951        let number = number << 8;
952
953        let allbytes = number.to_le_bytes();
954        // Little-endian stores the LSB at the smallest address.
955        // Drop the LSB and insert padding at MSB!
956        let bytes = [allbytes[1], allbytes[2], allbytes[3], 0];
957
958        let wrapped = U24LE(bytes);
959        assert_eq!(number, wrapped.to_number());
960    }
961
962    #[test]
963    #[allow(non_snake_case)]
964    fn test_U24BE_4bytes() {
965        let number = u32::MAX / 5 * 4;
966
967        // make sure LSB is zero
968        let number = number >> 8;
969        let number = number << 8;
970
971        let allbytes = number.to_be_bytes();
972        // Big-endian stores the LSB at the largest address.
973        // Drop the LSB and insert padding at MSB!
974        let bytes = [0, allbytes[0], allbytes[1], allbytes[2]];
975
976        let wrapped = U24BE(bytes);
977        assert_eq!(number, wrapped.to_number());
978    }
979}