lilliput_core/decoder/
int.rs1use core::num::TryFromIntError;
2
3use num_traits::{Signed, Unsigned};
4
5use crate::{
6 error::{Error, Result},
7 header::{CompactIntHeader, ExtendedIntHeader, IntHeader},
8 marker::Marker,
9 num::FromZigZag,
10 value::{IntValue, SignedIntValue, UnsignedIntValue},
11};
12
13use super::{Decoder, Read};
14
15impl<'de, R> Decoder<R>
16where
17 R: Read<'de>,
18{
19 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
23 pub fn decode_i8(&mut self) -> Result<i8> {
24 self.decode_signed_int()
25 }
26
27 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
29 pub fn decode_i16(&mut self) -> Result<i16> {
30 self.decode_signed_int()
31 }
32
33 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
35 pub fn decode_i32(&mut self) -> Result<i32> {
36 self.decode_signed_int()
37 }
38
39 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
41 pub fn decode_i64(&mut self) -> Result<i64> {
42 self.decode_signed_int()
43 }
44
45 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
47 pub fn decode_u8(&mut self) -> Result<u8> {
48 self.decode_unsigned_int()
49 }
50
51 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
53 pub fn decode_u16(&mut self) -> Result<u16> {
54 self.decode_unsigned_int()
55 }
56
57 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
59 pub fn decode_u32(&mut self) -> Result<u32> {
60 self.decode_unsigned_int()
61 }
62
63 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
65 pub fn decode_u64(&mut self) -> Result<u64> {
66 self.decode_unsigned_int()
67 }
68
69 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
71 pub fn decode_signed_int<T>(&mut self) -> Result<T>
72 where
73 T: Signed + TryFrom<SignedIntValue, Error = TryFromIntError>,
74 {
75 let pos = self.pos;
76
77 self.decode_signed_int_value()?
78 .try_into()
79 .map_err(|_| Error::number_out_of_range(Some(pos)))
80 }
81
82 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
84 pub fn decode_unsigned_int<T>(&mut self) -> Result<T>
85 where
86 T: Unsigned + TryFrom<UnsignedIntValue, Error = TryFromIntError>,
87 {
88 let pos = self.pos;
89
90 self.decode_unsigned_int_value()?
91 .try_into()
92 .map_err(|_| Error::number_out_of_range(Some(pos)))
93 }
94
95 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
97 pub fn decode_signed_int_value(&mut self) -> Result<SignedIntValue> {
98 let pos = self.pos;
99
100 self.decode_int_value()?
101 .to_signed()
102 .map_err(|_| Error::number_out_of_range(Some(pos)))
103 }
104
105 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
107 pub fn decode_unsigned_int_value(&mut self) -> Result<UnsignedIntValue> {
108 let pos = self.pos;
109
110 self.decode_int_value()?
111 .to_unsigned()
112 .map_err(|_| Error::number_out_of_range(Some(pos)))
113 }
114
115 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
117 pub fn decode_int_value(&mut self) -> Result<IntValue> {
118 let header = self.decode_int_header()?;
119 self.decode_int_value_of(header)
120 }
121
122 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
126 pub fn decode_int_header(&mut self) -> Result<IntHeader> {
127 let byte = self.pull_byte_expecting(Marker::Int)?;
128
129 if (byte & IntHeader::COMPACT_VARIANT_BIT) != 0b0 {
130 let is_signed = (byte & IntHeader::SIGNEDNESS_BIT) != 0b0;
131 let bits = byte & IntHeader::COMPACT_VALUE_BITS;
132
133 #[cfg(feature = "tracing")]
134 tracing::debug!(
135 byte = crate::binary::fmt_byte(byte),
136 is_compact = true,
137 is_signed = is_signed,
138 bits = bits
139 );
140
141 Ok(IntHeader::Compact(CompactIntHeader { is_signed, bits }))
142 } else {
143 let is_signed = (byte & IntHeader::SIGNEDNESS_BIT) != 0b0;
144 let width = 1 + (byte & IntHeader::EXTENDED_WIDTH_BITS);
145
146 #[cfg(feature = "tracing")]
147 tracing::debug!(
148 byte = crate::binary::fmt_byte(byte),
149 is_compact = false,
150 is_signed = is_signed,
151 width = width
152 );
153
154 Ok(IntHeader::Extended(ExtendedIntHeader { is_signed, width }))
155 }
156 }
157
158 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
162 pub fn skip_int_value_of(&mut self, header: IntHeader) -> Result<()> {
163 let header = match header {
164 IntHeader::Compact(_) => return Ok(()),
165 IntHeader::Extended(header) => header,
166 };
167
168 self.reader.skip(header.width().into())
169 }
170
171 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
175 pub fn decode_int_value_of(&mut self, header: IntHeader) -> Result<IntValue> {
176 let (is_signed, width): (bool, usize) = match header {
177 IntHeader::Compact(CompactIntHeader { is_signed, bits }) => {
178 if is_signed {
179 let value = i8::from_zig_zag(bits);
180
181 #[cfg(feature = "tracing")]
182 tracing::debug!(value = value);
183
184 return Ok(IntValue::Signed(SignedIntValue::I8(value)));
185 } else {
186 let value = bits;
187
188 #[cfg(feature = "tracing")]
189 tracing::debug!(value = value);
190
191 return Ok(IntValue::Unsigned(UnsignedIntValue::U8(value)));
192 }
193 }
194 IntHeader::Extended(ExtendedIntHeader { is_signed, width }) => {
195 (is_signed, width as usize)
196 }
197 };
198
199 match width {
200 1..=1 => {
201 const MAX_WIDTH: usize = 1;
202 let mut padded_be_bytes: [u8; MAX_WIDTH] = [0b0; MAX_WIDTH];
203 self.pull_bytes_into(&mut padded_be_bytes[(MAX_WIDTH - width)..])?;
204
205 #[cfg(feature = "tracing")]
206 let bytes = crate::binary::fmt_bytes(&padded_be_bytes[(MAX_WIDTH - width)..]);
207
208 let value = u8::from_be_bytes(padded_be_bytes);
209
210 if is_signed {
211 let value = i8::from_zig_zag(value);
212
213 #[cfg(feature = "tracing")]
214 tracing::debug!(bytes = bytes, value = value);
215
216 Ok(IntValue::Signed(SignedIntValue::I8(value)))
217 } else {
218 #[cfg(feature = "tracing")]
219 tracing::debug!(bytes = bytes, value = value);
220
221 Ok(IntValue::Unsigned(UnsignedIntValue::U8(value)))
222 }
223 }
224 2..=2 => {
225 const MAX_WIDTH: usize = 2;
226 let mut padded_be_bytes: [u8; MAX_WIDTH] = [0b0; MAX_WIDTH];
227 self.pull_bytes_into(&mut padded_be_bytes[(MAX_WIDTH - width)..])?;
228
229 #[cfg(feature = "tracing")]
230 let bytes = crate::binary::fmt_bytes(&padded_be_bytes[(MAX_WIDTH - width)..]);
231
232 let value = u16::from_be_bytes(padded_be_bytes);
233
234 if is_signed {
235 let value = i16::from_zig_zag(value);
236
237 #[cfg(feature = "tracing")]
238 tracing::debug!(bytes = bytes, value = value);
239
240 Ok(IntValue::Signed(SignedIntValue::I16(value)))
241 } else {
242 #[cfg(feature = "tracing")]
243 tracing::debug!(bytes = bytes, value = value);
244
245 Ok(IntValue::Unsigned(UnsignedIntValue::U16(value)))
246 }
247 }
248 3..=4 => {
249 const MAX_WIDTH: usize = 4;
250 let mut padded_be_bytes: [u8; MAX_WIDTH] = [0b0; MAX_WIDTH];
251 self.pull_bytes_into(&mut padded_be_bytes[(MAX_WIDTH - width)..])?;
252
253 #[cfg(feature = "tracing")]
254 let bytes = crate::binary::fmt_bytes(&padded_be_bytes[(MAX_WIDTH - width)..]);
255
256 let value = u32::from_be_bytes(padded_be_bytes);
257
258 if is_signed {
259 let value = i32::from_zig_zag(value);
260
261 #[cfg(feature = "tracing")]
262 tracing::debug!(bytes = bytes, value = value);
263
264 Ok(IntValue::Signed(SignedIntValue::I32(value)))
265 } else {
266 #[cfg(feature = "tracing")]
267 tracing::debug!(bytes = bytes, value = value);
268
269 Ok(IntValue::Unsigned(UnsignedIntValue::U32(value)))
270 }
271 }
272 5..=8 => {
273 const MAX_WIDTH: usize = 8;
274 let mut padded_be_bytes: [u8; MAX_WIDTH] = [0b0; MAX_WIDTH];
275 self.pull_bytes_into(&mut padded_be_bytes[(MAX_WIDTH - width)..])?;
276
277 #[cfg(feature = "tracing")]
278 let bytes = crate::binary::fmt_bytes(&padded_be_bytes[(MAX_WIDTH - width)..]);
279
280 let value = u64::from_be_bytes(padded_be_bytes);
281
282 if is_signed {
283 let value = i64::from_zig_zag(value);
284
285 #[cfg(feature = "tracing")]
286 tracing::debug!(bytes = bytes, value = value);
287
288 Ok(IntValue::Signed(SignedIntValue::I64(value)))
289 } else {
290 #[cfg(feature = "tracing")]
291 tracing::debug!(bytes = bytes, value = value);
292
293 Ok(IntValue::Unsigned(UnsignedIntValue::U64(value)))
294 }
295 }
296 _ => unreachable!(),
297 }
298 }
299}