Skip to main content

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}