use crate::error::{Error, Result};
use std::io::{Read, Write};
pub(crate) trait WriteLe: Write {
fn put_u8(&mut self, v: u8) -> Result<()> {
Ok(self.write_all(&[v])?)
}
fn put_u32(&mut self, v: u32) -> Result<()> {
Ok(self.write_all(&v.to_le_bytes())?)
}
fn put_i32(&mut self, v: i32) -> Result<()> {
Ok(self.write_all(&v.to_le_bytes())?)
}
fn put_u64(&mut self, v: u64) -> Result<()> {
Ok(self.write_all(&v.to_le_bytes())?)
}
fn put_f32(&mut self, v: f32) -> Result<()> {
Ok(self.write_all(&v.to_le_bytes())?)
}
fn put_f64(&mut self, v: f64) -> Result<()> {
Ok(self.write_all(&v.to_le_bytes())?)
}
fn put_f64s(&mut self, v: &[f64]) -> Result<()> {
for x in v {
self.put_f64(*x)?;
}
Ok(())
}
}
impl<W: Write + ?Sized> WriteLe for W {}
pub(crate) trait ReadLe: Read {
fn get_bytes<const N: usize>(&mut self) -> Result<[u8; N]> {
let mut b = [0u8; N];
self.read_exact(&mut b).map_err(|e| {
if e.kind() == std::io::ErrorKind::UnexpectedEof {
Error::Format("파일이 예상보다 일찍 끝남".into())
} else {
Error::Io(e)
}
})?;
Ok(b)
}
fn get_u8(&mut self) -> Result<u8> {
Ok(self.get_bytes::<1>()?[0])
}
fn get_u32(&mut self) -> Result<u32> {
Ok(u32::from_le_bytes(self.get_bytes()?))
}
fn get_i32(&mut self) -> Result<i32> {
Ok(i32::from_le_bytes(self.get_bytes()?))
}
fn get_u64(&mut self) -> Result<u64> {
Ok(u64::from_le_bytes(self.get_bytes()?))
}
fn get_f32(&mut self) -> Result<f32> {
Ok(f32::from_le_bytes(self.get_bytes()?))
}
fn get_f64(&mut self) -> Result<f64> {
Ok(f64::from_le_bytes(self.get_bytes()?))
}
fn get_f64_array<const N: usize>(&mut self) -> Result<[f64; N]> {
let mut a = [0.0; N];
for x in a.iter_mut() {
*x = self.get_f64()?;
}
Ok(a)
}
fn get_cstring(&mut self) -> Result<String> {
let mut v = Vec::new();
loop {
let b = self.get_u8()?;
if b == 0 {
break;
}
v.push(b);
}
String::from_utf8(v).map_err(|_| Error::Format("UTF-8 이 아닌 이름".into()))
}
fn get_vec_u8(&mut self, n: usize) -> Result<Vec<u8>> {
let mut v = vec![0u8; n];
self.read_exact(&mut v)?;
Ok(v)
}
}
impl<R: Read + ?Sized> ReadLe for R {}
pub(crate) fn check_count(n: u64, what: &str) -> Result<usize> {
if n > (1u64 << 40) {
return Err(Error::Format(format!("{what} 개수가 비정상적으로 큼: {n}")));
}
Ok(n as usize)
}