#![deny(missing_docs)]
use std::{
borrow::Borrow,
io::{Read, Write},
};
mod error;
mod stream;
pub use error::BinaryError;
pub use stream::file::FileStream;
pub use stream::memory::MemoryStream;
pub use stream::slice::SliceStream;
pub type BinaryResult<T> = std::result::Result<T, BinaryError>;
macro_rules! encode {
($endian:expr, $value:expr, $stream:expr) => {
let data = match $endian {
Endian::Little => $value.to_le_bytes(),
Endian::Big => $value.to_be_bytes(),
};
return Ok($stream.write(&data)?);
};
}
macro_rules! decode {
($endian:expr, $value:expr, $kind:ty) => {
let data = match $endian {
Endian::Little => <$kind>::from_le_bytes($value),
Endian::Big => <$kind>::from_be_bytes($value),
};
return Ok(data);
};
}
pub enum Endian {
Big,
Little,
}
impl Default for Endian {
fn default() -> Self {
Self::Big
}
}
#[allow(clippy::len_without_is_empty)]
pub trait SeekStream {
fn seek(&mut self, to: u64) -> BinaryResult<u64>;
fn tell(&mut self) -> BinaryResult<u64>;
fn len(&self) -> BinaryResult<u64>;
}
pub trait ReadStream: Read + SeekStream {}
pub trait WriteStream: Write + SeekStream {}
pub struct BinaryReader<'a> {
stream: &'a mut dyn ReadStream,
endian: Endian,
}
impl<'a> SeekStream for BinaryReader<'a> {
fn seek(&mut self, to: u64) -> BinaryResult<u64> {
self.stream.seek(to)
}
fn tell(&mut self) -> BinaryResult<u64> {
self.stream.tell()
}
fn len(&self) -> BinaryResult<u64> {
self.stream.len()
}
}
impl<'a> BinaryReader<'a> {
pub fn new(stream: &'a mut dyn ReadStream, endian: Endian) -> Self {
Self { stream, endian }
}
pub fn read_string(&mut self) -> BinaryResult<String> {
let chars = if cfg!(feature = "32bit") {
let str_len = self.read_u32()?;
let mut chars: Vec<u8> = vec![0; str_len as usize];
self.stream.read_exact(&mut chars)?;
chars
} else {
let str_len = self.read_u64()?;
let mut chars: Vec<u8> = vec![0; str_len as usize];
self.stream.read_exact(&mut chars)?;
chars
};
Ok(String::from_utf8(chars)?)
}
pub fn read_char(&mut self) -> BinaryResult<char> {
std::char::from_u32(self.read_u32()?).ok_or(BinaryError::InvalidChar)
}
pub fn read_bool(&mut self) -> BinaryResult<bool> {
let value = self.read_u8()?;
Ok(value > 0)
}
pub fn read_f32(&mut self) -> BinaryResult<f32> {
let mut buffer: [u8; 4] = [0; 4];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, f32);
}
pub fn read_f64(&mut self) -> BinaryResult<f64> {
let mut buffer: [u8; 8] = [0; 8];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, f64);
}
#[cfg(target_pointer_width = "32")]
pub fn read_isize(&mut self) -> BinaryResult<isize> {
let mut buffer: [u8; 4] = [0; 4];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, isize);
}
#[cfg(target_pointer_width = "64")]
pub fn read_isize(&mut self) -> BinaryResult<isize> {
let mut buffer: [u8; 8] = [0; 8];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, isize);
}
#[cfg(target_pointer_width = "32")]
pub fn read_usize(&mut self) -> BinaryResult<usize> {
let mut buffer: [u8; 4] = [0; 4];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, usize);
}
#[cfg(target_pointer_width = "64")]
pub fn read_usize(&mut self) -> BinaryResult<usize> {
let mut buffer: [u8; 8] = [0; 8];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, usize);
}
pub fn read_u64(&mut self) -> BinaryResult<u64> {
let mut buffer: [u8; 8] = [0; 8];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, u64);
}
pub fn read_i64(&mut self) -> BinaryResult<i64> {
let mut buffer: [u8; 8] = [0; 8];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, i64);
}
pub fn read_u32(&mut self) -> BinaryResult<u32> {
let mut buffer: [u8; 4] = [0; 4];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, u32);
}
pub fn read_i32(&mut self) -> BinaryResult<i32> {
let mut buffer: [u8; 4] = [0; 4];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, i32);
}
pub fn read_u16(&mut self) -> BinaryResult<u16> {
let mut buffer: [u8; 2] = [0; 2];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, u16);
}
pub fn read_i16(&mut self) -> BinaryResult<i16> {
let mut buffer: [u8; 2] = [0; 2];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, i16);
}
pub fn read_u8(&mut self) -> BinaryResult<u8> {
let mut buffer: [u8; 1] = [0; 1];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, u8);
}
pub fn read_i8(&mut self) -> BinaryResult<i8> {
let mut buffer: [u8; 1] = [0; 1];
self.stream.read_exact(&mut buffer)?;
decode!(self.endian, buffer, i8);
}
pub fn read_bytes(&mut self, length: usize) -> BinaryResult<Vec<u8>> {
let mut buffer: Vec<u8> = vec![0; length];
self.stream.read_exact(&mut buffer)?;
Ok(buffer)
}
}
pub struct BinaryWriter<'a> {
stream: &'a mut dyn WriteStream,
endian: Endian,
}
impl<'a> SeekStream for BinaryWriter<'a> {
fn seek(&mut self, to: u64) -> BinaryResult<u64> {
self.stream.seek(to)
}
fn tell(&mut self) -> BinaryResult<u64> {
self.stream.tell()
}
fn len(&self) -> BinaryResult<u64> {
self.stream.len()
}
}
impl<'a> BinaryWriter<'a> {
pub fn new(stream: &'a mut dyn WriteStream, endian: Endian) -> Self {
Self { stream, endian }
}
pub fn write_string<S: AsRef<str>>(
&mut self,
value: S,
) -> BinaryResult<usize> {
let bytes = value.as_ref().as_bytes();
if cfg!(feature = "32bit") {
self.write_u32(bytes.len() as u32)?;
} else {
self.write_u64(bytes.len() as u64)?;
}
Ok(self.stream.write(bytes)?)
}
pub fn write_char<V: Borrow<char>>(
&mut self,
v: V,
) -> BinaryResult<usize> {
self.write_u32(*v.borrow() as u32)
}
pub fn write_bool<V: Borrow<bool>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
let written = self.write_u8(if *value.borrow() { 1 } else { 0 })?;
Ok(written)
}
pub fn write_f32<V: Borrow<f32>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_f64<V: Borrow<f64>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_isize<V: Borrow<isize>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_usize<V: Borrow<usize>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_u64<V: Borrow<u64>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_i64<V: Borrow<i64>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_u32<V: Borrow<u32>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_i32<V: Borrow<i32>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_u16<V: Borrow<u16>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_i16<V: Borrow<i16>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_u8<V: Borrow<u8>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_i8<V: Borrow<i8>>(
&mut self,
value: V,
) -> BinaryResult<usize> {
encode!(self.endian, value.borrow(), self.stream);
}
pub fn write_bytes<B: AsRef<[u8]>>(
&mut self,
data: B,
) -> BinaryResult<usize> {
Ok(self.stream.write(data.as_ref())?)
}
}
pub trait Encode {
fn encode(&self, writer: &mut BinaryWriter) -> BinaryResult<()>;
}
pub trait Decode {
fn decode(&mut self, reader: &mut BinaryReader) -> BinaryResult<()>;
}