Skip to main content

qubit_io/ext/
zig_zag_write_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    Result,
12    Write,
13};
14
15use crate::Leb128WriteExt;
16
17/// Extension methods for writing 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 written with
21/// unsigned LEB128. The ZigZag mapping follows the Protocol Buffers encoding
22/// guide:
23/// <https://protobuf.dev/programming-guides/encoding/#signed-integers>.
24pub trait ZigZagWriteExt: Write {
25    /// Writes a ZigZag encoded `i8`.
26    ///
27    /// # Parameters
28    /// - `value`: Value to encode.
29    ///
30    /// # Errors
31    /// Returns an I/O error from the underlying writer.
32    fn write_zigzag_i8(&mut self, value: i8) -> Result<()>;
33
34    /// Writes a ZigZag encoded `i16`.
35    ///
36    /// # Parameters
37    /// - `value`: Value to encode.
38    ///
39    /// # Errors
40    /// Returns an I/O error from the underlying writer.
41    fn write_zigzag_i16(&mut self, value: i16) -> Result<()>;
42
43    /// Writes a ZigZag encoded `i32`.
44    ///
45    /// # Parameters
46    /// - `value`: Value to encode.
47    ///
48    /// # Errors
49    /// Returns an I/O error from the underlying writer.
50    fn write_zigzag_i32(&mut self, value: i32) -> Result<()>;
51
52    /// Writes a ZigZag encoded `i64`.
53    ///
54    /// # Parameters
55    /// - `value`: Value to encode.
56    ///
57    /// # Errors
58    /// Returns an I/O error from the underlying writer.
59    fn write_zigzag_i64(&mut self, value: i64) -> Result<()>;
60
61    /// Writes a ZigZag encoded `i128`.
62    ///
63    /// # Parameters
64    /// - `value`: Value to encode.
65    ///
66    /// # Errors
67    /// Returns an I/O error from the underlying writer.
68    fn write_zigzag_i128(&mut self, value: i128) -> Result<()>;
69
70    /// Writes a ZigZag encoded `isize`.
71    ///
72    /// # Parameters
73    /// - `value`: Value to encode.
74    ///
75    /// # Errors
76    /// Returns an I/O error from the underlying writer.
77    fn write_zigzag_isize(&mut self, value: isize) -> Result<()>;
78}
79
80impl<T> ZigZagWriteExt for T
81where
82    T: Write + ?Sized,
83{
84    #[inline]
85    fn write_zigzag_i8(&mut self, value: i8) -> Result<()> {
86        self.write_uleb_u8(encode_zigzag_i8(value))
87    }
88
89    #[inline]
90    fn write_zigzag_i16(&mut self, value: i16) -> Result<()> {
91        self.write_uleb_u16(encode_zigzag_i16(value))
92    }
93
94    #[inline]
95    fn write_zigzag_i32(&mut self, value: i32) -> Result<()> {
96        self.write_uleb_u32(encode_zigzag_i32(value))
97    }
98
99    #[inline]
100    fn write_zigzag_i64(&mut self, value: i64) -> Result<()> {
101        self.write_uleb_u64(encode_zigzag_i64(value))
102    }
103
104    #[inline]
105    fn write_zigzag_i128(&mut self, value: i128) -> Result<()> {
106        self.write_uleb_u128(encode_zigzag_i128(value))
107    }
108
109    #[inline]
110    fn write_zigzag_isize(&mut self, value: isize) -> Result<()> {
111        self.write_uleb_usize(encode_zigzag_isize(value))
112    }
113}
114
115/// Encodes an `i8` with ZigZag mapping.
116///
117/// # Parameters
118/// - `value`: Signed value to map.
119///
120/// # Returns
121/// ZigZag mapped unsigned value.
122fn encode_zigzag_i8(value: i8) -> u8 {
123    ((value as u8) << 1) ^ ((value >> 7) as u8)
124}
125
126/// Encodes an `i16` with ZigZag mapping.
127///
128/// # Parameters
129/// - `value`: Signed value to map.
130///
131/// # Returns
132/// ZigZag mapped unsigned value.
133fn encode_zigzag_i16(value: i16) -> u16 {
134    ((value as u16) << 1) ^ ((value >> 15) as u16)
135}
136
137/// Encodes an `i32` with ZigZag mapping.
138///
139/// # Parameters
140/// - `value`: Signed value to map.
141///
142/// # Returns
143/// ZigZag mapped unsigned value.
144fn encode_zigzag_i32(value: i32) -> u32 {
145    ((value as u32) << 1) ^ ((value >> 31) as u32)
146}
147
148/// Encodes an `i64` with ZigZag mapping.
149///
150/// # Parameters
151/// - `value`: Signed value to map.
152///
153/// # Returns
154/// ZigZag mapped unsigned value.
155fn encode_zigzag_i64(value: i64) -> u64 {
156    ((value as u64) << 1) ^ ((value >> 63) as u64)
157}
158
159/// Encodes an `i128` with ZigZag mapping.
160///
161/// # Parameters
162/// - `value`: Signed value to map.
163///
164/// # Returns
165/// ZigZag mapped unsigned value.
166fn encode_zigzag_i128(value: i128) -> u128 {
167    ((value as u128) << 1) ^ ((value >> 127) as u128)
168}
169
170/// Encodes an `isize` with ZigZag mapping.
171///
172/// # Parameters
173/// - `value`: Signed value to map.
174///
175/// # Returns
176/// ZigZag mapped unsigned value.
177fn encode_zigzag_isize(value: isize) -> usize {
178    ((value as usize) << 1) ^ ((value >> (isize::BITS - 1)) as usize)
179}