lilliput_core/encoder/
int.rs

1use num_traits::{Signed, Unsigned};
2
3use crate::{
4    binary::bits_if,
5    error::Result,
6    header::{CompactIntHeader, ExtendedIntHeader, IntHeader},
7    io::Write,
8    num::WithPackedBeBytes,
9    value::{IntValue, SignedIntValue, UnsignedIntValue},
10};
11
12use super::Encoder;
13
14impl<W> Encoder<W>
15where
16    W: Write,
17{
18    // MARK: - Value
19
20    /// Encodes a 8-bit signed integer value.
21    pub fn encode_i8(&mut self, value: i8) -> Result<()> {
22        self.encode_signed_int(value)
23    }
24
25    /// Encodes a 16-bit signed integer value.
26    pub fn encode_i16(&mut self, value: i16) -> Result<()> {
27        self.encode_signed_int(value)
28    }
29
30    /// Encodes a 32-bit signed integer value.
31    pub fn encode_i32(&mut self, value: i32) -> Result<()> {
32        self.encode_signed_int(value)
33    }
34
35    /// Encodes a 64-bit signed integer value.
36    pub fn encode_i64(&mut self, value: i64) -> Result<()> {
37        self.encode_signed_int(value)
38    }
39
40    /// Encodes a 8-bit unsigned integer value.
41    pub fn encode_u8(&mut self, value: u8) -> Result<()> {
42        self.encode_unsigned_int(value)
43    }
44
45    /// Encodes a 16-bit unsigned integer value.
46    pub fn encode_u16(&mut self, value: u16) -> Result<()> {
47        self.encode_unsigned_int(value)
48    }
49
50    /// Encodes a 32-bit unsigned integer value.
51    pub fn encode_u32(&mut self, value: u32) -> Result<()> {
52        self.encode_unsigned_int(value)
53    }
54
55    /// Encodes a 64-bit unsigned integer value.
56    pub fn encode_u64(&mut self, value: u64) -> Result<()> {
57        self.encode_unsigned_int(value)
58    }
59
60    /// Encodes a signed integer value, from a `SignedIntValue`.
61    pub fn encode_signed_int_value(&mut self, value: &SignedIntValue) -> Result<()> {
62        match value {
63            SignedIntValue::I8(value) => self.encode_signed_int(*value),
64            SignedIntValue::I16(value) => self.encode_signed_int(*value),
65            SignedIntValue::I32(value) => self.encode_signed_int(*value),
66            SignedIntValue::I64(value) => self.encode_signed_int(*value),
67        }
68    }
69
70    /// Encodes an unsigned integer value, from a `UnsignedIntValue`.
71    pub fn encode_unsigned_int_value(&mut self, value: &UnsignedIntValue) -> Result<()> {
72        match value {
73            UnsignedIntValue::U8(value) => self.encode_unsigned_int(*value),
74            UnsignedIntValue::U16(value) => self.encode_unsigned_int(*value),
75            UnsignedIntValue::U32(value) => self.encode_unsigned_int(*value),
76            UnsignedIntValue::U64(value) => self.encode_unsigned_int(*value),
77        }
78    }
79
80    /// Encodes an integer value, from a `IntValue`.
81    pub fn encode_int_value(&mut self, value: &IntValue) -> Result<()> {
82        match value {
83            IntValue::Signed(value) => self.encode_signed_int_value(value),
84            IntValue::Unsigned(value) => self.encode_unsigned_int_value(value),
85        }
86    }
87
88    // MARK: - Header
89
90    /// Encodes a integer value's header.
91    pub fn encode_int_header(&mut self, header: &IntHeader) -> Result<()> {
92        let mut byte = IntHeader::TYPE_BITS;
93
94        match header {
95            IntHeader::Compact(CompactIntHeader { is_signed, bits }) => {
96                byte |= IntHeader::COMPACT_VARIANT_BIT;
97                byte |= bits_if(IntHeader::SIGNEDNESS_BIT, *is_signed);
98                byte |= bits & IntHeader::COMPACT_VALUE_BITS;
99
100                #[cfg(feature = "tracing")]
101                tracing::debug!(
102                    byte = crate::binary::fmt_byte(byte),
103                    is_compact = true,
104                    is_signed = is_signed,
105                    bits = bits
106                );
107            }
108            IntHeader::Extended(ExtendedIntHeader { is_signed, width }) => {
109                byte |= bits_if(IntHeader::SIGNEDNESS_BIT, *is_signed);
110                byte |= (width - 1) & IntHeader::EXTENDED_WIDTH_BITS;
111
112                #[cfg(feature = "tracing")]
113                tracing::debug!(
114                    byte = crate::binary::fmt_byte(byte),
115                    is_compact = false,
116                    is_signed = is_signed,
117                    width = width
118                );
119            }
120        }
121
122        // Push the header byte:
123        self.push_byte(byte)
124    }
125
126    /// Creates a header for a signed integer value.
127    pub fn header_for_signed_int<T>(&self, value: T) -> IntHeader
128    where
129        T: Signed + WithPackedBeBytes,
130    {
131        IntHeader::for_signed(value, self.config.ints.packing)
132    }
133
134    /// Creates a header for an unsigned integer value.
135    pub fn header_for_unsigned_int<T>(&self, value: T) -> IntHeader
136    where
137        T: Unsigned + WithPackedBeBytes,
138    {
139        IntHeader::for_unsigned(value, self.config.ints.packing)
140    }
141
142    #[inline]
143    fn encode_signed_int<S>(&mut self, value: S) -> Result<()>
144    where
145        S: Signed + WithPackedBeBytes,
146    {
147        let packing_mode = self.config.ints.packing;
148        value.with_packed_be_bytes(packing_mode, |bytes| {
149            let header = IntHeader::for_int_be_bytes(true, bytes, packing_mode);
150
151            self.encode_int_header(&header)?;
152
153            #[cfg(feature = "tracing")]
154            tracing::debug!(bytes = bytes);
155
156            if matches!(header, IntHeader::Extended(_)) {
157                self.push_bytes(bytes)?;
158            }
159
160            Ok(())
161        })
162    }
163
164    #[inline]
165    fn encode_unsigned_int<U>(&mut self, value: U) -> Result<()>
166    where
167        U: Unsigned + WithPackedBeBytes,
168    {
169        let packing_mode = self.config.ints.packing;
170        value.with_packed_be_bytes(packing_mode, |bytes| {
171            let header = IntHeader::for_int_be_bytes(false, bytes, packing_mode);
172
173            self.encode_int_header(&header)?;
174
175            #[cfg(feature = "tracing")]
176            tracing::debug!(bytes = bytes);
177
178            if matches!(header, IntHeader::Extended(_)) {
179                self.push_bytes(bytes)?;
180            }
181
182            Ok(())
183        })
184    }
185}