uleb128/
io.rs

1use std::io::{Read, Write};
2
3use crate::error::{Error, Result};
4use crate::{ULEB128_U32_MAX_LENGTH, ULEB128_U64_MAX_LENGTH};
5
6const VALUE_MASK: u8 = 0b0111_1111;
7const VALUE_LENGTH: usize = 7;
8
9macro_rules! read_method_body {
10    ($self:expr, $ty:ty, $len:expr) => {{
11        let mut value = 0;
12        let mut bytes_read = 0;
13
14        loop {
15            let mut buf = [0; 1];
16            $self.read_exact(&mut buf)?;
17
18            let byte = buf[0];
19            let byte_value = (byte & VALUE_MASK) as $ty;
20            value |= byte_value << (VALUE_LENGTH * bytes_read);
21
22            bytes_read += 1;
23            if bytes_read > $len {
24                return Err(Error::LengthOverflow($len));
25            }
26
27            if (byte & !VALUE_MASK) == 0 {
28                break;
29            }
30        }
31
32        Ok(value)
33    }};
34}
35
36/// Extends [`Read`][reader] with methods for reading numbers encoded in
37/// [unsigned LEB128*]
38///
39/// # Examples
40///
41/// Read unsigned LEB128 integers from a [reader]:
42///
43/// ```
44/// use std::io::Cursor;
45/// use uleb128::ReadULeb128Ext;
46///
47/// let mut rdr = Cursor::new(vec![
48///     0b0111_1111, // 127
49///     0b1000_0000, 0b0000_0001, // 128
50///     0b1000_0001, 0b0000_0001 // 129
51/// ]);
52///
53/// assert_eq!(127, rdr.read_uleb128_u32().unwrap());
54/// assert_eq!(128, rdr.read_uleb128_u32().unwrap());
55/// assert_eq!(129, rdr.read_uleb128_u32().unwrap());
56/// ```
57///
58/// [unsigned LEB128]: https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128
59/// [reader]: https://doc.rust-lang.org/std/io/trait.Read.html
60pub trait ReadULeb128Ext: Read {
61    /// Read an unsigned 32-bit integer that's encoded in [unsigned LEB128]
62    /// from the underlying [reader].
63    ///
64    /// # Errors
65    ///
66    /// If this function encounters an error when performing an I/O operation,
67    /// then this function immediately returns an [`Error::Io`] to propagate the
68    /// [`io::Error`] returned by an internal call to [`Read::read_exact`].
69    ///
70    /// If this function encounters an encoded number with a length in bytes
71    /// greater than what is permitted, an [`Error::LengthOverflow`] is
72    /// immediately returned.
73    ///
74    /// # Examples
75    ///
76    /// Read an unsigned LEB128-encoded, 32-bit integer:
77    ///
78    /// ```
79    /// use std::io::Cursor;
80    /// use uleb128::ReadULeb128Ext;
81    ///
82    /// let mut rdr = Cursor::new(vec![
83    ///     // 2_147_483_647
84    ///     0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111, 0b0000_0111
85    /// ]);
86    ///
87    /// assert_eq!(2_147_483_647, rdr.read_uleb128_u32().unwrap());
88    /// ```
89    ///
90    /// [unsigned LEB128]: https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128
91    /// [reader]: https://doc.rust-lang.org/std/io/trait.Read.html
92    /// [`io::Error`]: std::io::Error
93    fn read_uleb128_u32(&mut self) -> Result<u32> {
94        read_method_body!(self, u32, ULEB128_U32_MAX_LENGTH)
95    }
96
97    /// Read an unsigned 64-bit integer that's encoded in [unsigned LEB128]
98    /// from the underlying [reader].
99    ///
100    /// # Errors
101    ///
102    /// If this function encounters an error when performing an I/O operation,
103    /// then this function immediately returns an [`Error::Io`] to propagate the
104    /// [`io::Error`] returned by an internal call to [`Read::read_exact`].
105    ///
106    /// If this function encounters an encoded number with a length in bytes
107    /// greater than what is permitted, an [`Error::LengthOverflow`] is
108    /// immediately returned.
109    ///
110    /// # Examples
111    ///
112    /// Read an unsigned LEB128-encoded, 64-bit integer:
113    ///
114    /// ```
115    /// use std::io::Cursor;
116    /// use uleb128::ReadULeb128Ext;
117    ///
118    /// let mut rdr = Cursor::new(vec![
119    ///     // 9_223_372_036_854_775_807
120    ///     0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111,
121    ///     0b1111_1111, 0b1111_1111, 0b1111_1111, 0b0111_1111
122    /// ]);
123    ///
124    /// assert_eq!(9_223_372_036_854_775_807, rdr.read_uleb128_u64().unwrap());
125    /// ```
126    ///
127    /// [unsigned LEB128]: https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128
128    /// [reader]: https://doc.rust-lang.org/std/io/trait.Read.html
129    /// [`io::Error`]: std::io::Error
130    fn read_uleb128_u64(&mut self) -> Result<u64> {
131        read_method_body!(self, u64, ULEB128_U64_MAX_LENGTH)
132    }
133}
134
135impl<R: Read + ?Sized> ReadULeb128Ext for R {}
136
137macro_rules! write_method_body {
138    ($self:expr, $value:ident, $ty:ty) => {{
139        let mut value = $value;
140        loop {
141            let mut byte = value & VALUE_MASK as $ty;
142            value >>= VALUE_LENGTH;
143
144            if value != 0 {
145                byte |= !VALUE_MASK as $ty;
146            }
147
148            $self.write_all(&[byte as u8])?;
149
150            if value == 0 {
151                return Ok(());
152            }
153        }
154    }};
155}
156
157/// Extends [`Write`][writer] with methods for writing unsigned integers to the
158/// underlying writer encoded in [unsigned LEB128].
159///
160/// # Examples
161///
162/// Write unsigned integers to a [writer] encoded in LEB128:
163///
164/// ```
165/// use uleb128::WriteULeb128Ext;
166///
167/// let mut wtr = vec![];
168/// wtr.write_uleb128_u32(127).unwrap();
169/// wtr.write_uleb128_u32(128).unwrap();
170/// wtr.write_uleb128_u32(129).unwrap();
171///
172/// assert_eq!(wtr, vec![
173///     0b0111_1111, // 127
174///     0b1000_0000, 0b0000_0001, // 128
175///     0b1000_0001, 0b0000_0001, // 129
176/// ]);
177/// ```
178///
179/// [unsigned LEB128]: https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128
180/// [writer]: https://doc.rust-lang.org/std/io/trait.Write.html
181pub trait WriteULeb128Ext: Write {
182    /// Write an unsigned 32-bit integer to the underlying [writer] encoded in
183    /// [unsigned LEB128].
184    ///
185    /// # Errors
186    ///
187    /// If this function encounters an error when performing an I/O operation,
188    /// then this function immediately returns an [`Error::Io`] to propagate the
189    /// [`io::Error`] returned by an internal call to [`Write::write_all`].
190    ///
191    /// # Examples
192    ///
193    /// Write an unsigned 32-bit integer to a [writer] encoded in LEB128:
194    ///
195    /// ```
196    /// use uleb128::WriteULeb128Ext;
197    ///
198    /// let mut wtr = vec![];
199    /// wtr.write_uleb128_u32(2_147_483_647).unwrap();
200    ///
201    /// assert_eq!(wtr, vec![
202    ///     // 2_147_483_647
203    ///     0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111, 0b0000_0111
204    /// ]);
205    /// ```
206    ///
207    /// [unsigned LEB128]: https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128
208    /// [writer]: https://doc.rust-lang.org/std/io/trait.Write.html
209    /// [`io::Error`]: std::io::Error
210    fn write_uleb128_u32(&mut self, value: u32) -> Result {
211        write_method_body!(self, value, u32)
212    }
213
214    /// Write an unsigned 64-bit integer to the underlying [writer] encoded in
215    /// [unsigned LEB128].
216    ///
217    /// # Errors
218    ///
219    /// If this function encounters an error when performing an I/O operation,
220    /// then this function immediately returns an [`Error::Io`] to propagate the
221    /// [`io::Error`] returned by an internal call to [`Write::write_all`].
222    ///
223    /// # Examples
224    ///
225    /// Write an unsigned 64-bit integer to a [writer] encoded in LEB128:
226    ///
227    /// ```
228    /// use uleb128::WriteULeb128Ext;
229    ///
230    /// let mut wtr = vec![];
231    /// wtr.write_uleb128_u64(9_223_372_036_854_775_807).unwrap();
232    ///
233    /// assert_eq!(wtr, vec![
234    ///     // 9_223_372_036_854_775_807
235    ///     0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111,
236    ///     0b1111_1111, 0b1111_1111, 0b1111_1111, 0b0111_1111
237    /// ]);
238    /// ```
239    ///
240    /// [unsigned LEB128]: https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128
241    /// [writer]: https://doc.rust-lang.org/std/io/trait.Write.html
242    /// [`io::Error`]: std::io::Error
243    fn write_uleb128_u64(&mut self, value: u64) -> Result {
244        write_method_body!(self, value, u64)
245    }
246}
247
248impl<W: Write + ?Sized> WriteULeb128Ext for W {}