Skip to main content

audioadapter_sample/
sample.rs

1#![allow(non_camel_case_types)]
2
3use num_traits::{PrimInt, ToPrimitive, float::FloatCore};
4
5// ------ 8-bit integer formats ------
6
7/// 8 bit signed integer. Stored as 1 byte.
8/// A single byte has no byte order,
9/// so there are no little endian and big endian variants.
10#[derive(Debug, Clone, Copy)]
11#[repr(transparent)]
12pub struct I8([u8; 1]);
13
14/// 8 bit unsigned integer. Stored as 1 byte.
15/// A single byte has no byte order,
16/// so there are no little endian and big endian variants.
17#[derive(Debug, Clone, Copy)]
18#[repr(transparent)]
19pub struct U8([u8; 1]);
20
21// ------ 16-bit integer formats ------
22
23/// 16 bit signed integer, little endian. Stored as 2 bytes.
24#[derive(Debug, Clone, Copy)]
25#[repr(transparent)]
26pub struct I16_LE([u8; 2]);
27
28/// 16 bit signed integer, big endian. Stored as 2 bytes.
29#[derive(Debug, Clone, Copy)]
30#[repr(transparent)]
31pub struct I16_BE([u8; 2]);
32
33/// 16 bit unsigned integer, little endian. Stored as 2 bytes.
34#[derive(Debug, Clone, Copy)]
35#[repr(transparent)]
36pub struct U16_LE([u8; 2]);
37
38/// 16 bit unsigned integer, big endian. Stored as 2 bytes.
39#[derive(Debug, Clone, Copy)]
40#[repr(transparent)]
41pub struct U16_BE([u8; 2]);
42
43// ----- 24-bit formats -----
44
45/// 24 bit signed integer, little endian. Stored as 3 bytes.
46#[derive(Debug, Clone, Copy)]
47#[repr(transparent)]
48pub struct I24_LE([u8; 3]);
49
50/// 24 bit signed integer, little endian. Stored as 4 bytes left justified.
51/// The 24 data bits are stored in the three most significant bytes,
52/// while the least significant byte is unused padding.
53#[derive(Debug, Clone, Copy)]
54#[repr(transparent)]
55pub struct I24_4LJ_LE([u8; 4]);
56
57/// 24 bit signed integer, little endian. Stored as 4 bytes right justified.
58/// The 24 data bits are stored in the three least significant bytes,
59/// while the most significant byte is unused padding.
60#[derive(Debug, Clone, Copy)]
61#[repr(transparent)]
62pub struct I24_4RJ_LE([u8; 4]);
63
64/// 24 bit signed integer, big endian. Stored as 3 bytes.
65#[derive(Debug, Clone, Copy)]
66#[repr(transparent)]
67pub struct I24_BE([u8; 3]);
68
69/// 24 bit signed integer, big endian. Stored as 4 bytes left justified.
70/// The 24 data bits are stored in the three most significant bytes,
71/// while the least significant byte is unused padding.
72#[derive(Debug, Clone, Copy)]
73#[repr(transparent)]
74pub struct I24_4LJ_BE([u8; 4]);
75
76/// 24 bit signed integer, big endian. Stored as 4 bytes right justified.
77/// The 24 data bits are stored in the three least significant bytes,
78/// while the most significant byte is unused padding.
79#[derive(Debug, Clone, Copy)]
80#[repr(transparent)]
81pub struct I24_4RJ_BE([u8; 4]);
82
83/// 24 bit unsigned integer, little endian. Stored as 3 bytes.
84#[derive(Debug, Clone, Copy)]
85#[repr(transparent)]
86pub struct U24_LE([u8; 3]);
87
88/// 24 bit unsigned integer, little endian. Stored as 4 bytes left justified.
89/// The 24 data bits are stored in the three most significant bytes,
90/// while the least significant byte is unused padding.
91#[derive(Debug, Clone, Copy)]
92#[repr(transparent)]
93pub struct U24_4LJ_LE([u8; 4]);
94
95/// 24 bit unsigned integer, little endian. Stored as 4 bytes right justified.
96/// The 24 data bits are stored in the three least significant bytes,
97/// while the most significant byte is unused padding.
98#[derive(Debug, Clone, Copy)]
99#[repr(transparent)]
100pub struct U24_4RJ_LE([u8; 4]);
101
102/// 24 bit unsigned integer, big endian. Stored as 3 bytes.
103#[derive(Debug, Clone, Copy)]
104#[repr(transparent)]
105pub struct U24_BE([u8; 3]);
106
107/// 24 bit unsigned integer, big endian. Stored as 4 bytes left justified.
108/// The 24 data bits are stored in the three most significant bytes,
109/// while the least significant byte is unused padding.
110#[derive(Debug, Clone, Copy)]
111#[repr(transparent)]
112pub struct U24_4LJ_BE([u8; 4]);
113
114/// 24 bit unsigned integer, big endian. Stored as 4 bytes right justified.
115/// The 24 data bits are stored in the three least significant bytes,
116/// while the most significant byte is unused padding.
117#[derive(Debug, Clone, Copy)]
118#[repr(transparent)]
119pub struct U24_4RJ_BE([u8; 4]);
120
121// ------ 32-bit integer formats ------
122
123/// 32 bit signed integer, little endian. Stored as 4 bytes.
124#[derive(Debug, Clone, Copy)]
125#[repr(transparent)]
126pub struct I32_LE([u8; 4]);
127
128/// 32 bit signed integer, big endian. Stored as 4 bytes.
129#[derive(Debug, Clone, Copy)]
130#[repr(transparent)]
131pub struct I32_BE([u8; 4]);
132
133/// 32 bit unsigned integer, little endian. Stored as 4 bytes.
134#[derive(Debug, Clone, Copy)]
135#[repr(transparent)]
136pub struct U32_LE([u8; 4]);
137
138/// 32 bit unsigned integer, big endian. Stored as 4 bytes.
139#[derive(Debug, Clone, Copy)]
140#[repr(transparent)]
141pub struct U32_BE([u8; 4]);
142
143// ----- 64-bit integer formats ------
144
145/// 64 bit signed integer, little endian. Stored as 8 bytes.
146#[derive(Debug, Clone, Copy)]
147#[repr(transparent)]
148pub struct I64_LE([u8; 8]);
149
150/// 64 bit signed integer, big endian. Stored as 8 bytes.
151#[derive(Debug, Clone, Copy)]
152#[repr(transparent)]
153pub struct I64_BE([u8; 8]);
154
155/// 64 bit unsigned integer, little endian. Stored as 8 bytes.
156#[derive(Debug, Clone, Copy)]
157#[repr(transparent)]
158pub struct U64_LE([u8; 8]);
159
160/// 64 bit unsigned integer, big endian. Stored as 8 bytes.
161#[derive(Debug, Clone, Copy)]
162#[repr(transparent)]
163pub struct U64_BE([u8; 8]);
164
165// ----- floating point formats -----
166
167/// 32 bit floating point, little endian. Stored as 4 bytes.
168#[derive(Debug, Clone, Copy)]
169#[repr(transparent)]
170pub struct F32_LE([u8; 4]);
171
172/// 32 bit floating point, big endian. Stored as 4 bytes.
173#[derive(Debug, Clone, Copy)]
174#[repr(transparent)]
175pub struct F32_BE([u8; 4]);
176
177/// 64 bit floating point, little endian. Stored as 8 bytes.
178#[derive(Debug, Clone, Copy)]
179#[repr(transparent)]
180pub struct F64_LE([u8; 8]);
181
182/// 64 bit floating point, big endian. Stored as 8 bytes.
183#[derive(Debug, Clone, Copy)]
184#[repr(transparent)]
185pub struct F64_BE([u8; 8]);
186
187/// Convert a float to an integer, clamp at the min and max limits of the integer.
188fn to_clamped_int<T: FloatCore + ToPrimitive, U: PrimInt>(
189    value: T,
190    converted: Option<U>,
191) -> ConversionResult<U> {
192    if let Some(val) = converted {
193        return ConversionResult {
194            clipped: false,
195            value: val,
196        };
197    }
198    if value.is_nan() {
199        return ConversionResult {
200            clipped: true,
201            value: U::zero(),
202        };
203    }
204    if value > T::zero() {
205        return ConversionResult {
206            clipped: true,
207            value: U::max_value(),
208        };
209    }
210    ConversionResult {
211        clipped: true,
212        value: U::min_value(),
213    }
214}
215
216/// A conversion result, containing the resulting value as `value`
217/// and a boolean `clipped` indicating if the value was clipped during conversion.
218pub struct ConversionResult<T> {
219    pub clipped: bool,
220    pub value: T,
221}
222
223/// A trait for converting a given sample type to and from floating point values.
224/// The floating point values use the range -1.0 to +1.0.
225/// When converting to/from signed integers, the range does not include +1.0.
226/// For example, an 8-bit signed integer supports the range -128 to +127.
227/// When these values are converted to float, 0 becomes 0.0,
228/// -128 becomes -1.0, and 127 becomes 127/128 ≈ 0.992.
229/// Unsigned integers are also converted to the same -1.0 to +1.0 range.
230/// For an 8-but unsigned integer, 128 is the center point and becomes 0.0.
231/// The value 0 becomes -1.0, and 255 becomes 127/128 ≈ 0.992.
232pub trait RawSample
233where
234    Self: Sized,
235{
236    /// Convert the sample value to a float in the range -1.0 .. +1.0.
237    fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T;
238
239    /// Convert a float in the range -1.0 .. +1.0 to a sample value.
240    ///
241    /// For integer formats, values outside the allowed range are clipped to the
242    /// nearest limit and the returned `clipped` flag is set.
243    /// Floating point formats are not range-limited: values outside -1.0 .. +1.0
244    /// are valid headroom, are passed through unchanged, and never set `clipped`.
245    fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self>;
246}
247
248/// A trait for converting samples stored as raw bytes into a numerical type.
249/// Each implementation defines the associated type `NumericType`,
250/// which is the nearest matching numeric type for the original format.
251/// If a direct match exists, this is used.
252/// For example signed 16 bit integer samples use [i16].
253/// For formats that don't have a direct match,
254/// the next larger numeric type is used.
255/// For example for 24 bit signed integers,
256/// this means [i32].
257/// The values are scaled to use the full range of the `NumericType`
258/// associated type.
259pub trait BytesSample {
260    /// The closest matching numeric type.
261    type NumericType: Copy;
262
263    /// The number of bytes making up each sample value.
264    const BYTES_PER_SAMPLE: usize;
265
266    /// Create a sample with all bytes set to zero.
267    ///
268    /// This gives a correctly sized, valid value whose bytes can then be
269    /// overwritten, for example via [`as_mut_slice`](Self::as_mut_slice) when
270    /// reading from a stream.
271    fn zero() -> Self;
272
273    /// Create a new ByteSample from a slice of raw bytes.
274    /// The slice length must be at least the number of bytes
275    /// for a sample value.
276    fn from_slice(bytes: &[u8]) -> Self;
277
278    /// Return the raw bytes as a slice.
279    fn as_slice(&self) -> &[u8];
280
281    /// Return the raw bytes as a mutable slice.
282    fn as_mut_slice(&mut self) -> &mut [u8];
283
284    /// Convert the raw bytes to a numerical value.
285    fn to_number(&self) -> Self::NumericType;
286
287    /// Convert a numerical value to raw bytes.
288    fn from_number(value: Self::NumericType) -> Self;
289}
290
291macro_rules! rawsample_for_int {
292    ($type:ident, $to:ident) => {
293        impl RawSample for $type {
294            fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
295                T::from(*self).unwrap() / (T::from($type::MAX).unwrap() + T::one())
296            }
297
298            fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
299                let scaled = value * (T::from($type::MAX).unwrap() + T::one());
300                let converted = scaled.$to();
301                to_clamped_int(scaled, converted)
302            }
303        }
304    };
305}
306
307rawsample_for_int!(i8, to_i8);
308rawsample_for_int!(i16, to_i16);
309rawsample_for_int!(i32, to_i32);
310rawsample_for_int!(i64, to_i64);
311
312macro_rules! rawsample_for_uint {
313    ($type:ident, $to:ident) => {
314        impl RawSample for $type {
315            fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
316                let max_ampl = (T::from($type::MAX).unwrap() + T::one()) / T::from(2).unwrap();
317                (T::from(*self).unwrap() - max_ampl) / max_ampl
318            }
319
320            fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
321                let max_ampl = (T::from($type::MAX).unwrap() + T::one()) / T::from(2).unwrap();
322                let scaled = value * max_ampl + max_ampl;
323                let converted = scaled.$to();
324                to_clamped_int(scaled, converted)
325            }
326        }
327    };
328}
329
330rawsample_for_uint!(u8, to_u8);
331rawsample_for_uint!(u16, to_u16);
332rawsample_for_uint!(u32, to_u32);
333rawsample_for_uint!(u64, to_u64);
334
335macro_rules! rawsample_for_float {
336    ($type:ident, $to:ident) => {
337        impl RawSample for $type {
338            fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
339                T::from(*self).unwrap_or(T::zero())
340            }
341
342            fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
343                // Floating point formats are not range-limited. Values outside
344                // -1.0..1.0 are valid headroom and pass through unchanged, so no
345                // clipping is applied and `clipped` is always false.
346                ConversionResult {
347                    clipped: false,
348                    value: value.$to().unwrap_or(0.0),
349                }
350            }
351        }
352    };
353}
354
355rawsample_for_float!(f32, to_f32);
356rawsample_for_float!(f64, to_f64);
357
358// 24 bit formats, needs more work than others
359// because they don't map directly to a normal numerical type,
360
361/// 24 bit signed integer, little endian, stored as 4 bytes right justified.
362/// The data is in the lower 3 bytes and the most significant byte is padding.
363impl BytesSample for I24_4RJ_LE {
364    type NumericType = i32;
365    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
366
367    fn zero() -> Self {
368        Self(Default::default())
369    }
370
371    fn from_slice(bytes: &[u8]) -> Self {
372        Self(bytes[0..4].try_into().unwrap())
373    }
374
375    fn as_slice(&self) -> &[u8] {
376        &self.0
377    }
378
379    fn as_mut_slice(&mut self) -> &mut [u8] {
380        &mut self.0
381    }
382
383    fn to_number(&self) -> Self::NumericType {
384        let padded = [0, self.0[0], self.0[1], self.0[2]];
385        i32::from_le_bytes(padded)
386    }
387
388    fn from_number(value: Self::NumericType) -> Self {
389        let bytes = value.to_le_bytes();
390        Self([bytes[1], bytes[2], bytes[3], 0])
391    }
392}
393
394/// 24 bit signed integer, little endian, stored as 4 bytes left justified.
395/// The data is in the upper 3 bytes and the least significant byte is padding.
396impl BytesSample for I24_4LJ_LE {
397    type NumericType = i32;
398    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
399
400    fn zero() -> Self {
401        Self(Default::default())
402    }
403
404    fn from_slice(bytes: &[u8]) -> Self {
405        Self(bytes[0..4].try_into().unwrap())
406    }
407
408    fn as_slice(&self) -> &[u8] {
409        &self.0
410    }
411
412    fn as_mut_slice(&mut self) -> &mut [u8] {
413        &mut self.0
414    }
415
416    fn to_number(&self) -> Self::NumericType {
417        let padded = [0, self.0[1], self.0[2], self.0[3]];
418        i32::from_le_bytes(padded)
419    }
420
421    fn from_number(value: Self::NumericType) -> Self {
422        let bytes = value.to_le_bytes();
423        Self([0, bytes[1], bytes[2], bytes[3]])
424    }
425}
426
427/// 24 bit signed integer, little endian, stored as 3 bytes without padding.
428impl BytesSample for I24_LE {
429    type NumericType = i32;
430    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
431
432    fn zero() -> Self {
433        Self(Default::default())
434    }
435
436    fn from_slice(bytes: &[u8]) -> Self {
437        Self(bytes[0..3].try_into().unwrap())
438    }
439
440    fn as_slice(&self) -> &[u8] {
441        &self.0
442    }
443
444    fn as_mut_slice(&mut self) -> &mut [u8] {
445        &mut self.0
446    }
447
448    fn to_number(&self) -> Self::NumericType {
449        let padded = [0, self.0[0], self.0[1], self.0[2]];
450        i32::from_le_bytes(padded)
451    }
452
453    fn from_number(value: Self::NumericType) -> Self {
454        let bytes = value.to_le_bytes();
455        Self([bytes[1], bytes[2], bytes[3]])
456    }
457}
458
459/// 24 bit signed integer, big endian, stored as 4 bytes right justified.
460/// The data is in the lower 3 bytes and the most significant byte is padding.
461impl BytesSample for I24_4RJ_BE {
462    type NumericType = i32;
463    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
464
465    fn zero() -> Self {
466        Self(Default::default())
467    }
468
469    fn from_slice(bytes: &[u8]) -> Self {
470        Self(bytes[0..4].try_into().unwrap())
471    }
472
473    fn as_slice(&self) -> &[u8] {
474        &self.0
475    }
476
477    fn as_mut_slice(&mut self) -> &mut [u8] {
478        &mut self.0
479    }
480
481    fn to_number(&self) -> Self::NumericType {
482        let padded = [self.0[1], self.0[2], self.0[3], 0];
483        i32::from_be_bytes(padded)
484    }
485
486    fn from_number(value: Self::NumericType) -> Self {
487        let bytes = value.to_be_bytes();
488        Self([0, bytes[0], bytes[1], bytes[2]])
489    }
490}
491
492/// 24 bit signed integer, big endian, stored as 4 bytes left justified.
493/// The data is in the upper 3 bytes and the least significant byte is padding.
494impl BytesSample for I24_4LJ_BE {
495    type NumericType = i32;
496    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
497
498    fn zero() -> Self {
499        Self(Default::default())
500    }
501
502    fn from_slice(bytes: &[u8]) -> Self {
503        Self(bytes[0..4].try_into().unwrap())
504    }
505
506    fn as_slice(&self) -> &[u8] {
507        &self.0
508    }
509
510    fn as_mut_slice(&mut self) -> &mut [u8] {
511        &mut self.0
512    }
513
514    fn to_number(&self) -> Self::NumericType {
515        let padded = [self.0[0], self.0[1], self.0[2], 0];
516        i32::from_be_bytes(padded)
517    }
518
519    fn from_number(value: Self::NumericType) -> Self {
520        let bytes = value.to_be_bytes();
521        Self([bytes[0], bytes[1], bytes[2], 0])
522    }
523}
524
525/// 24 bit signed integer, big endian, stored as 3 bytes without padding.
526impl BytesSample for I24_BE {
527    type NumericType = i32;
528    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
529
530    fn zero() -> Self {
531        Self(Default::default())
532    }
533
534    fn from_slice(bytes: &[u8]) -> Self {
535        Self(bytes[0..3].try_into().unwrap())
536    }
537
538    fn as_slice(&self) -> &[u8] {
539        &self.0
540    }
541
542    fn as_mut_slice(&mut self) -> &mut [u8] {
543        &mut self.0
544    }
545
546    fn to_number(&self) -> Self::NumericType {
547        let padded = [self.0[0], self.0[1], self.0[2], 0];
548        i32::from_be_bytes(padded)
549    }
550
551    fn from_number(value: Self::NumericType) -> Self {
552        let bytes = value.to_be_bytes();
553        Self([bytes[0], bytes[1], bytes[2]])
554    }
555}
556
557/// 24 bit unsigned integer, little endian, stored as 4 bytes right justified.
558/// The data is in the lower 3 bytes and the most significant byte is padding.
559impl BytesSample for U24_4RJ_LE {
560    type NumericType = u32;
561    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
562
563    fn zero() -> Self {
564        Self(Default::default())
565    }
566
567    fn from_slice(bytes: &[u8]) -> Self {
568        Self(bytes[0..4].try_into().unwrap())
569    }
570
571    fn as_slice(&self) -> &[u8] {
572        &self.0
573    }
574
575    fn as_mut_slice(&mut self) -> &mut [u8] {
576        &mut self.0
577    }
578
579    fn to_number(&self) -> Self::NumericType {
580        let padded = [0, self.0[0], self.0[1], self.0[2]];
581        u32::from_le_bytes(padded)
582    }
583
584    fn from_number(value: Self::NumericType) -> Self {
585        let bytes = value.to_le_bytes();
586        Self([bytes[1], bytes[2], bytes[3], 0])
587    }
588}
589
590/// 24 bit unsigned integer, little endian, stored as 4 bytes left justified.
591/// The data is in the upper 3 bytes and the least significant byte is padding.
592impl BytesSample for U24_4LJ_LE {
593    type NumericType = u32;
594    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
595
596    fn zero() -> Self {
597        Self(Default::default())
598    }
599
600    fn from_slice(bytes: &[u8]) -> Self {
601        Self(bytes[0..4].try_into().unwrap())
602    }
603
604    fn as_slice(&self) -> &[u8] {
605        &self.0
606    }
607
608    fn as_mut_slice(&mut self) -> &mut [u8] {
609        &mut self.0
610    }
611
612    fn to_number(&self) -> Self::NumericType {
613        let padded = [0, self.0[1], self.0[2], self.0[3]];
614        u32::from_le_bytes(padded)
615    }
616
617    fn from_number(value: Self::NumericType) -> Self {
618        let bytes = value.to_le_bytes();
619        Self([0, bytes[1], bytes[2], bytes[3]])
620    }
621}
622
623/// 24 bit unsigned integer, little endian, stored as 3 bytes without padding.
624impl BytesSample for U24_LE {
625    type NumericType = u32;
626    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
627
628    fn zero() -> Self {
629        Self(Default::default())
630    }
631
632    fn from_slice(bytes: &[u8]) -> Self {
633        Self(bytes[0..3].try_into().unwrap())
634    }
635
636    fn as_slice(&self) -> &[u8] {
637        &self.0
638    }
639
640    fn as_mut_slice(&mut self) -> &mut [u8] {
641        &mut self.0
642    }
643
644    fn to_number(&self) -> Self::NumericType {
645        let padded = [0, self.0[0], self.0[1], self.0[2]];
646        u32::from_le_bytes(padded)
647    }
648
649    fn from_number(value: Self::NumericType) -> Self {
650        let bytes = value.to_le_bytes();
651        Self([bytes[1], bytes[2], bytes[3]])
652    }
653}
654
655/// 24 bit unsigned integer, big endian, stored as 4 bytes right justified.
656/// The data is in the lower 3 bytes and the most significant byte is padding.
657impl BytesSample for U24_4RJ_BE {
658    type NumericType = u32;
659    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
660
661    fn zero() -> Self {
662        Self(Default::default())
663    }
664
665    fn from_slice(bytes: &[u8]) -> Self {
666        Self(bytes[0..4].try_into().unwrap())
667    }
668
669    fn as_slice(&self) -> &[u8] {
670        &self.0
671    }
672
673    fn as_mut_slice(&mut self) -> &mut [u8] {
674        &mut self.0
675    }
676
677    fn to_number(&self) -> Self::NumericType {
678        let padded = [self.0[1], self.0[2], self.0[3], 0];
679        u32::from_be_bytes(padded)
680    }
681
682    fn from_number(value: Self::NumericType) -> Self {
683        let bytes = value.to_be_bytes();
684        Self([0, bytes[0], bytes[1], bytes[2]])
685    }
686}
687
688/// 24 bit unsigned integer, big endian, stored as 4 bytes left justified.
689/// The data is in the upper 3 bytes and the least significant byte is padding.
690impl BytesSample for U24_4LJ_BE {
691    type NumericType = u32;
692    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
693
694    fn zero() -> Self {
695        Self(Default::default())
696    }
697
698    fn from_slice(bytes: &[u8]) -> Self {
699        Self(bytes[0..4].try_into().unwrap())
700    }
701
702    fn as_slice(&self) -> &[u8] {
703        &self.0
704    }
705
706    fn as_mut_slice(&mut self) -> &mut [u8] {
707        &mut self.0
708    }
709
710    fn to_number(&self) -> Self::NumericType {
711        let padded = [self.0[0], self.0[1], self.0[2], 0];
712        u32::from_be_bytes(padded)
713    }
714
715    fn from_number(value: Self::NumericType) -> Self {
716        let bytes = value.to_be_bytes();
717        Self([bytes[0], bytes[1], bytes[2], 0])
718    }
719}
720
721/// 24 bit unsigned integer, big endian, stored as 3 bytes without padding.
722impl BytesSample for U24_BE {
723    type NumericType = u32;
724    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
725
726    fn zero() -> Self {
727        Self(Default::default())
728    }
729
730    fn from_slice(bytes: &[u8]) -> Self {
731        Self(bytes[0..3].try_into().unwrap())
732    }
733
734    fn as_slice(&self) -> &[u8] {
735        &self.0
736    }
737
738    fn as_mut_slice(&mut self) -> &mut [u8] {
739        &mut self.0
740    }
741
742    fn to_number(&self) -> Self::NumericType {
743        let padded = [self.0[0], self.0[1], self.0[2], 0];
744        u32::from_be_bytes(padded)
745    }
746
747    fn from_number(value: Self::NumericType) -> Self {
748        let bytes = value.to_be_bytes();
749        Self([bytes[0], bytes[1], bytes[2]])
750    }
751}
752
753macro_rules! bytessample_for_newtype {
754    ($type:ident, $newtype:ident, $from:ident, $to:ident) => {
755        impl BytesSample for $newtype {
756            type NumericType = $type;
757            const BYTES_PER_SAMPLE: usize = core::mem::size_of::<$type>();
758
759            fn zero() -> Self {
760                Self(Default::default())
761            }
762
763            fn from_slice(bytes: &[u8]) -> Self {
764                Self(bytes.try_into().unwrap())
765            }
766
767            fn as_slice(&self) -> &[u8] {
768                &self.0
769            }
770
771            fn as_mut_slice(&mut self) -> &mut [u8] {
772                &mut self.0
773            }
774
775            fn to_number(&self) -> Self::NumericType {
776                $type::$from(self.0)
777            }
778
779            fn from_number(value: Self::NumericType) -> Self {
780                Self(value.$to())
781            }
782        }
783    };
784}
785
786// Single byte formats, where the endianness of the conversion is irrelevant.
787bytessample_for_newtype!(i8, I8, from_le_bytes, to_le_bytes);
788bytessample_for_newtype!(u8, U8, from_le_bytes, to_le_bytes);
789
790bytessample_for_newtype!(i64, I64_LE, from_le_bytes, to_le_bytes);
791bytessample_for_newtype!(u64, U64_LE, from_le_bytes, to_le_bytes);
792bytessample_for_newtype!(i64, I64_BE, from_be_bytes, to_be_bytes);
793bytessample_for_newtype!(u64, U64_BE, from_be_bytes, to_be_bytes);
794
795bytessample_for_newtype!(i16, I16_LE, from_le_bytes, to_le_bytes);
796bytessample_for_newtype!(u16, U16_LE, from_le_bytes, to_le_bytes);
797bytessample_for_newtype!(i16, I16_BE, from_be_bytes, to_be_bytes);
798bytessample_for_newtype!(u16, U16_BE, from_be_bytes, to_be_bytes);
799
800bytessample_for_newtype!(i32, I32_LE, from_le_bytes, to_le_bytes);
801bytessample_for_newtype!(u32, U32_LE, from_le_bytes, to_le_bytes);
802bytessample_for_newtype!(i32, I32_BE, from_be_bytes, to_be_bytes);
803bytessample_for_newtype!(u32, U32_BE, from_be_bytes, to_be_bytes);
804
805bytessample_for_newtype!(f32, F32_LE, from_le_bytes, to_le_bytes);
806bytessample_for_newtype!(f32, F32_BE, from_be_bytes, to_be_bytes);
807bytessample_for_newtype!(f64, F64_LE, from_le_bytes, to_le_bytes);
808bytessample_for_newtype!(f64, F64_BE, from_be_bytes, to_be_bytes);
809
810impl<V> RawSample for V
811where
812    V: BytesSample,
813    <V as BytesSample>::NumericType: RawSample,
814{
815    fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
816        let value = self.to_number();
817        value.to_scaled_float()
818    }
819
820    fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
821        let value = <V as BytesSample>::NumericType::from_scaled_float(value);
822        ConversionResult {
823            clipped: value.clipped,
824            value: V::from_number(value.value),
825        }
826    }
827}
828
829#[cfg(test)]
830mod tests {
831    use super::*;
832
833    macro_rules! assert_conversion_eq {
834        ($result:expr, $value:expr, $clipped:expr, $desc:expr) => {
835            assert_eq!($result.value, $value, $desc);
836            assert_eq!($result.clipped, $clipped, $desc);
837        };
838    }
839
840    macro_rules! test_to_signed_int {
841        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
842            #[test]
843            fn $fname() {
844                let val: $float = 0.25;
845                assert_conversion_eq!(
846                    $int::from_scaled_float(val),
847                    1 << ($bits - 3),
848                    false,
849                    "check +0.25"
850                );
851                let val: $float = -0.25;
852                assert_conversion_eq!(
853                    $int::from_scaled_float(val),
854                    -1 << ($bits - 3),
855                    false,
856                    "check -0.25"
857                );
858                let val: $float = 1.1;
859                assert_conversion_eq!(
860                    $int::from_scaled_float(val),
861                    $int::MAX,
862                    true,
863                    "clipped positive"
864                );
865                let val: $float = -1.1;
866                assert_conversion_eq!(
867                    $int::from_scaled_float(val),
868                    $int::MIN,
869                    true,
870                    "clipped negative"
871                );
872            }
873        };
874    }
875
876    macro_rules! test_to_unsigned_int {
877        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
878            #[test]
879            fn $fname() {
880                let val: $float = -0.5;
881                assert_conversion_eq!(
882                    $int::from_scaled_float(val),
883                    1 << ($bits - 2),
884                    false,
885                    "check -0.5"
886                );
887                let val: $float = 0.5;
888                assert_conversion_eq!(
889                    $int::from_scaled_float(val),
890                    $int::MAX - (1 << ($bits - 2)) + 1,
891                    false,
892                    "check 0.5"
893                );
894                let val: $float = 1.1;
895                assert_conversion_eq!(
896                    $int::from_scaled_float(val),
897                    $int::MAX,
898                    true,
899                    "clipped positive"
900                );
901                let val: $float = -1.1;
902                assert_conversion_eq!(
903                    $int::from_scaled_float(val),
904                    $int::MIN,
905                    true,
906                    "clipped negative"
907                );
908            }
909        };
910    }
911
912    test_to_signed_int!(convert_f32_to_i8, f32, i8, 8);
913    test_to_signed_int!(convert_642_to_i8, f64, i8, 8);
914    test_to_signed_int!(convert_f32_to_i16, f32, i16, 16);
915    test_to_signed_int!(convert_f64_to_i16, f64, i16, 16);
916    test_to_signed_int!(convert_f32_to_i32, f32, i32, 32);
917    test_to_signed_int!(convert_f64_to_i32, f64, i32, 32);
918    test_to_signed_int!(convert_f32_to_i64, f32, i64, 64);
919    test_to_signed_int!(convert_f64_to_i64, f64, i64, 64);
920
921    test_to_unsigned_int!(convert_f32_to_u8, f32, u8, 8);
922    test_to_unsigned_int!(convert_f64_to_u8, f64, u8, 8);
923    test_to_unsigned_int!(convert_f32_to_u16, f32, u16, 16);
924    test_to_unsigned_int!(convert_f64_to_u16, f64, u16, 16);
925    test_to_unsigned_int!(convert_f32_to_u32, f32, u32, 32);
926    test_to_unsigned_int!(convert_f64_to_u32, f64, u32, 32);
927    test_to_unsigned_int!(convert_f32_to_u64, f32, u64, 64);
928    test_to_unsigned_int!(convert_f64_to_u64, f64, u64, 64);
929
930    macro_rules! test_from_signed_int {
931        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
932            #[test]
933            fn $fname() {
934                let val: $int = -1 << ($bits - 2);
935                assert_eq!(val.to_scaled_float::<$float>(), -0.5, "check -0.5");
936                let val: $int = 1 << ($bits - 2);
937                assert_eq!(val.to_scaled_float::<$float>(), 0.5, "check 0.5");
938                let val: $int = $int::MIN;
939                assert_eq!(val.to_scaled_float::<$float>(), -1.0, "negative limit");
940            }
941        };
942    }
943
944    macro_rules! test_from_unsigned_int {
945        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
946            #[test]
947            fn $fname() {
948                let val: $int = 1 << ($bits - 2);
949                assert_eq!(val.to_scaled_float::<$float>(), -0.5, "check -0.5");
950                let val: $int = $int::MAX - (1 << ($bits - 2)) + 1;
951                assert_eq!(val.to_scaled_float::<$float>(), 0.5, "check 0.5");
952                let val: $int = 0;
953                assert_eq!(val.to_scaled_float::<$float>(), -1.0, "negative limit");
954            }
955        };
956    }
957
958    test_from_signed_int!(convert_f32_from_i8, f32, i8, 8);
959    test_from_signed_int!(convert_f64_from_i8, f64, i8, 8);
960    test_from_signed_int!(convert_f32_from_i16, f32, i16, 16);
961    test_from_signed_int!(convert_f64_from_i16, f64, i16, 16);
962    test_from_signed_int!(convert_f32_from_i32, f32, i32, 32);
963    test_from_signed_int!(convert_f64_from_i32, f64, i32, 32);
964    test_from_signed_int!(convert_f32_from_i64, f32, i64, 64);
965    test_from_signed_int!(convert_f64_from_i64, f64, i64, 64);
966
967    test_from_unsigned_int!(convert_f32_from_u8, f32, u8, 8);
968    test_from_unsigned_int!(convert_f64_from_u8, f64, u8, 8);
969    test_from_unsigned_int!(convert_f32_from_u16, f32, u16, 16);
970    test_from_unsigned_int!(convert_f64_from_u16, f64, u16, 16);
971    test_from_unsigned_int!(convert_f32_from_u32, f32, u32, 32);
972    test_from_unsigned_int!(convert_f64_from_u32, f64, u32, 32);
973    test_from_unsigned_int!(convert_f32_from_u64, f32, u64, 64);
974    test_from_unsigned_int!(convert_f64_from_u64, f64, u64, 64);
975
976    #[test]
977    fn test_to_clamped_int() {
978        let converted = to_clamped_int::<f32, i32>(12345.0, Some(12345));
979        assert_conversion_eq!(converted, 12345, false, "in range f32 i32");
980
981        let converted = to_clamped_int::<f32, i32>(1.0e10, None);
982        assert_conversion_eq!(converted, i32::MAX, true, "above range f32 i32");
983
984        let converted = to_clamped_int::<f32, i32>(-1.0e10, None);
985        assert_conversion_eq!(converted, i32::MIN, true, "below range f32 i32");
986
987        let converted = to_clamped_int::<f64, i32>(12345.0, Some(12345));
988        assert_conversion_eq!(converted, 12345, false, "in range f64 i32");
989
990        let converted = to_clamped_int::<f64, i32>(1.0e10, None);
991        assert_conversion_eq!(converted, i32::MAX, true, "above range f64 i32");
992
993        let converted = to_clamped_int::<f64, i32>(-1.0e10, None);
994        assert_conversion_eq!(converted, i32::MIN, true, "below range f64 i32");
995    }
996
997    #[test]
998    fn test_to_clamped_uint() {
999        let converted = to_clamped_int::<f32, u32>(12345.0, Some(12345));
1000        assert_conversion_eq!(converted, 12345, false, "in range f32 u32");
1001
1002        let converted = to_clamped_int::<f32, u32>(1.0e10, None);
1003        assert_conversion_eq!(converted, u32::MAX, true, "above range f32 u32");
1004
1005        let converted = to_clamped_int::<f32, u32>(-1.0, None);
1006        assert_conversion_eq!(converted, u32::MIN, true, "below range f32 u32");
1007
1008        let converted = to_clamped_int::<f64, u32>(12345.0, Some(12345));
1009        assert_conversion_eq!(converted, 12345, false, "in range f64 u32");
1010
1011        let converted = to_clamped_int::<f64, u32>(1.0e10, None);
1012        assert_conversion_eq!(converted, u32::MAX, true, "above range f64 u32");
1013
1014        let converted = to_clamped_int::<f64, u32>(-1.0, None);
1015        assert_conversion_eq!(converted, u32::MIN, true, "below range f64 u32");
1016    }
1017
1018    macro_rules! test_simple_int_bytes {
1019        ($fname:ident, $number:ty, $wrapper:ident, $to_bytes_fn:ident) => {
1020            #[test]
1021            #[allow(non_snake_case)]
1022            fn $fname() {
1023                let number: $number = <$number>::MAX / 5 * 4;
1024                let wrapped = $wrapper(number.$to_bytes_fn());
1025                assert_eq!(number, wrapped.to_number());
1026            }
1027        };
1028    }
1029
1030    macro_rules! test_float_bytes {
1031        ($fname:ident, $number:ty, $wrapper:ident, $to_bytes_fn:ident) => {
1032            #[test]
1033            #[allow(non_snake_case)]
1034            fn $fname() {
1035                let number: $number = 12345.0;
1036                let wrapped = $wrapper(number.$to_bytes_fn());
1037                assert_eq!(number, wrapped.to_number());
1038            }
1039        };
1040    }
1041
1042    test_simple_int_bytes!(convert_i16_from_I16_LE, i16, I16_LE, to_le_bytes);
1043    test_simple_int_bytes!(convert_i16_from_I16_BE, i16, I16_BE, to_be_bytes);
1044    test_simple_int_bytes!(convert_i32_from_I32_LE, i32, I32_LE, to_le_bytes);
1045    test_simple_int_bytes!(convert_i32_from_I32_BE, i32, I32_BE, to_be_bytes);
1046    test_simple_int_bytes!(convert_i64_from_I64_LE, i64, I64_LE, to_le_bytes);
1047    test_simple_int_bytes!(convert_i64_from_I64_BE, i64, I64_BE, to_be_bytes);
1048
1049    test_simple_int_bytes!(convert_u16_from_U16_LE, u16, U16_LE, to_le_bytes);
1050    test_simple_int_bytes!(convert_u16_from_U16_BE, u16, U16_BE, to_be_bytes);
1051    test_simple_int_bytes!(convert_u32_from_U32_LE, u32, U32_LE, to_le_bytes);
1052    test_simple_int_bytes!(convert_u32_from_U32_BE, u32, U32_BE, to_be_bytes);
1053    test_simple_int_bytes!(convert_u64_from_U64_LE, u64, U64_LE, to_le_bytes);
1054    test_simple_int_bytes!(convert_u64_from_U64_BE, u64, U64_BE, to_be_bytes);
1055
1056    test_float_bytes!(convert_f32_fom_F32_LE, f32, F32_LE, to_le_bytes);
1057    test_float_bytes!(convert_f32_fom_F32_BE, f32, F32_BE, to_be_bytes);
1058    test_float_bytes!(convert_f64_fom_F64_LE, f64, F64_LE, to_le_bytes);
1059    test_float_bytes!(convert_f64_fom_F64_BE, f64, F64_BE, to_be_bytes);
1060
1061    #[test]
1062    #[allow(non_snake_case)]
1063    fn test_I8() {
1064        assert_eq!(I8::BYTES_PER_SAMPLE, 1);
1065        assert_eq!(I8::zero().to_number(), 0);
1066        assert_eq!(I8::from_slice(&[0x80]).to_number(), i8::MIN);
1067
1068        for number in [0, 1, -1, 100, i8::MIN, i8::MAX] {
1069            let wrapped = I8::from_number(number);
1070            assert_eq!(
1071                wrapped.as_slice(),
1072                number.to_le_bytes(),
1073                "bytes for {number}"
1074            );
1075            assert_eq!(wrapped.to_number(), number, "roundtrip of {number}");
1076        }
1077    }
1078
1079    #[test]
1080    #[allow(non_snake_case)]
1081    fn test_U8() {
1082        assert_eq!(U8::BYTES_PER_SAMPLE, 1);
1083        assert_eq!(U8::zero().to_number(), 0);
1084        assert_eq!(U8::from_slice(&[0x80]).to_number(), 128);
1085
1086        for number in [0, 1, 128, 200, u8::MAX] {
1087            let wrapped = U8::from_number(number);
1088            assert_eq!(
1089                wrapped.as_slice(),
1090                number.to_le_bytes(),
1091                "bytes for {number}"
1092            );
1093            assert_eq!(wrapped.to_number(), number, "roundtrip of {number}");
1094        }
1095    }
1096
1097    #[test]
1098    #[allow(non_snake_case)]
1099    fn convert_I8_to_and_from_float() {
1100        assert_eq!(I8::from_slice(&[0]).to_scaled_float::<f32>(), 0.0);
1101        assert_eq!(I8::from_slice(&[0x80]).to_scaled_float::<f32>(), -1.0);
1102        assert_eq!(I8::from_slice(&[0x40]).to_scaled_float::<f32>(), 0.5);
1103        assert_eq!(I8::from_slice(&[0xC0]).to_scaled_float::<f32>(), -0.5);
1104
1105        let converted = I8::from_scaled_float(0.5f32);
1106        assert_eq!(converted.value.as_slice(), [0x40]);
1107        assert!(!converted.clipped);
1108
1109        let converted = I8::from_scaled_float(-1.0f32);
1110        assert_eq!(converted.value.as_slice(), [0x80]);
1111        assert!(!converted.clipped);
1112
1113        // Values outside -1.0 .. +1.0 clip at the limits of an i8.
1114        let converted = I8::from_scaled_float(1.5f32);
1115        assert_eq!(converted.value.to_number(), i8::MAX);
1116        assert!(converted.clipped);
1117
1118        let converted = I8::from_scaled_float(-1.5f32);
1119        assert_eq!(converted.value.to_number(), i8::MIN);
1120        assert!(converted.clipped);
1121    }
1122
1123    #[test]
1124    #[allow(non_snake_case)]
1125    fn convert_U8_to_and_from_float() {
1126        // Unsigned samples are centered at 128.
1127        assert_eq!(U8::from_slice(&[128]).to_scaled_float::<f32>(), 0.0);
1128        assert_eq!(U8::from_slice(&[0]).to_scaled_float::<f32>(), -1.0);
1129        assert_eq!(U8::from_slice(&[192]).to_scaled_float::<f32>(), 0.5);
1130        assert_eq!(U8::from_slice(&[64]).to_scaled_float::<f32>(), -0.5);
1131
1132        let converted = U8::from_scaled_float(0.5f32);
1133        assert_eq!(converted.value.as_slice(), [192]);
1134        assert!(!converted.clipped);
1135
1136        let converted = U8::from_scaled_float(-1.0f32);
1137        assert_eq!(converted.value.as_slice(), [0]);
1138        assert!(!converted.clipped);
1139
1140        // Values outside -1.0 .. +1.0 clip at the limits of a u8.
1141        let converted = U8::from_scaled_float(1.5f32);
1142        assert_eq!(converted.value.to_number(), u8::MAX);
1143        assert!(converted.clipped);
1144
1145        let converted = U8::from_scaled_float(-1.5f32);
1146        assert_eq!(converted.value.to_number(), u8::MIN);
1147        assert!(converted.clipped);
1148    }
1149
1150    #[test]
1151    #[allow(non_snake_case)]
1152    fn test_I24_LE() {
1153        let number = i32::MAX / 5 * 4;
1154
1155        // make sure LSB is zero
1156        let number = number >> 8;
1157        let number = number << 8;
1158
1159        let allbytes = number.to_le_bytes();
1160        // Little-endian stores the LSB at the smallest address.
1161        // Drop the LSB!
1162        let bytes = [allbytes[1], allbytes[2], allbytes[3]];
1163
1164        let wrapped = I24_LE(bytes);
1165        assert_eq!(number, wrapped.to_number());
1166    }
1167
1168    #[test]
1169    #[allow(non_snake_case)]
1170    fn test_I24_BE() {
1171        let number = i32::MAX / 5 * 4;
1172
1173        // make sure LSB is zero
1174        let number = number >> 8;
1175        let number = number << 8;
1176
1177        let allbytes = number.to_be_bytes();
1178        // Big-endian stores the LSB at the largest address.
1179        // Drop the LSB!
1180        let bytes = [allbytes[0], allbytes[1], allbytes[2]];
1181
1182        let wrapped = I24_BE(bytes);
1183        assert_eq!(number, wrapped.to_number());
1184    }
1185
1186    #[test]
1187    #[allow(non_snake_case)]
1188    fn test_I24_4RJ_LE() {
1189        let number = i32::MAX / 5 * 4;
1190
1191        // make sure LSB is zero
1192        let number = number >> 8;
1193        let number = number << 8;
1194
1195        let allbytes = number.to_le_bytes();
1196        // Little-endian stores the LSB at the smallest address.
1197        // Drop the LSB and insert padding at MSB!
1198        let bytes = [allbytes[1], allbytes[2], allbytes[3], 0];
1199
1200        let wrapped = I24_4RJ_LE(bytes);
1201        assert_eq!(number, wrapped.to_number());
1202    }
1203
1204    #[test]
1205    #[allow(non_snake_case)]
1206    fn test_I24_4RJ_BE() {
1207        let number = i32::MAX / 5 * 4;
1208
1209        // make sure LSB is zero
1210        let number = number >> 8;
1211        let number = number << 8;
1212
1213        let allbytes = number.to_be_bytes();
1214        // Big-endian stores the LSB at the largest address.
1215        // Drop the LSB and insert padding at MSB!
1216        let bytes = [0, allbytes[0], allbytes[1], allbytes[2]];
1217
1218        let wrapped = I24_4RJ_BE(bytes);
1219        assert_eq!(number, wrapped.to_number());
1220    }
1221
1222    #[test]
1223    #[allow(non_snake_case)]
1224    fn test_I24_4LJ_LE() {
1225        let number = i32::MAX / 5 * 4;
1226
1227        // make sure LSB is zero
1228        let number = number >> 8;
1229        let number = number << 8;
1230
1231        let allbytes = number.to_le_bytes();
1232        // Little-endian stores the LSB at the smallest address.
1233        // Put a zero at LSB and keep the rest unchanged.
1234        let bytes = [0, allbytes[1], allbytes[2], allbytes[3]];
1235
1236        let wrapped = I24_4LJ_LE(bytes);
1237        assert_eq!(number, wrapped.to_number());
1238    }
1239
1240    #[test]
1241    #[allow(non_snake_case)]
1242    fn test_I24_4LJ_BE() {
1243        let number = i32::MAX / 5 * 4;
1244
1245        // make sure LSB is zero
1246        let number = number >> 8;
1247        let number = number << 8;
1248
1249        let allbytes = number.to_be_bytes();
1250        // Big-endian stores the LSB at the largest address.
1251        // Put a zero at LSB and keep the rest unchanged.
1252        let bytes = [allbytes[0], allbytes[1], allbytes[2], 0];
1253
1254        let wrapped = I24_4LJ_BE(bytes);
1255        assert_eq!(number, wrapped.to_number());
1256    }
1257
1258    #[test]
1259    #[allow(non_snake_case)]
1260    fn test_U24_LE() {
1261        let number = u32::MAX / 5 * 4;
1262
1263        // make sure LSB is zero
1264        let number = number >> 8;
1265        let number = number << 8;
1266
1267        let allbytes = number.to_le_bytes();
1268        // Little-endian stores the LSB at the smallest address.
1269        // Drop the LSB!
1270        let bytes = [allbytes[1], allbytes[2], allbytes[3]];
1271
1272        let wrapped = U24_LE(bytes);
1273        assert_eq!(number, wrapped.to_number());
1274    }
1275
1276    #[test]
1277    #[allow(non_snake_case)]
1278    fn test_U24_BE() {
1279        let number = u32::MAX / 5 * 4;
1280
1281        // make sure LSB is zero
1282        let number = number >> 8;
1283        let number = number << 8;
1284
1285        let allbytes = number.to_be_bytes();
1286        // Big-endian stores the LSB at the largest address.
1287        // Drop the LSB!
1288        let bytes = [allbytes[0], allbytes[1], allbytes[2]];
1289
1290        let wrapped = U24_BE(bytes);
1291        assert_eq!(number, wrapped.to_number());
1292    }
1293
1294    #[test]
1295    #[allow(non_snake_case)]
1296    fn test_U24_4RJ_LE() {
1297        let number = u32::MAX / 5 * 4;
1298
1299        // make sure LSB is zero
1300        let number = number >> 8;
1301        let number = number << 8;
1302
1303        let allbytes = number.to_le_bytes();
1304        // Little-endian stores the LSB at the smallest address.
1305        // Drop the LSB and insert padding at MSB!
1306        let bytes = [allbytes[1], allbytes[2], allbytes[3], 0];
1307
1308        let wrapped = U24_4RJ_LE(bytes);
1309        assert_eq!(number, wrapped.to_number());
1310    }
1311
1312    #[test]
1313    #[allow(non_snake_case)]
1314    fn test_U24_4RJ_BE() {
1315        let number = u32::MAX / 5 * 4;
1316
1317        // make sure LSB is zero
1318        let number = number >> 8;
1319        let number = number << 8;
1320
1321        let allbytes = number.to_be_bytes();
1322        // Big-endian stores the LSB at the largest address.
1323        // Drop the LSB and insert padding at MSB!
1324        let bytes = [0, allbytes[0], allbytes[1], allbytes[2]];
1325
1326        let wrapped = U24_4RJ_BE(bytes);
1327        assert_eq!(number, wrapped.to_number());
1328    }
1329
1330    #[test]
1331    #[allow(non_snake_case)]
1332    fn test_U24_4LJ_LE() {
1333        let number = u32::MAX / 5 * 4;
1334
1335        // make sure LSB is zero
1336        let number = number >> 8;
1337        let number = number << 8;
1338
1339        let allbytes = number.to_le_bytes();
1340        // Little-endian stores the LSB at the smallest address.
1341        // Put a zero at LSB and keep the rest unchanged.
1342        let bytes = [0, allbytes[1], allbytes[2], allbytes[3]];
1343
1344        let wrapped = U24_4LJ_LE(bytes);
1345        assert_eq!(number, wrapped.to_number());
1346    }
1347
1348    #[test]
1349    #[allow(non_snake_case)]
1350    fn test_U24_4LJ_BE() {
1351        let number = u32::MAX / 5 * 4;
1352
1353        // make sure LSB is zero
1354        let number = number >> 8;
1355        let number = number << 8;
1356
1357        let allbytes = number.to_be_bytes();
1358        // Big-endian stores the LSB at the largest address.
1359        // Put a zero at LSB and keep the rest unchanged.
1360        let bytes = [allbytes[0], allbytes[1], allbytes[2], 0];
1361
1362        let wrapped = U24_4LJ_BE(bytes);
1363        assert_eq!(number, wrapped.to_number());
1364    }
1365}