Skip to main content

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    u32,
437    16,
438    64,
439    write_be_u32,
440    write_le_u32,
441    next_be_u32,
442    next_le_u32
443); // 512 bit
444
445impl_large_array!(
446    u64,
447    3,
448    24,
449    write_be_u64,
450    write_le_u64,
451    next_be_u64,
452    next_le_u64
453); // 192 bit
454impl_large_array!(
455    u64,
456    4,
457    32,
458    write_be_u64,
459    write_le_u64,
460    next_be_u64,
461    next_le_u64
462); // 256 bit
463impl_large_array!(
464    u64,
465    5,
466    40,
467    write_be_u64,
468    write_le_u64,
469    next_be_u64,
470    next_le_u64
471); // 320 bit
472impl_large_array!(
473    u64,
474    6,
475    48,
476    write_be_u64,
477    write_le_u64,
478    next_be_u64,
479    next_le_u64
480); // 384 bit
481impl_large_array!(
482    u64,
483    7,
484    56,
485    write_be_u64,
486    write_le_u64,
487    next_be_u64,
488    next_le_u64
489); // 448 bit
490impl_large_array!(
491    u64,
492    8,
493    64,
494    write_be_u64,
495    write_le_u64,
496    next_be_u64,
497    next_le_u64
498); // 512 bit
499impl_large_array!(
500    u64,
501    9,
502    72,
503    write_be_u64,
504    write_le_u64,
505    next_be_u64,
506    next_le_u64
507); // 576 bit
508impl_large_array!(
509    u64,
510    10,
511    80,
512    write_be_u64,
513    write_le_u64,
514    next_be_u64,
515    next_le_u64
516); // 640 bit
517impl_large_array!(
518    u64,
519    11,
520    88,
521    write_be_u64,
522    write_le_u64,
523    next_be_u64,
524    next_le_u64
525); // 704 bit
526impl_large_array!(
527    u64,
528    12,
529    96,
530    write_be_u64,
531    write_le_u64,
532    next_be_u64,
533    next_le_u64
534); // 768 bit
535
536impl_large_array!(
537    u128,
538    3,
539    48,
540    write_be_u128,
541    write_le_u128,
542    next_be_u128,
543    next_le_u128
544); // 384 bit
545impl_large_array!(
546    u128,
547    4,
548    64,
549    write_be_u128,
550    write_le_u128,
551    next_be_u128,
552    next_le_u128
553); // 512 bit
554impl_large_array!(
555    u128,
556    5,
557    80,
558    write_be_u128,
559    write_le_u128,
560    next_be_u128,
561    next_le_u128
562); // 640 bit
563impl_large_array!(
564    u128,
565    6,
566    96,
567    write_be_u128,
568    write_le_u128,
569    next_be_u128,
570    next_le_u128
571); // 768 bit
572impl_large_array!(
573    u128,
574    7,
575    112,
576    write_be_u128,
577    write_le_u128,
578    next_be_u128,
579    next_le_u128
580); // 896 bit
581impl_large_array!(
582    u128,
583    8,
584    128,
585    write_be_u128,
586    write_le_u128,
587    next_be_u128,
588    next_le_u128
589); // 1024 bit
590impl_large_array!(
591    u128,
592    9,
593    144,
594    write_be_u128,
595    write_le_u128,
596    next_be_u128,
597    next_le_u128
598); // 1152 bit
599impl_large_array!(
600    u128,
601    10,
602    160,
603    write_be_u128,
604    write_le_u128,
605    next_be_u128,
606    next_le_u128
607); // 1280 bit
608impl_large_array!(
609    u128,
610    11,
611    176,
612    write_be_u128,
613    write_le_u128,
614    next_be_u128,
615    next_le_u128
616); // 1408 bit
617impl_large_array!(
618    u128,
619    12,
620    192,
621    write_be_u128,
622    write_le_u128,
623    next_be_u128,
624    next_le_u128
625); // 1536 bit
626
627macro_rules! impl_tobe_self {
628    ($($n:literal) +) => {
629        $(
630            impl ToBEBytes<$n> for [u8;$n] {
631                fn to_be_bytes(&self) -> [u8; $n] {
632                    *self
633                }
634            }
635        )*
636    };
637}
638impl_tobe_self!(16 20 28 32 48 60 64);
639
640/// Writes 'self' to the provided [`MutBits`] impl in big endian order.
641pub trait WriteToBEBits {
642    fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error>;
643}
644/// Writes 'self' to the provided [`MutBits`] impl in little endian order.
645pub trait WriteToLEBits {
646    fn write_le_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error>;
647}
648
649pub trait ReadFromBEBits: Sized {
650    fn read_from_be_bits<T: Bits>(inp: &mut T) -> Result<Self, Error>;
651}
652pub trait ReadFromLEBits: Sized {
653    fn read_from_le_bits<T: Bits>(inp: &mut T) -> Result<Self, Error>;
654}
655impl<const N: usize> ReadFromBEBits for [u8; N] {
656    fn read_from_be_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
657        let mut out = [0; N];
658        inp.read_all_into(&mut out.as_mut_slice())?;
659        Ok(out)
660    }
661}
662impl<const N: usize> ReadFromLEBits for [u8; N] {
663    fn read_from_le_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
664        let mut out = [0; N];
665        inp.read_all_into(&mut out.as_mut_slice())?;
666        Ok(out)
667    }
668}
669
670/// compile time u64x2 to u128 conversion
671pub const fn u64_to_u128(val: [u64; 2]) -> u128 {
672    let [a, b] = val;
673    u128::from_be_bytes(array_concat_8(u64::to_be_bytes(a), u64::to_be_bytes(b)))
674}
675/// compile time u32x2 to u64 conversion
676pub const fn u32_to_u64(val: [u32; 2]) -> u64 {
677    let [a, b] = val;
678    u64::from_be_bytes(array_concat_4(u32::to_be_bytes(a), u32::to_be_bytes(b)))
679}
680/// compile time u32x4 to u128 conversion
681pub const fn u32_to_u128(val: [u32; 4]) -> u128 {
682    let [a, b, c, d] = val;
683    u64_to_u128([u32_to_u64([a, b]), u32_to_u64([c, d])])
684}
685/// compile time u16x2 to u32 conversion
686pub const fn u16_to_u32(val: [u16; 2]) -> u32 {
687    let [a, b] = val;
688    u32::from_be_bytes(array_concat_2(u16::to_be_bytes(a), u16::to_be_bytes(b)))
689}
690/// compile time u16 to u64 conversion
691pub const fn u16_to_u64(val: [u16; 4]) -> u64 {
692    let [a, b, c, d] = val;
693    u32_to_u64([u16_to_u32([a, b]), u16_to_u32([c, d])])
694}
695/// compile time u16 to u128 conversion
696pub const fn u16_to_u128(val: [u16; 8]) -> u128 {
697    let [a, b, c, d, e, f, g, h] = val;
698    u64_to_u128([u16_to_u64([a, b, c, d]), u16_to_u64([e, f, g, h])])
699}
700
701/// compile time u128 to u64 conversion
702pub const fn u128_to_u64(val: u128) -> [u64; 2] {
703    let a = val as u64;
704    let b = (val >> 64) as u64;
705    [b, a]
706}
707/// compile time u64 to u32 conversion
708pub const fn u64_to_u32(val: u64) -> [u32; 2] {
709    let a = val as u32;
710    let b = (val >> 32) as u32;
711    [b, a]
712}
713/// compile time u32 to u16 conversion
714pub const fn u32_to_u16(val: u32) -> [u16; 2] {
715    let a = val as u16;
716    let b = (val >> 16) as u16;
717    [b, a]
718}
719/// compile time u128 to u32 conversion
720pub const fn u128_to_u32(val: u128) -> [u32; 4] {
721    let [a, b] = u128_to_u64(val);
722    let [c, d] = u64_to_u32(a);
723    let [e, f] = u64_to_u32(b);
724    [c, d, e, f]
725}
726/// compile time u64 to u16 conversion
727pub const fn u64_to_u16(val: u64) -> [u16; 4] {
728    let [a, b] = u64_to_u32(val);
729    let [c, d] = u32_to_u16(a);
730    let [e, f] = u32_to_u16(b);
731    [c, d, e, f]
732}
733/// compile-time u128 to u16 conversion
734pub const fn u128_to_u16(val: u128) -> [u16; 8] {
735    let [a, b, c, d] = u128_to_u32(val);
736    let [e, f] = u32_to_u16(a);
737    let [g, h] = u32_to_u16(b);
738    let [i, j] = u32_to_u16(c);
739    let [k, l] = u32_to_u16(d);
740    [e, f, g, h, i, j, k, l]
741}
742
743impl WriteToBEBits for &str {
744    fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
745        bits.write_str_u32_blob(self)
746    }
747}
748impl WriteToLEBits for &str {
749    fn write_le_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
750        let len = self.len() as u32;
751        bits.write_le_u32(len)?;
752        bits.write_all_bytes(self.as_bytes())?;
753
754        Ok((len + 4) as usize)
755    }
756}
757impl WriteToBEBits for &[u8] {
758    fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
759        bits.write_all_bytes(self)?;
760        Ok(self.len())
761    }
762}
763
764cfg_feature_alloc! {
765    extern crate alloc;
766    impl WriteToBEBits for alloc::string::String {
767        fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
768            bits.write_str_u32_blob(self.as_str())
769        }
770    }
771    impl ReadFromBEBits for alloc::string::String {
772        fn read_from_be_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
773            inp.read_str_u32_blob()
774        }
775    }
776    impl ReadFromLEBits for alloc::string::String {
777        fn read_from_le_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
778            let len = inp.read_le_u32()?;
779            inp.read_str_sized_lossy(len as usize)
780        }
781    }
782    impl WriteToBEBits for alloc::sync::Arc<alloc::string::String> {
783        fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
784            bits.write_str_u32_blob(self.as_str())
785        }
786    }
787    impl WriteToBEBits for alloc::boxed::Box<[u8]> {
788        fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
789            bits.write_all_bytes(self)?;
790            Ok(self.len())
791        }
792    }
793}
794
795/// Serialize a structure (struct, enum, tuple, etc) to a [`MutBits`] impl.
796pub trait SerializeToBits {
797    fn serialize_to_bits<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error>;
798}
799
800/// Deserialize a structure (struct, enum, tuple, etc) from a [`Bits`] impl.
801pub trait DeserializeFromBits {
802    type Output: Sized;
803    fn deserialize_from_bits<T: Bits>(inp: &mut T) -> Result<Self::Output, Error>;
804}