qubit_io/ext/leb128_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
15/// Extension methods for writing LEB128 encoded integers.
16///
17/// Unsigned methods write unsigned LEB128 values, and signed methods write
18/// signed LEB128 values. Both forms encode seven payload bits per byte in
19/// least-significant group first order, with the high bit marking
20/// continuation. The integer encoding is described by the WebAssembly Core
21/// binary format:
22/// <https://webassembly.github.io/spec/core/binary/values.html#integers>.
23pub trait Leb128WriteExt: Write {
24 /// Writes an unsigned LEB128 `u8`.
25 ///
26 /// # Parameters
27 /// - `value`: Value to encode.
28 ///
29 /// # Errors
30 /// Returns an I/O error from the underlying writer.
31 fn write_uleb_u8(&mut self, value: u8) -> Result<()>;
32
33 /// Writes an unsigned LEB128 `u16`.
34 ///
35 /// # Parameters
36 /// - `value`: Value to encode.
37 ///
38 /// # Errors
39 /// Returns an I/O error from the underlying writer.
40 fn write_uleb_u16(&mut self, value: u16) -> Result<()>;
41
42 /// Writes an unsigned LEB128 `u32`.
43 ///
44 /// # Parameters
45 /// - `value`: Value to encode.
46 ///
47 /// # Errors
48 /// Returns an I/O error from the underlying writer.
49 fn write_uleb_u32(&mut self, value: u32) -> Result<()>;
50
51 /// Writes an unsigned LEB128 `u64`.
52 ///
53 /// # Parameters
54 /// - `value`: Value to encode.
55 ///
56 /// # Errors
57 /// Returns an I/O error from the underlying writer.
58 fn write_uleb_u64(&mut self, value: u64) -> Result<()>;
59
60 /// Writes an unsigned LEB128 `u128`.
61 ///
62 /// # Parameters
63 /// - `value`: Value to encode.
64 ///
65 /// # Errors
66 /// Returns an I/O error from the underlying writer.
67 fn write_uleb_u128(&mut self, value: u128) -> Result<()>;
68
69 /// Writes an unsigned LEB128 `usize`.
70 ///
71 /// # Parameters
72 /// - `value`: Value to encode.
73 ///
74 /// # Errors
75 /// Returns an I/O error from the underlying writer.
76 fn write_uleb_usize(&mut self, value: usize) -> Result<()>;
77
78 /// Writes a signed LEB128 `i8`.
79 ///
80 /// # Parameters
81 /// - `value`: Value to encode.
82 ///
83 /// # Errors
84 /// Returns an I/O error from the underlying writer.
85 fn write_sleb_i8(&mut self, value: i8) -> Result<()>;
86
87 /// Writes a signed LEB128 `i16`.
88 ///
89 /// # Parameters
90 /// - `value`: Value to encode.
91 ///
92 /// # Errors
93 /// Returns an I/O error from the underlying writer.
94 fn write_sleb_i16(&mut self, value: i16) -> Result<()>;
95
96 /// Writes a signed LEB128 `i32`.
97 ///
98 /// # Parameters
99 /// - `value`: Value to encode.
100 ///
101 /// # Errors
102 /// Returns an I/O error from the underlying writer.
103 fn write_sleb_i32(&mut self, value: i32) -> Result<()>;
104
105 /// Writes a signed LEB128 `i64`.
106 ///
107 /// # Parameters
108 /// - `value`: Value to encode.
109 ///
110 /// # Errors
111 /// Returns an I/O error from the underlying writer.
112 fn write_sleb_i64(&mut self, value: i64) -> Result<()>;
113
114 /// Writes a signed LEB128 `i128`.
115 ///
116 /// # Parameters
117 /// - `value`: Value to encode.
118 ///
119 /// # Errors
120 /// Returns an I/O error from the underlying writer.
121 fn write_sleb_i128(&mut self, value: i128) -> Result<()>;
122
123 /// Writes a signed LEB128 `isize`.
124 ///
125 /// # Parameters
126 /// - `value`: Value to encode.
127 ///
128 /// # Errors
129 /// Returns an I/O error from the underlying writer.
130 fn write_sleb_isize(&mut self, value: isize) -> Result<()>;
131}
132
133impl<T> Leb128WriteExt for T
134where
135 T: Write + ?Sized,
136{
137 #[inline]
138 fn write_uleb_u8(&mut self, value: u8) -> Result<()> {
139 write_uleb(self, value as u128)
140 }
141
142 #[inline]
143 fn write_uleb_u16(&mut self, value: u16) -> Result<()> {
144 write_uleb(self, value as u128)
145 }
146
147 #[inline]
148 fn write_uleb_u32(&mut self, value: u32) -> Result<()> {
149 write_uleb(self, value as u128)
150 }
151
152 #[inline]
153 fn write_uleb_u64(&mut self, value: u64) -> Result<()> {
154 write_uleb(self, value as u128)
155 }
156
157 #[inline]
158 fn write_uleb_u128(&mut self, value: u128) -> Result<()> {
159 write_uleb(self, value)
160 }
161
162 #[inline]
163 fn write_uleb_usize(&mut self, value: usize) -> Result<()> {
164 write_uleb(self, value as u128)
165 }
166
167 #[inline]
168 fn write_sleb_i8(&mut self, value: i8) -> Result<()> {
169 write_sleb(self, value as i128)
170 }
171
172 #[inline]
173 fn write_sleb_i16(&mut self, value: i16) -> Result<()> {
174 write_sleb(self, value as i128)
175 }
176
177 #[inline]
178 fn write_sleb_i32(&mut self, value: i32) -> Result<()> {
179 write_sleb(self, value as i128)
180 }
181
182 #[inline]
183 fn write_sleb_i64(&mut self, value: i64) -> Result<()> {
184 write_sleb(self, value as i128)
185 }
186
187 #[inline]
188 fn write_sleb_i128(&mut self, value: i128) -> Result<()> {
189 write_sleb(self, value)
190 }
191
192 #[inline]
193 fn write_sleb_isize(&mut self, value: isize) -> Result<()> {
194 write_sleb(self, value as i128)
195 }
196}
197
198/// Writes an unsigned LEB128 integer.
199///
200/// # Parameters
201/// - `writer`: Destination writer. It may be a sized writer or a writer trait
202/// object.
203/// - `value`: Value to encode.
204///
205/// # Errors
206/// Returns an I/O error from `writer`.
207fn write_uleb<T>(writer: &mut T, value: u128) -> Result<()>
208where
209 T: Write + ?Sized,
210{
211 let mut remaining = value;
212 while remaining > 0x7f {
213 writer.write_all(&[((remaining as u8) & 0x7f) | 0x80])?;
214 remaining >>= 7;
215 }
216 writer.write_all(&[remaining as u8])
217}
218
219/// Writes a signed LEB128 integer.
220///
221/// # Parameters
222/// - `writer`: Destination writer. It may be a sized writer or a writer trait
223/// object.
224/// - `value`: Value to encode.
225///
226/// # Errors
227/// Returns an I/O error from `writer`.
228fn write_sleb<T>(writer: &mut T, value: i128) -> Result<()>
229where
230 T: Write + ?Sized,
231{
232 let mut remaining = value;
233 loop {
234 let byte = (remaining as u8) & 0x7f;
235 remaining >>= 7;
236 let is_done = (remaining == 0 && byte & 0x40 == 0) || (remaining == -1 && byte & 0x40 != 0);
237 if is_done {
238 return writer.write_all(&[byte]);
239 }
240 writer.write_all(&[byte | 0x80])?;
241 }
242}