Skip to main content

bin_it/
lib.rs

1/// # Bin-It
2///
3/// **Bin-It** is a simple, efficient Rust library for binary serialization and deserialization. With a focus on
4/// performance and ease of use, Bin-It lets you seamlessly serialize Rust types into compact binary formats and
5/// read them back with precision. Whether you're storing data in binary files, transmitting data over networks,
6/// or handling low-level byte operations, **Bin-It** has you covered.
7///
8/// ## Features
9///
10/// - Serialize and deserialize common primitive types (`u8`, `i16`, `f32`, etc.).
11/// - Supports serialization of strings and collections (e.g., `Vec<u8>`, `Vec<f64>`, etc.).
12/// - Consistent, little-endian encoding for cross-platform compatibility.
13/// - Minimal dependencies for fast, lightweight binary manipulation.
14///
15/// ## Usage
16///
17/// ### Writing Data
18///
19/// The BinaryWriter struct allows you to serialize various data types into a binary buffer:
20///
21/// ```rust
22/// use bin_it::BinaryWriter;
23///
24/// fn main() {
25///     let mut writer = BinaryWriter::new();
26///     writer.write_u32(42);
27///     writer.write_string("Hello, Bin-It!");
28///     writer.write_f64(3.14159);
29///
30///     let data = writer.get_data();
31///     // Now `data` contains the binary representation of the serialized values.
32/// }
33/// ```
34///
35///
36/// ### Reading Data
37///
38/// The BinaryReader struct lets you deserialize the binary data back into Rust types:
39///
40/// ```rust
41/// use bin_it::BinaryReader;
42///
43/// fn main() {
44///     // Ensure `data` has enough bytes for the expected reads
45///     let data = vec![42, 0, 0, 0]; // Sufficient data for a u32
46///     let mut reader = BinaryReader::new(&data);
47///
48///     match reader.read_u32() {
49///         Ok(number) => println!("Number: {}", number),
50///         Err(e) => println!("Error reading u32: {}", e),
51///     }
52/// }
53/// ```
54///
55/// ## Supported Data Types
56///
57/// **Bin-It** supports writing and reading of:
58///  * Primitives: u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, and bool.
59///  * Strings: UTF-8 strings serialized with length-prefix encoding.
60///  * Collections: Fixed-size collections, such as Vec<T> for supported types.
61
62use std::convert::TryInto;
63
64
65/// BinaryWriter is used to serialize various data types into a byte buffer.
66pub struct BinaryWriter {
67  data: Vec<u8>,
68}
69
70impl BinaryWriter {
71  /// Creates a new BinaryWriter with an empty buffer.
72  pub fn new() -> Self {
73    BinaryWriter { data: Vec::new() }
74  }
75
76  /// Returns a reference to the internal byte buffer.
77  pub fn get_data(self) -> Vec<u8> {
78    self.data
79  }
80
81  /// Writes a u8 value to the buffer.
82  pub fn write_u8(&mut self, value: u8) {
83    self.data.push(value);
84  }
85
86  /// Writes a u16 value to the buffer in little-endian order.
87  pub fn write_u16(&mut self, value: u16) {
88    self.data.extend(&value.to_le_bytes());
89  }
90
91  /// Writes a u32 value to the buffer in little-endian order.
92  pub fn write_u32(&mut self, value: u32) {
93    self.data.extend(&value.to_le_bytes());
94  }
95
96  /// Writes a u64 value to the buffer in little-endian order.
97  pub fn write_u64(&mut self, value: u64) {
98    self.data.extend(&value.to_le_bytes());
99  }
100
101  /// Writes an i8 value to the buffer.
102  pub fn write_i8(&mut self, value: i8) {
103    self.data.push(value as u8);
104  }
105
106  /// Writes an i16 value to the buffer in little-endian order.
107  pub fn write_i16(&mut self, value: i16) {
108    self.data.extend(&value.to_le_bytes());
109  }
110
111  /// Writes an i32 value to the buffer in little-endian order.
112  pub fn write_i32(&mut self, value: i32) {
113    self.data.extend(&value.to_le_bytes());
114  }
115
116  /// Writes an i64 value to the buffer in little-endian order.
117  pub fn write_i64(&mut self, value: i64) {
118    self.data.extend(&value.to_le_bytes());
119  }
120
121  /// Writes a f32 value to the buffer in little-endian order.
122  pub fn write_f32(&mut self, value: f32) {
123    self.data.extend(&value.to_le_bytes());
124  }
125
126  /// Writes a f64 value to the buffer in little-endian order.
127  pub fn write_f64(&mut self, value: f64) {
128    self.data.extend(&value.to_le_bytes());
129  }
130
131  /// Writes a bool value to the buffer as a single byte (0 or 1).
132  pub fn write_bool(&mut self, value: bool) {
133    self.data.push(if value { 1 } else { 0 });
134  }
135
136  /// Writes a string to the buffer. First writes the length as u32, then the UTF-8 bytes.
137  pub fn write_string(&mut self, value: &str) {
138    let bytes = value.as_bytes();
139    self.write_u32(bytes.len() as u32);
140    self.data.extend(bytes);
141  }
142
143  /// Writes a vector of u8 to the buffer. First writes the length as u32, then the bytes.
144  pub fn write_vec_u8(&mut self, value: &[u8]) {
145    self.write_u32(value.len() as u32);
146    self.data.extend(value);
147  }
148
149  /// Writes a vector of u16 to the buffer. First writes the length as u32, then the bytes in little-endian.
150  pub fn write_vec_u16(&mut self, value: &[u16]) {
151    self.write_u32(value.len() as u32);
152    for &v in value {
153      self.write_u16(v);
154    }
155  }
156
157  /// Writes a vector of u32 to the buffer. First writes the length as u32, then the bytes in little-endian.
158  pub fn write_vec_u32(&mut self, value: &[u32]) {
159    self.write_u32(value.len() as u32);
160    for &v in value {
161      self.write_u32(v);
162    }
163  }
164
165  /// Writes a vector of u64 to the buffer. First writes the length as u32, then the bytes in little-endian.
166  pub fn write_vec_u64(&mut self, value: &[u64]) {
167    self.write_u32(value.len() as u32);
168    for &v in value {
169      self.write_u64(v);
170    }
171  }
172
173  /// Writes a vector of i8 to the buffer. First writes the length as u32, then the bytes.
174  pub fn write_vec_i8(&mut self, value: &[i8]) {
175    self.write_u32(value.len() as u32);
176    for &v in value {
177      self.write_i8(v);
178    }
179  }
180
181  /// Writes a vector of i16 to the buffer. First writes the length as u32, then the bytes in little-endian.
182  pub fn write_vec_i16(&mut self, value: &[i16]) {
183    self.write_u32(value.len() as u32);
184    for &v in value {
185      self.write_i16(v);
186    }
187  }
188
189  /// Writes a vector of i32 to the buffer. First writes the length as u32, then the bytes in little-endian.
190  pub fn write_vec_i32(&mut self, value: &[i32]) {
191    self.write_u32(value.len() as u32);
192    for &v in value {
193      self.write_i32(v);
194    }
195  }
196
197  /// Writes a vector of i64 to the buffer. First writes the length as u32, then the bytes in little-endian.
198  pub fn write_vec_i64(&mut self, value: &[i64]) {
199    self.write_u32(value.len() as u32);
200    for &v in value {
201      self.write_i64(v);
202    }
203  }
204
205  /// Writes a vector of f32 to the buffer. First writes the length as u32, then the bytes in little-endian.
206  pub fn write_vec_f32(&mut self, value: &[f32]) {
207    self.write_u32(value.len() as u32);
208    for &v in value {
209      self.write_f32(v);
210    }
211  }
212
213  /// Writes a vector of f64 to the buffer. First writes the length as u32, then the bytes in little-endian.
214  pub fn write_vec_f64(&mut self, value: &[f64]) {
215    self.write_u32(value.len() as u32);
216    for &v in value {
217      self.write_f64(v);
218    }
219  }
220
221  /// Writes a vector of strings to the buffer. First writes the length as u32, then each string serialized.
222  pub fn write_vec_string(&mut self, value: &[String]) {
223    self.write_u32(value.len() as u32);
224    for s in value {
225      self.write_string(s);
226    }
227  }
228}
229
230/// BinaryReader is used to deserialize various data types from a byte buffer.
231pub struct BinaryReader<'a> {
232  data: &'a [u8],
233  cursor: usize,
234}
235
236impl<'a> BinaryReader<'a> {
237  /// Creates a new BinaryReader with the given byte slice.
238  pub fn new(data: &'a [u8]) -> Self {
239    BinaryReader { data, cursor: 0 }
240  }
241
242  /// Reads a u8 value from the buffer.
243  pub fn read_u8(&mut self) -> Result<u8, String> {
244    self.ensure_available(1)?;
245    let value = self.data[self.cursor];
246    self.cursor += 1;
247    Ok(value)
248  }
249
250  /// Reads a u16 value from the buffer in little-endian order.
251  pub fn read_u16(&mut self) -> Result<u16, String> {
252    self.ensure_available(2)?;
253    let bytes = &self.data[self.cursor..self.cursor + 2];
254    self.cursor += 2;
255    Ok(u16::from_le_bytes(bytes.try_into().unwrap()))
256  }
257
258  /// Reads a u32 value from the buffer in little-endian order.
259  pub fn read_u32(&mut self) -> Result<u32, String> {
260    self.ensure_available(4)?;
261    let bytes = &self.data[self.cursor..self.cursor + 4];
262    self.cursor += 4;
263    Ok(u32::from_le_bytes(bytes.try_into().unwrap()))
264  }
265
266  /// Reads a u64 value from the buffer in little-endian order.
267  pub fn read_u64(&mut self) -> Result<u64, String> {
268    self.ensure_available(8)?;
269    let bytes = &self.data[self.cursor..self.cursor + 8];
270    self.cursor += 8;
271    Ok(u64::from_le_bytes(bytes.try_into().unwrap()))
272  }
273
274  /// Reads an i8 value from the buffer.
275  pub fn read_i8(&mut self) -> Result<i8, String> {
276    self.ensure_available(1)?;
277    let value = self.data[self.cursor] as i8;
278    self.cursor += 1;
279    Ok(value)
280  }
281
282  /// Reads an i16 value from the buffer in little-endian order.
283  pub fn read_i16(&mut self) -> Result<i16, String> {
284    self.read_u16().map(|v| v as i16)
285  }
286
287  /// Reads an i32 value from the buffer in little-endian order.
288  pub fn read_i32(&mut self) -> Result<i32, String> {
289    self.read_u32().map(|v| v as i32)
290  }
291
292  /// Reads an i64 value from the buffer in little-endian order.
293  pub fn read_i64(&mut self) -> Result<i64, String> {
294    self.read_u64().map(|v| v as i64)
295  }
296
297  /// Reads a f32 value from the buffer in little-endian order.
298  pub fn read_f32(&mut self) -> Result<f32, String> {
299    self.ensure_available(4)?;
300    let bytes = &self.data[self.cursor..self.cursor + 4];
301    self.cursor += 4;
302    Ok(f32::from_le_bytes(bytes.try_into().unwrap()))
303  }
304
305  /// Reads a f64 value from the buffer in little-endian order.
306  pub fn read_f64(&mut self) -> Result<f64, String> {
307    self.ensure_available(8)?;
308    let bytes = &self.data[self.cursor..self.cursor + 8];
309    self.cursor += 8;
310    Ok(f64::from_le_bytes(bytes.try_into().unwrap()))
311  }
312
313  /// Reads a bool value from the buffer (expects 0 or 1).
314  pub fn read_bool(&mut self) -> Result<bool, String> {
315    self.read_u8().map(|v| match v {
316      0 => false,
317      1 => true,
318      _ => panic!("Invalid boolean value: {}", v),
319    })
320  }
321
322  /// Reads a string from the buffer. Expects a u32 length followed by UTF-8 bytes.
323  pub fn read_string(&mut self) -> Result<String, String> {
324    let length = self.read_u32()? as usize;
325    self.ensure_available(length)?;
326    let bytes = &self.data[self.cursor..self.cursor + length];
327    self.cursor += length;
328    String::from_utf8(bytes.to_vec()).map_err(|e| e.to_string())
329  }
330
331  /// Reads a vector of u8 from the buffer. Expects a u32 length followed by bytes.
332  pub fn read_vec_u8(&mut self) -> Result<Vec<u8>, String> {
333    let length = self.read_u32()? as usize;
334    self.ensure_available(length)?;
335    let vec = self.data[self.cursor..self.cursor + length].to_vec();
336    self.cursor += length;
337    Ok(vec)
338  }
339
340  /// Reads a vector of u16 from the buffer. Expects a u32 length followed by u16 values.
341  pub fn read_vec_u16(&mut self) -> Result<Vec<u16>, String> {
342    let length = self.read_u32()? as usize;
343    let mut vec = Vec::with_capacity(length);
344    for _ in 0..length {
345      vec.push(self.read_u16()?);
346    }
347    Ok(vec)
348  }
349
350  /// Reads a vector of u32 from the buffer. Expects a u32 length followed by u32 values.
351  pub fn read_vec_u32(&mut self) -> Result<Vec<u32>, String> {
352    let length = self.read_u32()? as usize;
353    let mut vec = Vec::with_capacity(length);
354    for _ in 0..length {
355      vec.push(self.read_u32()?);
356    }
357    Ok(vec)
358  }
359
360  /// Reads a vector of u64 from the buffer. Expects a u32 length followed by u64 values.
361  pub fn read_vec_u64(&mut self) -> Result<Vec<u64>, String> {
362    let length = self.read_u32()? as usize;
363    let mut vec = Vec::with_capacity(length);
364    for _ in 0..length {
365      vec.push(self.read_u64()?);
366    }
367    Ok(vec)
368  }
369
370  /// Reads a vector of i8 from the buffer. Expects a u32 length followed by i8 values.
371  pub fn read_vec_i8(&mut self) -> Result<Vec<i8>, String> {
372    let length = self.read_u32()? as usize;
373    let mut vec = Vec::with_capacity(length);
374    for _ in 0..length {
375      vec.push(self.read_i8()?);
376    }
377    Ok(vec)
378  }
379
380  /// Reads a vector of i16 from the buffer. Expects a u32 length followed by i16 values.
381  pub fn read_vec_i16(&mut self) -> Result<Vec<i16>, String> {
382    let length = self.read_u32()? as usize;
383    let mut vec = Vec::with_capacity(length);
384    for _ in 0..length {
385      vec.push(self.read_i16()?);
386    }
387    Ok(vec)
388  }
389
390  /// Reads a vector of i32 from the buffer. Expects a u32 length followed by i32 values.
391  pub fn read_vec_i32(&mut self) -> Result<Vec<i32>, String> {
392    let length = self.read_u32()? as usize;
393    let mut vec = Vec::with_capacity(length);
394    for _ in 0..length {
395      vec.push(self.read_i32()?);
396    }
397    Ok(vec)
398  }
399
400  /// Reads a vector of i64 from the buffer. Expects a u32 length followed by i64 values.
401  pub fn read_vec_i64(&mut self) -> Result<Vec<i64>, String> {
402    let length = self.read_u32()? as usize;
403    let mut vec = Vec::with_capacity(length);
404    for _ in 0..length {
405      vec.push(self.read_i64()?);
406    }
407    Ok(vec)
408  }
409
410  /// Reads a vector of f32 from the buffer. Expects a u32 length followed by f32 values.
411  pub fn read_vec_f32(&mut self) -> Result<Vec<f32>, String> {
412    let length = self.read_u32()? as usize;
413    let mut vec = Vec::with_capacity(length);
414    for _ in 0..length {
415      vec.push(self.read_f32()?);
416    }
417    Ok(vec)
418  }
419
420  /// Reads a vector of f64 from the buffer. Expects a u32 length followed by f64 values.
421  pub fn read_vec_f64(&mut self) -> Result<Vec<f64>, String> {
422    let length = self.read_u32()? as usize;
423    let mut vec = Vec::with_capacity(length);
424    for _ in 0..length {
425      vec.push(self.read_f64()?);
426    }
427    Ok(vec)
428  }
429
430  /// Reads a vector of strings from the buffer. Expects a u32 length followed by serialized strings.
431  pub fn read_vec_string(&mut self) -> Result<Vec<String>, String> {
432    let length = self.read_u32()? as usize;
433    let mut vec = Vec::with_capacity(length);
434    for _ in 0..length {
435      vec.push(self.read_string()?);
436    }
437    Ok(vec)
438  }
439
440  /// Ensures that there are at least `size` bytes available to read.
441  fn ensure_available(&self, size: usize) -> Result<(), String> {
442    if self.cursor + size > self.data.len() {
443      Err("Unexpected end of data".to_string())
444    } else {
445      Ok(())
446    }
447  }
448}
449
450#[cfg(test)]
451mod tests {
452  use super::*;
453
454  #[test]
455  fn test_binary_writer_reader() {
456    let mut writer = BinaryWriter::new();
457
458    // Write various data types
459    writer.write_u8(255);
460    writer.write_i8(-128);
461    writer.write_u16(65535);
462    writer.write_i16(-32768);
463    writer.write_u32(4294967295);
464    writer.write_i32(-2147483648);
465    writer.write_u64(18446744073709551615);
466    writer.write_i64(-9223372036854775808);
467    writer.write_f32(3.1415927);
468    writer.write_f64(2.718281828459045);
469    writer.write_bool(true);
470    writer.write_string("Hello, World!");
471
472    let data = writer.get_data().clone();
473
474    let mut reader = BinaryReader::new(&data);
475
476    // Read and assert the values
477    assert_eq!(reader.read_u8().unwrap(), 255);
478    assert_eq!(reader.read_i8().unwrap(), -128);
479    assert_eq!(reader.read_u16().unwrap(), 65535);
480    assert_eq!(reader.read_i16().unwrap(), -32768);
481    assert_eq!(reader.read_u32().unwrap(), 4294967295);
482    assert_eq!(reader.read_i32().unwrap(), -2147483648);
483    assert_eq!(reader.read_u64().unwrap(), 18446744073709551615);
484    assert_eq!(reader.read_i64().unwrap(), -9223372036854775808);
485    assert!((reader.read_f32().unwrap() - 3.1415927).abs() < 1e-6);
486    assert!((reader.read_f64().unwrap() - 2.718281828459045).abs() < 1e-12);
487    assert_eq!(reader.read_bool().unwrap(), true);
488    assert_eq!(reader.read_string().unwrap(), "Hello, World!");
489  }
490
491  #[test]
492  fn test_binary_writer_reader_vectors() {
493    let mut writer = BinaryWriter::new();
494
495    // Write vectors
496    writer.write_vec_u8(&[1, 2, 3, 4, 5]);
497    writer.write_vec_i16(&[-1, -2, -3]);
498    writer.write_vec_f64(&[1.1, 2.2, 3.3]);
499
500    let data = writer.get_data().clone();
501
502    let mut reader = BinaryReader::new(&data);
503
504    // Read and assert the vectors
505    assert_eq!(reader.read_vec_u8().unwrap(), vec![1, 2, 3, 4, 5]);
506    assert_eq!(reader.read_vec_i16().unwrap(), vec![-1, -2, -3]);
507    let read_f64 = reader.read_vec_f64().unwrap();
508    assert_eq!(read_f64.len(), 3);
509    assert!((read_f64[0] - 1.1).abs() < 1e-10);
510    assert!((read_f64[1] - 2.2).abs() < 1e-10);
511    assert!((read_f64[2] - 3.3).abs() < 1e-10);
512  }
513
514  #[test]
515  fn test_binary_writer_reader_vec_string() {
516    let mut writer = BinaryWriter::new();
517
518    // Write a vector of strings
519    let strings = vec![
520      "Hello".to_string(),
521      "Bin-It".to_string(),
522      "Serialization".to_string(),
523      "".to_string(),
524      "🚀✨".to_string(),
525    ];
526    writer.write_vec_string(&strings);
527
528    let data = writer.get_data().clone();
529
530    let mut reader = BinaryReader::new(&data);
531
532    // Read and assert the vector of strings
533    let read_strings = reader.read_vec_string().unwrap();
534    assert_eq!(read_strings, strings);
535  }
536
537  #[test]
538  fn test_binary_reader_error() {
539    let data = vec![1, 2]; // Insufficient data for a u32
540
541    let mut reader = BinaryReader::new(&data);
542
543    // Attempt to read a u32, which should fail
544    assert!(reader.read_u32().is_err());
545  }
546}