use core::marker::PhantomData;
use std::io::{
Result,
Seek,
SeekFrom,
Write,
};
use crate::WriteExt;
use crate::codec::{
BigEndian,
BinaryCodec,
ByteOrder,
ByteOrderSpec,
LittleEndian,
};
use crate::util::{
checked_u16_len,
checked_u32_len,
};
pub struct BinaryWriter<W, O = BigEndian> {
inner: W,
buffer: [u8; 16],
marker: PhantomData<fn() -> O>,
}
impl<W, O> BinaryWriter<W, O>
where
W: Write,
O: ByteOrderSpec,
{
#[must_use]
#[inline]
pub const fn new(inner: W) -> Self {
Self {
inner,
buffer: [0; 16],
marker: PhantomData,
}
}
#[must_use]
#[inline]
pub const fn byte_order(&self) -> ByteOrder {
O::ORDER
}
#[must_use]
#[inline]
pub const fn get_ref(&self) -> &W {
&self.inner
}
#[must_use]
#[inline]
pub fn get_mut(&mut self) -> &mut W {
&mut self.inner
}
#[must_use]
#[inline]
pub fn into_inner(self) -> W {
self.inner
}
}
macro_rules! impl_value_write {
($order:ty, $method:ident, $ty:ty, $doc:literal) => {
#[doc = $doc]
#[inline]
pub fn $method(&mut self, value: $ty) -> Result<()> {
type Codec = BinaryCodec<$ty, $order>;
const LEN: usize = Codec::REQUIRED_MIN_BUFFER_LEN;
unsafe {
Codec::write_unchecked(&mut self.buffer, 0, value);
self.inner.write_all_unchecked(&self.buffer, 0, LEN)
}
}
};
}
macro_rules! impl_for_order {
($order:ty) => {
impl<W> BinaryWriter<W, $order>
where
W: Write,
{
impl_value_write!($order, write_u8, u8, "Writes an unsigned 8-bit integer.");
impl_value_write!($order, write_i8, i8, "Writes a signed 8-bit integer.");
impl_value_write!($order, write_u16, u16, "Writes an unsigned 16-bit integer.");
impl_value_write!($order, write_u32, u32, "Writes an unsigned 32-bit integer.");
impl_value_write!($order, write_u64, u64, "Writes an unsigned 64-bit integer.");
impl_value_write!($order, write_u128, u128, "Writes an unsigned 128-bit integer.");
impl_value_write!($order, write_i16, i16, "Writes a signed 16-bit integer.");
impl_value_write!($order, write_i32, i32, "Writes a signed 32-bit integer.");
impl_value_write!($order, write_i64, i64, "Writes a signed 64-bit integer.");
impl_value_write!($order, write_i128, i128, "Writes a signed 128-bit integer.");
impl_value_write!($order, write_f32, f32, "Writes a 32-bit float.");
impl_value_write!($order, write_f64, f64, "Writes a 64-bit float.");
#[inline]
pub fn write_utf8_string_u16(&mut self, value: &str) -> Result<()> {
self.write_u16(checked_u16_len(value.len())?)?;
let bytes = value.as_bytes();
unsafe { self.inner.write_all_unchecked(bytes, 0, bytes.len()) }
}
#[inline]
pub fn write_utf8_string_u32(&mut self, value: &str) -> Result<()> {
self.write_u32(checked_u32_len(value.len())?)?;
let bytes = value.as_bytes();
unsafe { self.inner.write_all_unchecked(bytes, 0, bytes.len()) }
}
}
};
}
impl_for_order!(BigEndian);
impl_for_order!(LittleEndian);
impl<W, O> Write for BinaryWriter<W, O>
where
W: Write,
{
#[inline]
fn write(&mut self, buffer: &[u8]) -> Result<usize> {
self.inner.write(buffer)
}
#[inline]
fn flush(&mut self) -> Result<()> {
self.inner.flush()
}
}
impl<W, O> Seek for BinaryWriter<W, O>
where
W: Seek,
{
#[inline]
fn seek(&mut self, position: SeekFrom) -> Result<u64> {
self.inner.seek(position)
}
}