use crate::constants::{ExpressionEnum, NumericArrayEnum, PackedArrayEnum};
use crate::writer::Writer;
use crate::Error;
pub struct WxfWriter<W> {
inner: W,
}
impl<W: Writer> WxfWriter<W> {
pub fn new(inner: W) -> Self {
WxfWriter { inner }
}
pub fn into_inner(self) -> W {
self.inner
}
pub fn write_varint(&mut self, n: u64) -> Result<(), Error> {
let mut value = n;
loop {
let mut byte = (value & 0x7F) as u8;
value >>= 7;
if value != 0 {
byte |= 0x80;
self.inner.write_byte(byte)?;
} else {
self.inner.write_byte(byte)?;
return Ok(());
}
}
}
pub fn write_expr_token(&mut self, t: ExpressionEnum) -> Result<(), Error> {
self.inner.write_byte(t as u8)
}
pub fn write_integer(&mut self, n: i64) -> Result<(), Error> {
if let Ok(v) = i8::try_from(n) {
self.write_expr_token(ExpressionEnum::Integer8)?;
self.inner.write_bytes(&v.to_le_bytes())
} else if let Ok(v) = i16::try_from(n) {
self.write_expr_token(ExpressionEnum::Integer16)?;
self.inner.write_bytes(&v.to_le_bytes())
} else if let Ok(v) = i32::try_from(n) {
self.write_expr_token(ExpressionEnum::Integer32)?;
self.inner.write_bytes(&v.to_le_bytes())
} else {
self.write_expr_token(ExpressionEnum::Integer64)?;
self.inner.write_bytes(&n.to_le_bytes())
}
}
pub fn write_real(&mut self, f: f64) -> Result<(), Error> {
self.write_expr_token(ExpressionEnum::Real64)?;
self.inner.write_bytes(&f.to_le_bytes())
}
pub fn write_string(&mut self, s: &str) -> Result<(), Error> {
self.write_length_prefixed(ExpressionEnum::String, s.as_bytes())
}
pub fn write_symbol(&mut self, name: &str) -> Result<(), Error> {
self.write_length_prefixed(ExpressionEnum::Symbol, name.as_bytes())
}
pub fn write_byte_array(&mut self, bytes: &[u8]) -> Result<(), Error> {
self.write_length_prefixed(ExpressionEnum::ByteArray, bytes)
}
pub fn write_big_integer(&mut self, digits: &str) -> Result<(), Error> {
self.write_length_prefixed(ExpressionEnum::BigInteger, digits.as_bytes())
}
pub fn write_big_real(&mut self, digits: &str) -> Result<(), Error> {
self.write_length_prefixed(ExpressionEnum::BigReal, digits.as_bytes())
}
pub fn write_numeric_array(
&mut self,
dt: NumericArrayEnum,
dims: &[usize],
bytes: &[u8],
) -> Result<(), Error> {
self.write_expr_token(ExpressionEnum::NumericArray)?;
self.inner.write_byte(dt as u8)?;
self.write_dims(dims)?;
self.inner.write_bytes(bytes)
}
pub fn write_packed_array(
&mut self,
dt: PackedArrayEnum,
dims: &[usize],
bytes: &[u8],
) -> Result<(), Error> {
self.write_expr_token(ExpressionEnum::PackedArray)?;
self.inner.write_byte(NumericArrayEnum::from(dt) as u8)?;
self.write_dims(dims)?;
self.inner.write_bytes(bytes)
}
pub fn write_function(&mut self, arity: usize) -> Result<(), Error> {
self.write_expr_token(ExpressionEnum::Function)?;
self.write_varint(arity as u64)
}
pub fn write_association(&mut self, count: usize) -> Result<(), Error> {
self.write_expr_token(ExpressionEnum::Association)?;
self.write_varint(count as u64)
}
pub fn write_rule(&mut self, delayed: bool) -> Result<(), Error> {
self.write_expr_token(if delayed {
ExpressionEnum::RuleDelayed
} else {
ExpressionEnum::Rule
})
}
fn write_length_prefixed(
&mut self,
token: ExpressionEnum,
bytes: &[u8],
) -> Result<(), Error> {
self.write_expr_token(token)?;
self.write_varint(bytes.len() as u64)?;
self.inner.write_bytes(bytes)
}
fn write_dims(&mut self, dims: &[usize]) -> Result<(), Error> {
self.write_varint(dims.len() as u64)?;
for d in dims {
self.write_varint(*d as u64)?;
}
Ok(())
}
}