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 {}