Skip to main content

qubit_io/ext/
zig_zag_read_ext.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10use std::io::{
11    Read,
12    Result,
13};
14
15use crate::Leb128ReadExt;
16
17/// Extension methods for reading ZigZag encoded signed integers.
18///
19/// ZigZag maps signed integers to unsigned integers so small negative values
20/// still have short varint encodings. The mapped unsigned value is read with
21/// unsigned LEB128. The ZigZag mapping follows the Protocol Buffers encoding
22/// guide:
23/// <https://protobuf.dev/programming-guides/encoding/#signed-integers>.
24///
25/// Methods with the `_strict` suffix also require the unsigned LEB128 payload
26/// to use canonical LEB128 encoding.
27pub trait ZigZagReadExt: Read {
28    /// Reads a ZigZag encoded `i8`.
29    ///
30    /// # Returns
31    /// The decoded signed value.
32    ///
33    /// # Errors
34    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
35    /// unsigned LEB128 input, or another I/O error from the underlying reader.
36    fn read_zigzag_i8(&mut self) -> Result<i8>;
37
38    /// Reads a canonical ZigZag encoded `i8`.
39    ///
40    /// # Returns
41    /// The decoded signed value.
42    ///
43    /// # Errors
44    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
45    /// or non-canonical unsigned LEB128 input, or another I/O error from the
46    /// underlying reader.
47    fn read_zigzag_i8_strict(&mut self) -> Result<i8>;
48
49    /// Reads a ZigZag encoded `i16`.
50    ///
51    /// # Returns
52    /// The decoded signed value.
53    ///
54    /// # Errors
55    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
56    /// unsigned LEB128 input, or another I/O error from the underlying reader.
57    fn read_zigzag_i16(&mut self) -> Result<i16>;
58
59    /// Reads a canonical ZigZag encoded `i16`.
60    ///
61    /// # Returns
62    /// The decoded signed value.
63    ///
64    /// # Errors
65    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
66    /// or non-canonical unsigned LEB128 input, or another I/O error from the
67    /// underlying reader.
68    fn read_zigzag_i16_strict(&mut self) -> Result<i16>;
69
70    /// Reads a ZigZag encoded `i32`.
71    ///
72    /// # Returns
73    /// The decoded signed value.
74    ///
75    /// # Errors
76    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
77    /// unsigned LEB128 input, or another I/O error from the underlying reader.
78    fn read_zigzag_i32(&mut self) -> Result<i32>;
79
80    /// Reads a canonical ZigZag encoded `i32`.
81    ///
82    /// # Returns
83    /// The decoded signed value.
84    ///
85    /// # Errors
86    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
87    /// or non-canonical unsigned LEB128 input, or another I/O error from the
88    /// underlying reader.
89    fn read_zigzag_i32_strict(&mut self) -> Result<i32>;
90
91    /// Reads a ZigZag encoded `i64`.
92    ///
93    /// # Returns
94    /// The decoded signed value.
95    ///
96    /// # Errors
97    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
98    /// unsigned LEB128 input, or another I/O error from the underlying reader.
99    fn read_zigzag_i64(&mut self) -> Result<i64>;
100
101    /// Reads a canonical ZigZag encoded `i64`.
102    ///
103    /// # Returns
104    /// The decoded signed value.
105    ///
106    /// # Errors
107    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
108    /// or non-canonical unsigned LEB128 input, or another I/O error from the
109    /// underlying reader.
110    fn read_zigzag_i64_strict(&mut self) -> Result<i64>;
111
112    /// Reads a ZigZag encoded `i128`.
113    ///
114    /// # Returns
115    /// The decoded signed value.
116    ///
117    /// # Errors
118    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
119    /// unsigned LEB128 input, or another I/O error from the underlying reader.
120    fn read_zigzag_i128(&mut self) -> Result<i128>;
121
122    /// Reads a canonical ZigZag encoded `i128`.
123    ///
124    /// # Returns
125    /// The decoded signed value.
126    ///
127    /// # Errors
128    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
129    /// or non-canonical unsigned LEB128 input, or another I/O error from the
130    /// underlying reader.
131    fn read_zigzag_i128_strict(&mut self) -> Result<i128>;
132
133    /// Reads a ZigZag encoded `isize`.
134    ///
135    /// # Returns
136    /// The decoded signed value.
137    ///
138    /// # Errors
139    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
140    /// unsigned LEB128 input, or another I/O error from the underlying reader.
141    fn read_zigzag_isize(&mut self) -> Result<isize>;
142
143    /// Reads a canonical ZigZag encoded `isize`.
144    ///
145    /// # Returns
146    /// The decoded signed value.
147    ///
148    /// # Errors
149    /// Returns `UnexpectedEof` for truncated input, `InvalidData` for malformed
150    /// or non-canonical unsigned LEB128 input, or another I/O error from the
151    /// underlying reader.
152    fn read_zigzag_isize_strict(&mut self) -> Result<isize>;
153}
154
155impl<T> ZigZagReadExt for T
156where
157    T: Read + ?Sized,
158{
159    #[inline]
160    fn read_zigzag_i8(&mut self) -> Result<i8> {
161        self.read_uleb_u8().map(decode_zigzag_u8)
162    }
163
164    #[inline]
165    fn read_zigzag_i8_strict(&mut self) -> Result<i8> {
166        self.read_uleb_u8_strict().map(decode_zigzag_u8)
167    }
168
169    #[inline]
170    fn read_zigzag_i16(&mut self) -> Result<i16> {
171        self.read_uleb_u16().map(decode_zigzag_u16)
172    }
173
174    #[inline]
175    fn read_zigzag_i16_strict(&mut self) -> Result<i16> {
176        self.read_uleb_u16_strict().map(decode_zigzag_u16)
177    }
178
179    #[inline]
180    fn read_zigzag_i32(&mut self) -> Result<i32> {
181        self.read_uleb_u32().map(decode_zigzag_u32)
182    }
183
184    #[inline]
185    fn read_zigzag_i32_strict(&mut self) -> Result<i32> {
186        self.read_uleb_u32_strict().map(decode_zigzag_u32)
187    }
188
189    #[inline]
190    fn read_zigzag_i64(&mut self) -> Result<i64> {
191        self.read_uleb_u64().map(decode_zigzag_u64)
192    }
193
194    #[inline]
195    fn read_zigzag_i64_strict(&mut self) -> Result<i64> {
196        self.read_uleb_u64_strict().map(decode_zigzag_u64)
197    }
198
199    #[inline]
200    fn read_zigzag_i128(&mut self) -> Result<i128> {
201        self.read_uleb_u128().map(decode_zigzag_u128)
202    }
203
204    #[inline]
205    fn read_zigzag_i128_strict(&mut self) -> Result<i128> {
206        self.read_uleb_u128_strict().map(decode_zigzag_u128)
207    }
208
209    #[inline]
210    fn read_zigzag_isize(&mut self) -> Result<isize> {
211        self.read_uleb_usize().map(decode_zigzag_usize)
212    }
213
214    #[inline]
215    fn read_zigzag_isize_strict(&mut self) -> Result<isize> {
216        self.read_uleb_usize_strict().map(decode_zigzag_usize)
217    }
218}
219
220/// Decodes a ZigZag mapped `u8`.
221///
222/// # Parameters
223/// - `value`: ZigZag mapped unsigned value.
224///
225/// # Returns
226/// Decoded signed value.
227fn decode_zigzag_u8(value: u8) -> i8 {
228    ((value >> 1) as i8) ^ (-((value & 1) as i8))
229}
230
231/// Decodes a ZigZag mapped `u16`.
232///
233/// # Parameters
234/// - `value`: ZigZag mapped unsigned value.
235///
236/// # Returns
237/// Decoded signed value.
238fn decode_zigzag_u16(value: u16) -> i16 {
239    ((value >> 1) as i16) ^ (-((value & 1) as i16))
240}
241
242/// Decodes a ZigZag mapped `u32`.
243///
244/// # Parameters
245/// - `value`: ZigZag mapped unsigned value.
246///
247/// # Returns
248/// Decoded signed value.
249fn decode_zigzag_u32(value: u32) -> i32 {
250    ((value >> 1) as i32) ^ (-((value & 1) as i32))
251}
252
253/// Decodes a ZigZag mapped `u64`.
254///
255/// # Parameters
256/// - `value`: ZigZag mapped unsigned value.
257///
258/// # Returns
259/// Decoded signed value.
260fn decode_zigzag_u64(value: u64) -> i64 {
261    ((value >> 1) as i64) ^ (-((value & 1) as i64))
262}
263
264/// Decodes a ZigZag mapped `u128`.
265///
266/// # Parameters
267/// - `value`: ZigZag mapped unsigned value.
268///
269/// # Returns
270/// Decoded signed value.
271fn decode_zigzag_u128(value: u128) -> i128 {
272    ((value >> 1) as i128) ^ (-((value & 1) as i128))
273}
274
275/// Decodes a ZigZag mapped `usize`.
276///
277/// # Parameters
278/// - `value`: ZigZag mapped unsigned value.
279///
280/// # Returns
281/// Decoded signed value.
282fn decode_zigzag_usize(value: usize) -> isize {
283    ((value >> 1) as isize) ^ (-((value & 1) as isize))
284}