extern crate byteorder;
use std::io::Write;
use crate::io::cube::{CubePos, CubePrecisePos, FloatPos, IntPos};
use crate::io::flex::FlexPos;
use crate::util::{io_error, VioResult};
use self::byteorder::{BigEndian, WriteBytesExt};
pub struct CubeWriter<W> {
current_byte: u8,
current_bit: u8,
pub target: W,
}
#[allow(dead_code)]
impl<W> CubeWriter<W> where W: Write {
pub fn new(target: W) -> CubeWriter<W> {
CubeWriter {
current_bit: 0,
current_byte: 0,
target,
}
}
pub fn write_nop(&mut self) -> VioResult {
if self.current_bit > 0 {
let ret = self.target.write_all(&[self.current_byte]);
self.current_bit = 0;
self.current_byte = 0;
return ret;
}
Result::Ok(())
}
pub fn ensure_complete_byte(&self) {
if self.current_bit != 0 {
panic!("Pointer is not at a complete byte")
}
}
pub fn write_bit(&mut self, value: bool) -> VioResult {
self.current_byte |= (value as u8) << (7 - self.current_bit);
self.current_bit += 1;
if self.current_bit >= 8 {
let ret = self.target.write_all(&[self.current_byte]);
self.current_bit = 0;
self.current_byte = 0;
return ret;
}
Result::Ok(())
}
pub fn write_nibble(&mut self, value: u8) -> VioResult {
if self.current_bit % 4 != 0 { panic!("Pointer is not at a complete nibble") }
for i in 0..=3 {
self.write_bit(((value >> (3 - i)) & 1) != 0)?;
}
Result::Ok(())
}
pub fn write_bytes(&mut self, bytes: &[u8]) -> VioResult {
self.ensure_complete_byte();
self.target.write_all(bytes)
}
pub fn write_int8(&mut self, value: i8) -> VioResult {
self.ensure_complete_byte();
self.target.write_all(&[value as u8])
}
pub fn write_int16(&mut self, value: i16) -> VioResult {
self.ensure_complete_byte();
self.target.write_i16::<BigEndian>(value)
}
pub fn write_int32(&mut self, value: i32) -> VioResult {
self.ensure_complete_byte();
return self.target.write_i32::<BigEndian>(value);
}
pub fn write_int64(&mut self, value: i64) -> VioResult {
self.ensure_complete_byte();
self.target.write_i64::<BigEndian>(value)
}
pub fn write_int128(&mut self, value: i128) -> VioResult {
self.ensure_complete_byte();
self.target.write_i128::<BigEndian>(value)
}
pub fn write_uint8(&mut self, value: u8) -> VioResult {
self.ensure_complete_byte();
self.target.write_all(&[value])
}
pub fn write_uint16(&mut self, value: u16) -> VioResult {
self.ensure_complete_byte();
self.target.write_u16::<BigEndian>(value)
}
pub fn write_uint32(&mut self, value: u32) -> VioResult {
self.ensure_complete_byte();
self.target.write_u32::<BigEndian>(value)
}
pub fn write_uint64(&mut self, value: u64) -> VioResult {
self.ensure_complete_byte();
self.target.write_u64::<BigEndian>(value)
}
pub fn write_uint128(&mut self, value: u128) -> VioResult {
self.ensure_complete_byte();
self.target.write_u128::<BigEndian>(value)
}
pub fn write_float32(&mut self, value: f32) -> VioResult {
self.ensure_complete_byte();
return self.target.write_f32::<BigEndian>(value);
}
pub fn write_float64(&mut self, value: f64) -> VioResult {
self.ensure_complete_byte();
return self.target.write_f64::<BigEndian>(value);
}
pub fn write_string(&mut self, value: &str) -> VioResult {
if value.len() > 0xFFFF { io_error("String is too long")?; }
self.write_uint16(value.len() as u16)?;
self.target.write_all(value.as_bytes())
}
pub fn write_string32(&mut self, value: &str) -> VioResult {
if value.len() > 0xFFFFFFFF { io_error("String is too long")?; }
self.write_uint16(value.len() as u16)?;
self.target.write_all(value.as_bytes())
}
pub fn write_int_pos(&mut self, value: &IntPos) -> VioResult {
self.write_int32(value.x)?;
self.write_int32(value.y)?;
self.write_int32(value.z)?;
Result::Ok(())
}
pub fn write_float_pos(&mut self, value: &FloatPos) -> VioResult {
self.write_float32(value.x)?;
self.write_float32(value.y)?;
self.write_float32(value.z)?;
Result::Ok(())
}
pub fn write_cube_pos(&mut self, value: &CubePos) -> VioResult {
self.write_int_pos(&value.batch)?;
self.write_nibble(value.local_x)?;
self.write_nibble(value.local_y)?;
self.write_nibble(value.local_z)?;
self.write_nop()?;
Result::Ok(())
}
pub fn write_cube_precise_pos(&mut self, value: &CubePrecisePos) -> VioResult {
self.write_int_pos(&value.cube.batch)?;
self.write_nibble(value.cube.local_x)?;
self.write_nibble(value.cube.local_y)?;
self.write_nibble(value.cube.local_z)?;
self.write_nibble(value.face)?;
self.write_float32(value.precise_x)?;
self.write_float32(value.precise_y)?;
Result::Ok(())
}
pub fn write_flex_pos(&mut self, value: &FlexPos) -> VioResult {
self.write_int_pos(&value.batch)?;
self.write_float_pos(&value.local)?;
self.write_float32(value.yaw)?;
self.write_float32(value.pitch)?;
Result::Ok(())
}
}