1mod macros;
2
3use std::{
4 io::{Read, Seek, Write},
5 string::FromUtf8Error,
6};
7
8use thiserror::Error;
9
10#[derive(Debug, Error)]
11pub enum Error {
12 #[error("IO Error: {0}")]
13 IO(#[from] std::io::Error),
14 #[error("Utf8: {0}")]
15 FromUtf8(#[from] FromUtf8Error),
16}
17
18pub trait BytesReadExt: Read + Seek {
19 define_integral_r!(i8, 1);
20 define_integral_r!(u8, 1);
21
22 define_integral_r!(i16, 2);
23 define_integral_r!(u16, 2);
24
25 define_integral_r!(i32, 4);
26 define_integral_r!(u32, 4);
27
28 define_integral_r!(i64, 8);
29 define_integral_r!(u64, 8);
30
31 define_integral_r!(i128, 16);
32 define_integral_r!(u128, 16);
33
34 fn read_to_vec(&mut self) -> Result<Vec<u8>, Error> {
35 let mut buf = Vec::new();
36 self.read_to_end(&mut buf)?;
37 Ok(buf)
38 }
39
40 fn read_n_bytes<const N: usize>(&mut self) -> Result<[u8; N], Error> {
41 let mut bytes = [0u8; N];
42 self.read_exact(&mut bytes)?;
43 Ok(bytes)
44 }
45
46 fn read_n_bytes_vec(&mut self, amount: usize) -> Result<Vec<u8>, Error> {
47 let mut bytes = vec![0; amount];
48 self.read_exact(&mut bytes)?;
49 Ok(bytes)
50 }
51
52 fn read_f32(&mut self) -> Result<f32, Error> {
53 let v = self.read_u32()?;
54 Ok(f32::from_bits(v))
55 }
56
57 fn read_f64(&mut self) -> Result<f64, Error> {
58 let v = self.read_u64()?;
59 Ok(f64::from_bits(v))
60 }
61
62 fn read_string(&mut self) -> Result<String, Error> {
63 let len = self.read_u64()?;
64 Ok(String::from_utf8(self.read_n_bytes_vec(len as usize)?)?)
65 }
66}
67
68pub trait BytesWriteExt: Write {
69 define_write!(i8);
70 define_write!(u8);
71
72 define_write!(i16);
73 define_write!(u16);
74
75 define_write!(i32);
76 define_write!(u32);
77
78 define_write!(i64);
79 define_write!(u64);
80
81 define_write!(i128);
82 define_write!(u128);
83
84 define_write!(f32);
85 define_write!(f64);
86
87 fn write_string<S: AsRef<str>>(&mut self, value: S) -> Result<(), Error> {
88 let value = value.as_ref();
89 self.write_u64(value.len() as u64)?;
90 self.write_all(value.as_bytes())?;
91 Ok(())
92 }
93}
94
95impl<R: Read + Seek> BytesReadExt for R {}
96impl<R: Write> BytesWriteExt for R {}
97
98#[cfg(test)]
99mod tests {
100 use std::io::Cursor;
101
102 use super::*;
103
104 #[test]
105 fn string() {
106 const CONTENTS: &str = "Hello World. Trans Rights 🏳️⚧️ 🏳️⚧️ 🏳️⚧️ 🦀 🦀 🦀";
107 let mut buffer: Cursor<Vec<u8>> = Cursor::new(Vec::new());
108 buffer.write_string(CONTENTS.to_string()).expect("Error when writing");
109 buffer.set_position(0);
110 assert_eq!(CONTENTS, buffer.read_string().expect("Error when reading"));
111 }
112
113 macro_rules! define_test {
114 ($ty:ty) => {
115 paste::item! {
116 #[test]
117 fn [<$ty>]() {
118 const VALUES: [$ty; 2] = [$ty::MAX, $ty::MIN];
119
120 for v in VALUES {
121 let mut buffer: Cursor<Vec<u8>> =
122 Cursor::new(Vec::new());
123 buffer.[<write_$ty>](v).expect("Error when writing");
124 buffer.set_position(0);
125 assert_eq!(
126 v,
127 buffer.[<read_$ty>]().expect("Error when reading")
128 );
129 }
130 }
131 }
132 };
133 }
134
135 define_test!(i8);
136 define_test!(u8);
137 define_test!(i16);
138 define_test!(u16);
139 define_test!(i32);
140 define_test!(u32);
141 define_test!(i64);
142 define_test!(u64);
143 define_test!(i128);
144 define_test!(u128);
145 define_test!(f32);
146 define_test!(f64);
147}