1use std::io::{BufRead, BufWriter, Write};
2
3#[allow(clippy::missing_errors_doc)]
4pub trait BinaryWriter:Write {
5 fn write_string(&mut self, s: &str) -> std::io::Result<()>;
6 fn write_u16(&mut self, u: u16) -> std::io::Result<()>;
7}
8
9#[allow(clippy::missing_errors_doc)]
10pub trait BinaryReader: BufRead {
11 fn read_string<R>(&mut self, f: impl FnOnce(&str) -> R) -> Result<R, DecodeError>;
12 fn read_u16(&mut self) -> Result<u16, DecodeError>;
13 fn pop(&mut self) -> Result<u8, DecodeError>;
14}
15
16impl<W: Write> BinaryWriter for BufWriter<W> {
17 #[inline]
18 fn write_string(&mut self, s: &str) -> std::io::Result<()> {
19 self.write_all(s.as_bytes())?;
20 self.write_all(&[0])
21 }
22
23 #[inline]
24 fn write_u16(&mut self, u: u16) -> std::io::Result<()> {
25 self.write_all(&u.to_le_bytes())
26 }
27}
28
29impl<B: BufRead> BinaryReader for B {
30 fn read_string<R>(&mut self, f: impl FnOnce(&str) -> R) -> Result<R, DecodeError> {
31 let mut buf = Vec::new();
32 self.read_until(0, &mut buf)?;
33 buf.pop();
34 let s = std::str::from_utf8(buf.as_slice())?;
35 Ok(f(s))
36 }
37 fn read_u16(&mut self) -> Result<u16, DecodeError> {
38 let mut buf = [0u8, 0u8];
39 self.read_exact(&mut buf)?;
40 Ok(u16::from_le_bytes(buf))
41 }
42 fn pop(&mut self) -> Result<u8, DecodeError> {
43 let mut buf = [0];
44 self.read_exact(&mut buf)?;
45 Ok(buf[0])
46 }
47}
48
49#[cfg(feature = "tokio")]
50pub trait AsyncBinaryReader: tokio::io::AsyncBufReadExt + Unpin + Send {
51 fn read_string<R>(
52 &mut self,
53 f: impl (FnOnce(&str) -> R) + Send,
54 ) -> impl std::future::Future<Output = Result<R, DecodeError>> + Send;
55}
56
57#[cfg(feature = "tokio")]
58impl<B: tokio::io::AsyncBufReadExt + Unpin + Send> AsyncBinaryReader for B {
59 async fn read_string<R>(
60 &mut self,
61 f: impl (FnOnce(&str) -> R) + Send,
62 ) -> Result<R, DecodeError> {
63 let mut buf = Vec::new();
64 self.read_until(0, &mut buf).await?;
65 buf.pop();
66 let s = std::str::from_utf8(buf.as_slice())?;
67 Ok(f(s))
68 }
69}
70
71pub enum DecodeError {
72 Io(std::io::Error),
73 Utf8(std::str::Utf8Error),
74}
75impl From<std::io::Error> for DecodeError {
76 #[inline]
77 fn from(value: std::io::Error) -> Self {
78 Self::Io(value)
79 }
80}
81impl From<std::str::Utf8Error> for DecodeError {
82 #[inline]
83 fn from(value: std::str::Utf8Error) -> Self {
84 Self::Utf8(value)
85 }
86}