Skip to main content

naia_serde/
number.rs

1use crate::{
2    bit_reader::BitReader, bit_writer::BitWrite, error::SerdeErr, serde::Serde, ConstBitLength,
3};
4
5// Integers
6
7pub trait SerdeIntegerConversion<const SIGNED: bool, const VARIABLE: bool, const BITS: u8> {
8    fn from(value: &SerdeInteger<SIGNED, VARIABLE, BITS>) -> Self;
9}
10
11pub type UnsignedInteger<const BITS: u8> = SerdeInteger<false, false, BITS>;
12pub type SignedInteger<const BITS: u8> = SerdeInteger<true, false, BITS>;
13pub type UnsignedVariableInteger<const BITS: u8> = SerdeInteger<false, true, BITS>;
14pub type SignedVariableInteger<const BITS: u8> = SerdeInteger<true, true, BITS>;
15
16#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
17pub struct SerdeInteger<const SIGNED: bool, const VARIABLE: bool, const BITS: u8> {
18    inner: SerdeNumberInner,
19}
20
21impl<const SIGNED: bool, const VARIABLE: bool, const BITS: u8>
22    SerdeInteger<SIGNED, VARIABLE, BITS>
23{
24    pub fn new<T: Into<i128>>(value: T) -> Self {
25        Self {
26            inner: SerdeNumberInner::new(SIGNED, VARIABLE, BITS, 0, value.into()),
27        }
28    }
29
30    pub fn get(&self) -> i128 {
31        self.inner.get()
32    }
33
34    pub fn set<T: Into<i128>>(&mut self, value: T) {
35        self.inner.set(value.into());
36    }
37
38    pub fn to<T: SerdeIntegerConversion<SIGNED, VARIABLE, BITS>>(&self) -> T {
39        T::from(self)
40    }
41}
42
43impl<const SIGNED: bool, const VARIABLE: bool, const BITS: u8> Serde
44    for SerdeInteger<SIGNED, VARIABLE, BITS>
45{
46    fn ser(&self, writer: &mut dyn BitWrite) {
47        self.inner.ser(writer);
48    }
49
50    fn de(reader: &mut BitReader) -> Result<Self, SerdeErr> {
51        let inner = SerdeNumberInner::de(reader, SIGNED, VARIABLE, BITS, 0)?;
52        Ok(Self { inner })
53    }
54
55    fn bit_length(&self) -> u32 {
56        self.inner.bit_length()
57    }
58}
59
60impl<const SIGNED: bool, const BITS: u8> ConstBitLength for SerdeInteger<SIGNED, false, BITS> {
61    fn const_bit_length() -> u32 {
62        let mut output: u32 = 0;
63        if SIGNED {
64            output += 1;
65        }
66        output + BITS as u32
67    }
68}
69
70impl<const SIGNED: bool, const VARIABLE: bool, const BITS: u8, T: Into<i128>> From<T>
71    for SerdeInteger<SIGNED, VARIABLE, BITS>
72{
73    fn from(value: T) -> Self {
74        Self::new(value)
75    }
76}
77
78impl<const SIGNED: bool, const VARIABLE: bool, const BITS: u8, T: TryFrom<i128>>
79    SerdeIntegerConversion<SIGNED, VARIABLE, BITS> for T
80{
81    fn from(value: &SerdeInteger<SIGNED, VARIABLE, BITS>) -> Self {
82        let Ok(t_value) = T::try_from(value.get()) else {
83            panic!("SerdeInteger's value is out of range to convert to this type.");
84        };
85        t_value
86    }
87}
88
89// Floats
90
91pub trait SerdeFloatConversion<
92    const SIGNED: bool,
93    const VARIABLE: bool,
94    const BITS: u8,
95    const FRACTION_DIGITS: u8,
96>
97{
98    fn from(value: &SerdeFloat<SIGNED, VARIABLE, BITS, FRACTION_DIGITS>) -> Self;
99}
100
101pub type UnsignedFloat<const BITS: u8, const FRACTION_DIGITS: u8> =
102    SerdeFloat<false, false, BITS, FRACTION_DIGITS>;
103pub type SignedFloat<const BITS: u8, const FRACTION_DIGITS: u8> =
104    SerdeFloat<true, false, BITS, FRACTION_DIGITS>;
105pub type UnsignedVariableFloat<const BITS: u8, const FRACTION_DIGITS: u8> =
106    SerdeFloat<false, true, BITS, FRACTION_DIGITS>;
107pub type SignedVariableFloat<const BITS: u8, const FRACTION_DIGITS: u8> =
108    SerdeFloat<true, true, BITS, FRACTION_DIGITS>;
109
110#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
111pub struct SerdeFloat<
112    const SIGNED: bool,
113    const VARIABLE: bool,
114    const BITS: u8,
115    const FRACTION_DIGITS: u8,
116> {
117    inner: SerdeNumberInner,
118}
119
120impl<const SIGNED: bool, const VARIABLE: bool, const BITS: u8, const FRACTION_DIGITS: u8>
121    SerdeFloat<SIGNED, VARIABLE, BITS, FRACTION_DIGITS>
122{
123    pub fn new<T: Into<f32>>(value: T) -> Self {
124        let float_val = value.into();
125        let scale = 10f32.powi(FRACTION_DIGITS as i32);
126        let scaled = (float_val * scale).round() as i128;
127        let inner = SerdeNumberInner::new(SIGNED, VARIABLE, BITS, FRACTION_DIGITS, scaled);
128        Self { inner }
129    }
130
131    pub fn get(&self) -> f32 {
132        let scale = 10f32.powi(FRACTION_DIGITS as i32);
133        (self.inner.get() as f32) / scale
134    }
135
136    pub fn set<T: Into<f32>>(&mut self, value: T) {
137        let float_val = value.into();
138        let scale = 10f32.powi(FRACTION_DIGITS as i32);
139        let scaled = (float_val * scale).round() as i128;
140        self.inner.set(scaled);
141    }
142}
143
144impl<const S: bool, const V: bool, const B: u8, const F: u8> Serde for SerdeFloat<S, V, B, F> {
145    fn ser(&self, writer: &mut dyn BitWrite) {
146        self.inner.ser(writer);
147    }
148
149    fn de(reader: &mut BitReader) -> Result<Self, SerdeErr> {
150        // read in i128, convert.
151        let inner = SerdeNumberInner::de(reader, S, V, B, F)?;
152        // We interpret the i128 as scaled. We just store it.
153        Ok(Self { inner })
154    }
155
156    fn bit_length(&self) -> u32 {
157        self.inner.bit_length()
158    }
159}
160
161impl<const SIGNED: bool, const BITS: u8, const FRACTION_DIGITS: u8> ConstBitLength
162    for SerdeFloat<SIGNED, false, BITS, FRACTION_DIGITS>
163{
164    fn const_bit_length() -> u32 {
165        let mut output: u32 = 0;
166        if SIGNED {
167            output += 1;
168        }
169        output + BITS as u32
170    }
171}
172
173impl<
174        const SIGNED: bool,
175        const VARIABLE: bool,
176        const BITS: u8,
177        const FRACTION_DIGITS: u8,
178        T: Into<f32>,
179    > From<T> for SerdeFloat<SIGNED, VARIABLE, BITS, FRACTION_DIGITS>
180{
181    fn from(value: T) -> Self {
182        Self::new(value)
183    }
184}
185
186impl<
187        const SIGNED: bool,
188        const VARIABLE: bool,
189        const BITS: u8,
190        const FRACTION_DIGITS: u8,
191        T: TryFrom<f32>,
192    > SerdeFloatConversion<SIGNED, VARIABLE, BITS, FRACTION_DIGITS> for T
193{
194    fn from(value: &SerdeFloat<SIGNED, VARIABLE, BITS, FRACTION_DIGITS>) -> Self {
195        let Ok(t_value) = T::try_from(value.get()) else {
196            panic!("SerdeFloat's value is out of range to convert to this type.");
197        };
198        t_value
199    }
200}
201
202// Inner type that is not generic (avoiding code bloat from monomorphization)
203
204#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
205struct SerdeNumberInner {
206    inner_value: i128,
207    signed: bool,
208    variable: bool,
209    bits: u8,
210    fraction_digits: u8,
211}
212
213impl SerdeNumberInner {
214    fn new(signed: bool, variable: bool, bits: u8, fraction_digits: u8, value: i128) -> Self {
215        if bits == 0 {
216            panic!("can't create an number with 0 bits...");
217        }
218        if bits > 127 {
219            panic!("can't create an number with more than 127 bits...");
220        }
221
222        if !signed && value < 0 {
223            panic!("can't encode a negative number with an Unsigned type!");
224        }
225
226        if !variable {
227            let max_value: i128 = 2_i128.pow(bits as u32);
228            if value >= max_value {
229                panic!(
230                    "value `{}` is too high! (with `{}` bits, can't encode number greater than `{}`)",
231                    value, bits, max_value
232                );
233            }
234            if signed && value < 0 {
235                let min_value: i128 = -(2_i128.pow(bits as u32));
236                if value <= min_value {
237                    panic!(
238                        "value `{}` is too low! (with `{}` bits, can't encode number less than `{}`)",
239                        value, bits, min_value
240                    );
241                }
242            }
243        }
244
245        Self {
246            inner_value: value,
247            signed,
248            variable,
249            bits,
250            fraction_digits,
251        }
252    }
253
254    fn new_unchecked(
255        signed: bool,
256        variable: bool,
257        bits: u8,
258        fraction_digits: u8,
259        value: i128,
260    ) -> Self {
261        Self {
262            inner_value: value,
263            signed,
264            variable,
265            bits,
266            fraction_digits,
267        }
268    }
269
270    fn get(&self) -> i128 {
271        self.inner_value
272    }
273
274    fn set(&mut self, value: i128) {
275        self.inner_value = value;
276    }
277
278    fn ser(&self, writer: &mut dyn BitWrite) {
279        // replicate original ser logic
280        let mut value: u128;
281        let negative = self.inner_value < 0;
282
283        if self.signed {
284            writer.write_bit(negative);
285            if negative {
286                value = -self.inner_value as u128;
287            } else {
288                value = self.inner_value as u128;
289            }
290        } else {
291            value = self.inner_value as u128;
292        }
293
294        if self.variable {
295            let chunk_threshold = 1u128 << self.bits;
296            loop {
297                let proceed = value >= chunk_threshold;
298                writer.write_bit(proceed);
299                for _ in 0..self.bits {
300                    writer.write_bit(value & 1 != 0);
301                    value >>= 1;
302                }
303                if !proceed {
304                    return;
305                }
306            }
307        } else {
308            for _ in 0..self.bits {
309                writer.write_bit(value & 1 != 0);
310                value >>= 1;
311            }
312        }
313    }
314
315    fn de(
316        reader: &mut BitReader,
317        signed: bool,
318        variable: bool,
319        bits: u8,
320        fraction_digits: u8,
321    ) -> Result<Self, SerdeErr> {
322        let mut negative = false;
323        if signed {
324            negative = reader.read_bit()?;
325        }
326
327        // Decode strategy: accumulate each chunk/field LSB-first into a u32
328        // (single-instruction shift on every target, including wasm32 and ARM),
329        // then widen and place into u128 output with a u32→u128 zero extension.
330        // This replaces the old MSB-first u128 accumulation + u128::reverse_bits
331        // (which is a software sequence on every target, not a single instruction).
332        if variable {
333            let mut output: u128 = 0;
334            let mut shift: u32 = 0;
335            loop {
336                let proceed = reader.read_bit()?;
337                // Accumulate chunk in u32: LSB-first, `1u32 << i` is one instruction.
338                let mut chunk = 0u32;
339                for i in 0..bits as u32 {
340                    if reader.read_bit()? {
341                        chunk |= 1u32 << i;
342                    }
343                }
344                output |= (chunk as u128) << shift;
345                shift += bits as u32;
346                if !proceed {
347                    let value = output as i128;
348                    return Ok(Self::new_unchecked(
349                        signed,
350                        variable,
351                        bits,
352                        fraction_digits,
353                        if negative { -value } else { value },
354                    ));
355                }
356            }
357        } else {
358            // Fixed-width: accumulate LSB-first.
359            let output = if bits <= 32 {
360                let mut raw = 0u32;
361                for i in 0..bits as u32 {
362                    if reader.read_bit()? {
363                        raw |= 1u32 << i;
364                    }
365                }
366                raw as u128
367            } else if bits <= 64 {
368                let mut raw = 0u64;
369                for i in 0..bits as u32 {
370                    if reader.read_bit()? {
371                        raw |= 1u64 << i;
372                    }
373                }
374                raw as u128
375            } else {
376                // bits > 64 (unusual): MSB-first + reverse to avoid u128 variable shift.
377                let mut raw: u128 = 0;
378                for _ in 0..bits {
379                    raw <<= 1;
380                    if reader.read_bit()? {
381                        raw |= 1;
382                    }
383                }
384                raw <<= 128 - bits as u32;
385                raw.reverse_bits()
386            };
387            let value = output as i128;
388            Ok(Self::new_unchecked(
389                signed,
390                variable,
391                bits,
392                fraction_digits,
393                if negative { -value } else { value },
394            ))
395        }
396    }
397
398    fn bit_length(&self) -> u32 {
399        let mut output: u32 = 0;
400
401        if self.signed {
402            output += 1; // sign bit
403        }
404
405        if self.variable {
406            let mut value = self.inner_value.unsigned_abs();
407            loop {
408                let proceed = value >= 2_u128.pow(self.bits as u32);
409                output += 1; // proceed bit
410                for _ in 0..self.bits {
411                    output += 1;
412                    value >>= 1;
413                }
414                if !proceed {
415                    break;
416                }
417            }
418        } else {
419            output += self.bits as u32;
420        }
421        output
422    }
423}
424
425// Tests
426
427#[cfg(test)]
428mod tests {
429    use crate::{
430        bit_reader::BitReader,
431        bit_writer::BitWriter,
432        number::{
433            SignedFloat, SignedInteger, SignedVariableFloat, SignedVariableInteger, UnsignedFloat,
434            UnsignedInteger, UnsignedVariableFloat, UnsignedVariableInteger,
435        },
436        serde::Serde,
437    };
438
439    #[test]
440    fn in_and_out() {
441        let in_u16: u16 = 123;
442        let middle = UnsignedInteger::<9>::new(in_u16);
443        let out_u16: u16 = middle.get() as u16;
444
445        assert_eq!(in_u16, out_u16);
446    }
447
448    #[test]
449    fn read_write_unsigned() {
450        // Write
451        let mut writer = BitWriter::new();
452
453        let in_1 = UnsignedInteger::<7>::new(123);
454        let in_2 = UnsignedInteger::<20>::new(535221);
455        let in_3 = UnsignedInteger::<2>::new(3);
456
457        in_1.ser(&mut writer);
458        in_2.ser(&mut writer);
459        in_3.ser(&mut writer);
460
461        let buffer = writer.to_bytes();
462
463        // Read
464        let mut reader = BitReader::new(&buffer);
465
466        let out_1 = Serde::de(&mut reader).unwrap();
467        let out_2 = Serde::de(&mut reader).unwrap();
468        let out_3 = Serde::de(&mut reader).unwrap();
469
470        assert_eq!(in_1, out_1);
471        assert_eq!(in_2, out_2);
472        assert_eq!(in_3, out_3);
473    }
474
475    #[test]
476    fn read_write_signed() {
477        // Write
478        let mut writer = BitWriter::new();
479
480        let in_1 = SignedInteger::<10>::new(-668);
481        let in_2 = SignedInteger::<20>::new(53);
482        let in_3 = SignedInteger::<2>::new(-3);
483
484        in_1.ser(&mut writer);
485        in_2.ser(&mut writer);
486        in_3.ser(&mut writer);
487
488        let buffer = writer.to_bytes();
489
490        // Read
491        let mut reader = BitReader::new(&buffer);
492
493        let out_1 = Serde::de(&mut reader).unwrap();
494        let out_2 = Serde::de(&mut reader).unwrap();
495        let out_3 = Serde::de(&mut reader).unwrap();
496
497        assert_eq!(in_1, out_1);
498        assert_eq!(in_2, out_2);
499        assert_eq!(in_3, out_3);
500    }
501
502    #[test]
503    fn read_write_unsigned_variable() {
504        // Write
505        let mut writer = BitWriter::new();
506
507        let in_1 = UnsignedVariableInteger::<3>::new(23);
508        let in_2 = UnsignedVariableInteger::<5>::new(153);
509        let in_3 = UnsignedVariableInteger::<2>::new(3);
510
511        in_1.ser(&mut writer);
512        in_2.ser(&mut writer);
513        in_3.ser(&mut writer);
514
515        let buffer = writer.to_bytes();
516
517        // Read
518        let mut reader = BitReader::new(&buffer);
519
520        let out_1 = Serde::de(&mut reader).unwrap();
521        let out_2 = Serde::de(&mut reader).unwrap();
522        let out_3 = Serde::de(&mut reader).unwrap();
523
524        assert_eq!(in_1, out_1);
525        assert_eq!(in_2, out_2);
526        assert_eq!(in_3, out_3);
527    }
528
529    #[test]
530    fn read_write_signed_variable() {
531        // Write
532        let mut writer = BitWriter::new();
533
534        let in_1 = SignedVariableInteger::<5>::new(-668);
535        let in_2 = SignedVariableInteger::<6>::new(53735);
536        let in_3 = SignedVariableInteger::<2>::new(-3);
537
538        in_1.ser(&mut writer);
539        in_2.ser(&mut writer);
540        in_3.ser(&mut writer);
541
542        let buffer = writer.to_bytes();
543
544        // Read
545        let mut reader = BitReader::new(&buffer);
546
547        let out_1 = Serde::de(&mut reader).unwrap();
548        let out_2 = Serde::de(&mut reader).unwrap();
549        let out_3 = Serde::de(&mut reader).unwrap();
550
551        assert_eq!(in_1, out_1);
552        assert_eq!(in_2, out_2);
553        assert_eq!(in_3, out_3);
554    }
555
556    // Floats
557
558    #[test]
559    fn read_write_unsigned_float() {
560        // Write
561        let mut writer = BitWriter::new();
562
563        let in_1 = UnsignedFloat::<7, 1>::new(12.3);
564        let in_2 = UnsignedFloat::<20, 2>::new(5352.21);
565        let in_3 = UnsignedFloat::<5, 1>::new(3.0);
566
567        in_1.ser(&mut writer);
568        in_2.ser(&mut writer);
569        in_3.ser(&mut writer);
570
571        let buffer = writer.to_bytes();
572
573        // Read
574        let mut reader = BitReader::new(&buffer);
575
576        let out_1: UnsignedFloat<7, 1> = Serde::de(&mut reader).unwrap();
577        let out_2: UnsignedFloat<20, 2> = Serde::de(&mut reader).unwrap();
578        let out_3: UnsignedFloat<5, 1> = Serde::de(&mut reader).unwrap();
579
580        assert!(
581            (in_1.get() - out_1.get()).abs() < 0.0001,
582            "{} != {}",
583            in_1.get(),
584            out_1.get()
585        );
586        assert!(
587            (in_2.get() - out_2.get()).abs() < 0.0001,
588            "{} != {}",
589            in_2.get(),
590            out_2.get()
591        );
592        assert!(
593            (in_3.get() - out_3.get()).abs() < 0.0001,
594            "{} != {}",
595            in_3.get(),
596            out_3.get()
597        );
598    }
599
600    #[test]
601    fn read_write_signed_float() {
602        let mut writer = BitWriter::new();
603
604        let in_1 = SignedFloat::<7, 1>::new(-12.3);
605        let in_2 = SignedFloat::<20, 2>::new(5352.21);
606        let in_3 = SignedFloat::<5, 1>::new(-3.0);
607
608        in_1.ser(&mut writer);
609        in_2.ser(&mut writer);
610        in_3.ser(&mut writer);
611
612        let buffer = writer.to_bytes();
613        let mut reader = BitReader::new(&buffer);
614
615        let out_1: SignedFloat<7, 1> = Serde::de(&mut reader).unwrap();
616        let out_2: SignedFloat<20, 2> = Serde::de(&mut reader).unwrap();
617        let out_3: SignedFloat<5, 1> = Serde::de(&mut reader).unwrap();
618
619        assert!(
620            (in_1.get() - out_1.get()).abs() < 0.0001,
621            "{} != {}",
622            in_1.get(),
623            out_1.get()
624        );
625        assert!(
626            (in_2.get() - out_2.get()).abs() < 0.0001,
627            "{} != {}",
628            in_2.get(),
629            out_2.get()
630        );
631        assert!(
632            (in_3.get() - out_3.get()).abs() < 0.0001,
633            "{} != {}",
634            in_3.get(),
635            out_3.get()
636        );
637    }
638
639    #[test]
640    fn read_write_unsigned_variable_float() {
641        let mut writer = BitWriter::new();
642
643        let in_1 = UnsignedVariableFloat::<3, 1>::new(2.3);
644        let in_2 = UnsignedVariableFloat::<5, 2>::new(153.22);
645        let in_3 = UnsignedVariableFloat::<2, 1>::new(3.0);
646
647        in_1.ser(&mut writer);
648        in_2.ser(&mut writer);
649        in_3.ser(&mut writer);
650
651        let buffer = writer.to_bytes();
652        let mut reader = BitReader::new(&buffer);
653
654        let out_1: UnsignedVariableFloat<3, 1> = Serde::de(&mut reader).unwrap();
655        let out_2: UnsignedVariableFloat<5, 2> = Serde::de(&mut reader).unwrap();
656        let out_3: UnsignedVariableFloat<2, 1> = Serde::de(&mut reader).unwrap();
657
658        assert!(
659            (in_1.get() - out_1.get()).abs() < 0.0001,
660            "{} != {}",
661            in_1.get(),
662            out_1.get()
663        );
664        assert!(
665            (in_2.get() - out_2.get()).abs() < 0.0001,
666            "{} != {}",
667            in_2.get(),
668            out_2.get()
669        );
670        assert!(
671            (in_3.get() - out_3.get()).abs() < 0.0001,
672            "{} != {}",
673            in_3.get(),
674            out_3.get()
675        );
676    }
677
678    #[test]
679    fn read_write_signed_variable_float() {
680        let mut writer = BitWriter::new();
681
682        let in_1 = SignedVariableFloat::<5, 1>::new(-66.8);
683        let in_2 = SignedVariableFloat::<6, 2>::new(537.35);
684        let in_3 = SignedVariableFloat::<2, 1>::new(-3.0);
685
686        in_1.ser(&mut writer);
687        in_2.ser(&mut writer);
688        in_3.ser(&mut writer);
689
690        let buffer = writer.to_bytes();
691        let mut reader = BitReader::new(&buffer);
692
693        let out_1: SignedVariableFloat<5, 1> = Serde::de(&mut reader).unwrap();
694        let out_2: SignedVariableFloat<6, 2> = Serde::de(&mut reader).unwrap();
695        let out_3: SignedVariableFloat<2, 1> = Serde::de(&mut reader).unwrap();
696
697        assert!(
698            (in_1.get() - out_1.get()).abs() < 0.0001,
699            "{} != {}",
700            in_1.get(),
701            out_1.get()
702        );
703        assert!(
704            (in_2.get() - out_2.get()).abs() < 0.0001,
705            "{} != {}",
706            in_2.get(),
707            out_2.get()
708        );
709        assert!(
710            (in_3.get() - out_3.get()).abs() < 0.0001,
711            "{} != {}",
712            in_3.get(),
713            out_3.get()
714        );
715    }
716}