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}