irox_bits/
codec.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2025 IROX Contributors
3//
4
5//!
6//! Bits encoding and decoding functions
7
8use crate::{Bits, BitsWrapper, Error, MutBits};
9
10/// Splits the input into two equal sized arrays.
11pub const fn array_concat_1(a: [u8; 1], b: [u8; 1]) -> [u8; 2] {
12    let [a] = a;
13    let [b] = b;
14    [a, b]
15}
16/// Splits the input into two equal sized arrays.
17pub const fn array_split_1(a: [u8; 2]) -> ([u8; 1], [u8; 1]) {
18    let [a, b] = a;
19    ([a], [b])
20}
21/// Splits the input into two equal sized arrays.
22pub const fn array_concat_2(a: [u8; 2], b: [u8; 2]) -> [u8; 4] {
23    let [c, d] = b;
24    let [a, b] = a;
25    [a, b, c, d]
26}
27/// Splits the input into two equal sized arrays.
28pub const fn array_split_2(a: [u8; 4]) -> ([u8; 2], [u8; 2]) {
29    let [a, b, c, d] = a;
30    ([a, b], [c, d])
31}
32/// Splits the input into two equal sized arrays.
33pub const fn array_concat_4(a: [u8; 4], b: [u8; 4]) -> [u8; 8] {
34    let [e, f, g, h] = b;
35    let [a, b, c, d] = a;
36    [a, b, c, d, e, f, g, h]
37}
38/// Splits the input into two equal sized arrays.
39pub const fn array_split_4(a: [u8; 8]) -> ([u8; 4], [u8; 4]) {
40    let [a, b, c, d, e, f, g, h] = a;
41    ([a, b, c, d], [e, f, g, h])
42}
43/// Splits the input into two equal sized arrays.
44pub const fn array_concat_8(a: [u8; 8], b: [u8; 8]) -> [u8; 16] {
45    let [i, j, k, l, m, n, o, p] = b;
46    let [a, b, c, d, e, f, g, h] = a;
47    [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p]
48}
49/// Splits the input into two equal sized arrays.
50pub const fn array_split_8(a: [u8; 16]) -> ([u8; 8], [u8; 8]) {
51    let [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = a;
52    ([a, b, c, d, e, f, g, h], [i, j, k, l, m, n, o, p])
53}
54/// Splits the input into two equal sized arrays.
55pub const fn array_concat_16(a: [u8; 16], b: [u8; 16]) -> [u8; 32] {
56    let [q, r, s, t, u, v, w, x, y, z, aa, ab, ac, ad, ae, af] = b;
57    let [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = a;
58    [
59        a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, ab, ac,
60        ad, ae, af,
61    ]
62}
63/// Splits the input into two equal sized arrays.
64pub const fn array_split_16(a: [u8; 32]) -> ([u8; 16], [u8; 16]) {
65    let [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, ab, ac, ad, ae, af] =
66        a;
67    (
68        [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p],
69        [q, r, s, t, u, v, w, x, y, z, aa, ab, ac, ad, ae, af],
70    )
71}
72/// Converts the value into a constant number of bytes
73pub trait ToBEBytes<const N: usize> {
74    fn to_be_bytes(&self) -> [u8; N];
75}
76/// Converts to the value from a constant number of bytes
77pub trait FromBEBytes<const N: usize> {
78    fn from_be_bytes(bytes: [u8; N]) -> Self;
79}
80/// Converts the value into a constant number of bytes
81pub trait ToLEBytes<const N: usize> {
82    fn to_le_bytes(&self) -> [u8; N];
83}
84/// Converts to the value from a constant number of bytes
85pub trait FromLEBytes<const N: usize> {
86    fn from_le_bytes(bytes: [u8; N]) -> Self;
87}
88
89macro_rules! impl_codecs {
90    ($ty:ty, $len:literal, $len2:literal, $arrsplit:ident, $arrconcat:ident, $writebe:ident, $readbe:ident, $writele:ident, $readle:ident) => {
91        impl ToBEBytes<$len> for $ty {
92            fn to_be_bytes(&self) -> [u8; $len] {
93                <$ty>::to_be_bytes(*self)
94            }
95        }
96        impl FromBEBytes<$len> for $ty {
97            fn from_be_bytes(bytes: [u8; $len]) -> $ty {
98                <$ty>::from_be_bytes(bytes)
99            }
100        }
101
102        impl ToLEBytes<$len> for $ty {
103            fn to_le_bytes(&self) -> [u8; $len] {
104                <$ty>::to_le_bytes(*self)
105            }
106        }
107        impl FromLEBytes<$len> for $ty {
108            fn from_le_bytes(bytes: [u8; $len]) -> Self {
109                <$ty>::from_le_bytes(bytes)
110            }
111        }
112        impl WriteToBEBits for $ty {
113            fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
114                bits.$writebe(*self)?;
115                Ok($len)
116            }
117        }
118        impl WriteToLEBits for $ty {
119            fn write_le_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
120                bits.$writele(*self)?;
121                Ok($len)
122            }
123        }
124        impl ReadFromBEBits for $ty {
125            fn read_from_be_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
126                inp.$readbe()
127            }
128        }
129        impl ReadFromLEBits for $ty {
130            fn read_from_le_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
131                inp.$readle()
132            }
133        }
134
135        impl ToBEBytes<$len2> for [$ty; 2] {
136            fn to_be_bytes(&self) -> [u8; $len2] {
137                let [a, b] = *self;
138                $arrconcat(<$ty>::to_be_bytes(a), <$ty>::to_be_bytes(b))
139            }
140        }
141        impl ToLEBytes<$len2> for [$ty; 2] {
142            fn to_le_bytes(&self) -> [u8; $len2] {
143                let [a, b] = *self;
144                $arrconcat(<$ty>::to_le_bytes(a), <$ty>::to_le_bytes(b))
145            }
146        }
147        impl FromBEBytes<$len2> for [$ty; 2] {
148            fn from_be_bytes(bytes: [u8; $len2]) -> Self {
149                let (a, b) = $arrsplit(bytes);
150                [<$ty>::from_be_bytes(a), <$ty>::from_be_bytes(b)]
151            }
152        }
153        impl FromLEBytes<$len2> for [$ty; 2] {
154            fn from_le_bytes(bytes: [u8; $len2]) -> Self {
155                let (a, b) = $arrsplit(bytes);
156                [<$ty>::from_le_bytes(a), <$ty>::from_le_bytes(b)]
157            }
158        }
159    };
160}
161impl_codecs!(
162    u8,
163    1,
164    2,
165    array_split_1,
166    array_concat_1,
167    write_u8,
168    read_u8,
169    write_u8,
170    read_u8
171);
172impl_codecs!(
173    i8,
174    1,
175    2,
176    array_split_1,
177    array_concat_1,
178    write_i8,
179    read_i8,
180    write_i8,
181    read_i8
182);
183impl_codecs!(
184    u16,
185    2,
186    4,
187    array_split_2,
188    array_concat_2,
189    write_be_u16,
190    read_be_u16,
191    write_le_u16,
192    read_le_u16
193);
194impl_codecs!(
195    i16,
196    2,
197    4,
198    array_split_2,
199    array_concat_2,
200    write_be_i16,
201    read_be_i16,
202    write_le_i16,
203    read_le_i16
204);
205impl_codecs!(
206    u32,
207    4,
208    8,
209    array_split_4,
210    array_concat_4,
211    write_be_u32,
212    read_be_u32,
213    write_le_u32,
214    read_le_u32
215);
216impl_codecs!(
217    i32,
218    4,
219    8,
220    array_split_4,
221    array_concat_4,
222    write_be_i32,
223    read_be_i32,
224    write_le_i32,
225    read_le_i32
226);
227impl_codecs!(
228    f32,
229    4,
230    8,
231    array_split_4,
232    array_concat_4,
233    write_be_f32,
234    read_be_f32,
235    write_le_f32,
236    read_le_f32
237);
238impl_codecs!(
239    u64,
240    8,
241    16,
242    array_split_8,
243    array_concat_8,
244    write_be_u64,
245    read_be_u64,
246    write_le_u64,
247    read_le_u64
248);
249impl_codecs!(
250    i64,
251    8,
252    16,
253    array_split_8,
254    array_concat_8,
255    write_be_i64,
256    read_be_i64,
257    write_le_i64,
258    read_le_i64
259);
260impl_codecs!(
261    f64,
262    8,
263    16,
264    array_split_8,
265    array_concat_8,
266    write_be_f64,
267    read_be_f64,
268    write_le_f64,
269    read_le_f64
270);
271impl_codecs!(
272    u128,
273    16,
274    32,
275    array_split_16,
276    array_concat_16,
277    write_be_u128,
278    read_le_u128,
279    write_le_u128,
280    read_le_u128
281);
282impl_codecs!(
283    i128,
284    16,
285    32,
286    array_split_16,
287    array_concat_16,
288    write_be_i128,
289    read_le_i128,
290    write_le_i128,
291    read_le_i128
292);
293
294macro_rules! impl_large_array {
295    ($ty:ty, $len:literal, $len2:literal, $writebe:ident, $writele:ident, $nextbe:ident, $nextle:ident) => {
296        impl ToBEBytes<$len2> for [$ty; $len] {
297            fn to_be_bytes(&self) -> [u8; $len2] {
298                let mut out = [0u8; $len2];
299                let mut wr = BitsWrapper::Owned(out.as_mut_slice());
300                for v in self {
301                    let _ = wr.$writebe(*v);
302                }
303                out
304            }
305        }
306        impl ToLEBytes<$len2> for [$ty; $len] {
307            fn to_le_bytes(&self) -> [u8; $len2] {
308                let mut out = [0u8; $len2];
309                let mut wr = BitsWrapper::Owned(out.as_mut_slice());
310                for v in self {
311                    let _ = wr.$writele(*v);
312                }
313                out
314            }
315        }
316        impl FromBEBytes<$len2> for [$ty; $len] {
317            fn from_be_bytes(bytes: [u8; $len2]) -> Self {
318                let mut out = [0; $len];
319                let mut rd = BitsWrapper::Owned(bytes.as_ref());
320                for v in out.iter_mut() {
321                    let Ok(Some(a)) = rd.$nextbe() else {
322                        break;
323                    };
324                    *v = a;
325                }
326                out
327            }
328        }
329        impl FromLEBytes<$len2> for [$ty; $len] {
330            fn from_le_bytes(bytes: [u8; $len2]) -> Self {
331                let mut out = [0; $len];
332                let mut rd = BitsWrapper::Owned(bytes.as_ref());
333                for v in out.iter_mut() {
334                    let Ok(Some(a)) = rd.$nextle() else {
335                        break;
336                    };
337                    *v = a;
338                }
339                out
340            }
341        }
342    };
343}
344impl_large_array!(
345    u32,
346    3,
347    12,
348    write_be_u32,
349    write_le_u32,
350    next_be_u32,
351    next_le_u32
352); // 96 bit
353impl_large_array!(
354    u32,
355    4,
356    16,
357    write_be_u32,
358    write_le_u32,
359    next_be_u32,
360    next_le_u32
361); // 128 bit
362impl_large_array!(
363    u32,
364    5,
365    20,
366    write_be_u32,
367    write_le_u32,
368    next_be_u32,
369    next_le_u32
370); // 160 bit
371impl_large_array!(
372    u32,
373    6,
374    24,
375    write_be_u32,
376    write_le_u32,
377    next_be_u32,
378    next_le_u32
379); // 192 bit
380impl_large_array!(
381    u32,
382    7,
383    28,
384    write_be_u32,
385    write_le_u32,
386    next_be_u32,
387    next_le_u32
388); // 224 bit
389impl_large_array!(
390    u32,
391    8,
392    32,
393    write_be_u32,
394    write_le_u32,
395    next_be_u32,
396    next_le_u32
397); // 256 bit
398impl_large_array!(
399    u32,
400    9,
401    36,
402    write_be_u32,
403    write_le_u32,
404    next_be_u32,
405    next_le_u32
406); // 288 bit
407impl_large_array!(
408    u32,
409    10,
410    40,
411    write_be_u32,
412    write_le_u32,
413    next_be_u32,
414    next_le_u32
415); // 320 bit
416impl_large_array!(
417    u32,
418    11,
419    44,
420    write_be_u32,
421    write_le_u32,
422    next_be_u32,
423    next_le_u32
424); // 352 bit
425impl_large_array!(
426    u32,
427    12,
428    48,
429    write_be_u32,
430    write_le_u32,
431    next_be_u32,
432    next_le_u32
433); // 384 bit
434
435impl_large_array!(
436    u64,
437    3,
438    24,
439    write_be_u64,
440    write_le_u64,
441    next_be_u64,
442    next_le_u64
443); // 192 bit
444impl_large_array!(
445    u64,
446    4,
447    32,
448    write_be_u64,
449    write_le_u64,
450    next_be_u64,
451    next_le_u64
452); // 256 bit
453impl_large_array!(
454    u64,
455    5,
456    40,
457    write_be_u64,
458    write_le_u64,
459    next_be_u64,
460    next_le_u64
461); // 320 bit
462impl_large_array!(
463    u64,
464    6,
465    48,
466    write_be_u64,
467    write_le_u64,
468    next_be_u64,
469    next_le_u64
470); // 384 bit
471impl_large_array!(
472    u64,
473    7,
474    56,
475    write_be_u64,
476    write_le_u64,
477    next_be_u64,
478    next_le_u64
479); // 448 bit
480impl_large_array!(
481    u64,
482    8,
483    64,
484    write_be_u64,
485    write_le_u64,
486    next_be_u64,
487    next_le_u64
488); // 512 bit
489impl_large_array!(
490    u64,
491    9,
492    72,
493    write_be_u64,
494    write_le_u64,
495    next_be_u64,
496    next_le_u64
497); // 576 bit
498impl_large_array!(
499    u64,
500    10,
501    80,
502    write_be_u64,
503    write_le_u64,
504    next_be_u64,
505    next_le_u64
506); // 640 bit
507impl_large_array!(
508    u64,
509    11,
510    88,
511    write_be_u64,
512    write_le_u64,
513    next_be_u64,
514    next_le_u64
515); // 704 bit
516impl_large_array!(
517    u64,
518    12,
519    96,
520    write_be_u64,
521    write_le_u64,
522    next_be_u64,
523    next_le_u64
524); // 768 bit
525
526impl_large_array!(
527    u128,
528    3,
529    48,
530    write_be_u128,
531    write_le_u128,
532    next_be_u128,
533    next_le_u128
534); // 384 bit
535impl_large_array!(
536    u128,
537    4,
538    64,
539    write_be_u128,
540    write_le_u128,
541    next_be_u128,
542    next_le_u128
543); // 512 bit
544impl_large_array!(
545    u128,
546    5,
547    80,
548    write_be_u128,
549    write_le_u128,
550    next_be_u128,
551    next_le_u128
552); // 640 bit
553impl_large_array!(
554    u128,
555    6,
556    96,
557    write_be_u128,
558    write_le_u128,
559    next_be_u128,
560    next_le_u128
561); // 768 bit
562impl_large_array!(
563    u128,
564    7,
565    112,
566    write_be_u128,
567    write_le_u128,
568    next_be_u128,
569    next_le_u128
570); // 896 bit
571impl_large_array!(
572    u128,
573    8,
574    128,
575    write_be_u128,
576    write_le_u128,
577    next_be_u128,
578    next_le_u128
579); // 1024 bit
580impl_large_array!(
581    u128,
582    9,
583    144,
584    write_be_u128,
585    write_le_u128,
586    next_be_u128,
587    next_le_u128
588); // 1152 bit
589impl_large_array!(
590    u128,
591    10,
592    160,
593    write_be_u128,
594    write_le_u128,
595    next_be_u128,
596    next_le_u128
597); // 1280 bit
598impl_large_array!(
599    u128,
600    11,
601    176,
602    write_be_u128,
603    write_le_u128,
604    next_be_u128,
605    next_le_u128
606); // 1408 bit
607impl_large_array!(
608    u128,
609    12,
610    192,
611    write_be_u128,
612    write_le_u128,
613    next_be_u128,
614    next_le_u128
615); // 1536 bit
616
617/// Writes 'self' to the provided [`MutBits`] impl in big endian order.
618pub trait WriteToBEBits {
619    fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error>;
620}
621/// Writes 'self' to the provided [`MutBits`] impl in little endian order.
622pub trait WriteToLEBits {
623    fn write_le_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error>;
624}
625
626pub trait ReadFromBEBits: Sized {
627    fn read_from_be_bits<T: Bits>(inp: &mut T) -> Result<Self, Error>;
628}
629pub trait ReadFromLEBits: Sized {
630    fn read_from_le_bits<T: Bits>(inp: &mut T) -> Result<Self, Error>;
631}
632impl<const N: usize> ReadFromBEBits for [u8; N] {
633    fn read_from_be_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
634        let mut out = [0; N];
635        inp.read_all_into(&mut out.as_mut_slice())?;
636        Ok(out)
637    }
638}
639impl<const N: usize> ReadFromLEBits for [u8; N] {
640    fn read_from_le_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
641        let mut out = [0; N];
642        inp.read_all_into(&mut out.as_mut_slice())?;
643        Ok(out)
644    }
645}
646
647/// compile time u64x2 to u128 conversion
648pub const fn u64_to_u128(val: [u64; 2]) -> u128 {
649    let [a, b] = val;
650    u128::from_be_bytes(array_concat_8(u64::to_be_bytes(a), u64::to_be_bytes(b)))
651}
652/// compile time u32x2 to u64 conversion
653pub const fn u32_to_u64(val: [u32; 2]) -> u64 {
654    let [a, b] = val;
655    u64::from_be_bytes(array_concat_4(u32::to_be_bytes(a), u32::to_be_bytes(b)))
656}
657/// compile time u32x4 to u128 conversion
658pub const fn u32_to_u128(val: [u32; 4]) -> u128 {
659    let [a, b, c, d] = val;
660    u64_to_u128([u32_to_u64([a, b]), u32_to_u64([c, d])])
661}
662/// compile time u16x2 to u32 conversion
663pub const fn u16_to_u32(val: [u16; 2]) -> u32 {
664    let [a, b] = val;
665    u32::from_be_bytes(array_concat_2(u16::to_be_bytes(a), u16::to_be_bytes(b)))
666}
667/// compile time u16 to u64 conversion
668pub const fn u16_to_u64(val: [u16; 4]) -> u64 {
669    let [a, b, c, d] = val;
670    u32_to_u64([u16_to_u32([a, b]), u16_to_u32([c, d])])
671}
672/// compile time u16 to u128 conversion
673pub const fn u16_to_u128(val: [u16; 8]) -> u128 {
674    let [a, b, c, d, e, f, g, h] = val;
675    u64_to_u128([u16_to_u64([a, b, c, d]), u16_to_u64([e, f, g, h])])
676}
677
678/// compile time u128 to u64 conversion
679pub const fn u128_to_u64(val: u128) -> [u64; 2] {
680    let a = val as u64;
681    let b = (val >> 64) as u64;
682    [b, a]
683}
684/// compile time u64 to u32 conversion
685pub const fn u64_to_u32(val: u64) -> [u32; 2] {
686    let a = val as u32;
687    let b = (val >> 32) as u32;
688    [b, a]
689}
690/// compile time u32 to u16 conversion
691pub const fn u32_to_u16(val: u32) -> [u16; 2] {
692    let a = val as u16;
693    let b = (val >> 16) as u16;
694    [b, a]
695}
696/// compile time u128 to u32 conversion
697pub const fn u128_to_u32(val: u128) -> [u32; 4] {
698    let [a, b] = u128_to_u64(val);
699    let [c, d] = u64_to_u32(a);
700    let [e, f] = u64_to_u32(b);
701    [c, d, e, f]
702}
703/// compile time u64 to u16 conversion
704pub const fn u64_to_u16(val: u64) -> [u16; 4] {
705    let [a, b] = u64_to_u32(val);
706    let [c, d] = u32_to_u16(a);
707    let [e, f] = u32_to_u16(b);
708    [c, d, e, f]
709}
710/// compile-time u128 to u16 conversion
711pub const fn u128_to_u16(val: u128) -> [u16; 8] {
712    let [a, b, c, d] = u128_to_u32(val);
713    let [e, f] = u32_to_u16(a);
714    let [g, h] = u32_to_u16(b);
715    let [i, j] = u32_to_u16(c);
716    let [k, l] = u32_to_u16(d);
717    [e, f, g, h, i, j, k, l]
718}
719
720impl WriteToBEBits for &str {
721    fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
722        bits.write_str_u32_blob(self)
723    }
724}
725impl WriteToLEBits for &str {
726    fn write_le_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
727        let len = self.len() as u32;
728        bits.write_le_u32(len)?;
729        bits.write_all_bytes(self.as_bytes())?;
730
731        Ok((len + 4) as usize)
732    }
733}
734
735cfg_feature_alloc! {
736    extern crate alloc;
737    impl WriteToBEBits for alloc::string::String {
738        fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
739            bits.write_str_u32_blob(self.as_str())
740        }
741    }
742    impl ReadFromBEBits for alloc::string::String {
743        fn read_from_be_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
744            inp.read_str_u32_blob()
745        }
746    }
747    impl ReadFromLEBits for alloc::string::String {
748        fn read_from_le_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
749            let len = inp.read_le_u32()?;
750            inp.read_str_sized_lossy(len as usize)
751        }
752    }
753    impl WriteToBEBits for alloc::sync::Arc<alloc::string::String> {
754        fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
755            bits.write_str_u32_blob(self.as_str())
756        }
757    }
758}