use std::io::Write;
use crate::Segment;
pub struct VarWriter {
data: Vec<Segment>,
}
impl VarWriter {
pub fn new() -> VarWriter {
VarWriter {
data: Vec::new(),
}
}
pub fn add(&mut self, segment: Segment) {
self.data.push(segment);
}
pub fn add_string<S: Into<String>>(&mut self, string: S) {
self.add(Segment::from(string.into()))
}
pub fn add_raw(&mut self, raw: &[u8]) {
self.data.push(Segment::from(raw));
}
pub fn send<W: Write>(&mut self, stream: &mut W) -> std::io::Result<()> {
self.send_without_clearing(stream)?;
self.clear();
Ok(())
}
pub fn send_without_clearing<W: Write>(&mut self, stream: &mut W) -> std::io::Result<()> {
let total_size: usize = self.data.iter().map(|segment| segment.len() + 4).sum();
self.write_varint(stream, total_size)?;
for segment in &self.data {
self.write_u32(stream, segment.len() as u32)?;
stream.write_all(segment.as_ref())?;
}
Ok(())
}
fn write_varint<W: Write>(&self, writer: &mut W, mut value: usize) -> std::io::Result<()> {
loop {
let mut byte = (value & 0x7F) as u8;
value >>= 7;
if value != 0 {
byte |= 0x80;
}
writer.write_all(&[byte])?;
if value == 0 {
break;
}
}
Ok(())
}
#[cfg(not(feature = "big-endian"))]
fn write_u32<W: Write>(&self, writer: &mut W, value: u32) -> std::io::Result<()> {
writer.write_all(&[
(value & 0xFF) as u8,
((value >> 8) & 0xFF) as u8,
((value >> 16) & 0xFF) as u8,
((value >> 24) & 0xFF) as u8,
])?;
Ok(())
}
#[cfg(feature = "big-endian")]
fn write_u32<W: Write>(&self, writer: &mut W, value: u32) -> std::io::Result<()> {
writer.write_all(&[
((value >> 24) & 0xFF) as u8,
((value >> 16) & 0xFF) as u8,
((value >> 8) & 0xFF) as u8,
(value & 0xFF) as u8,
])?;
Ok(())
}
pub fn clear(&mut self) {
self.data.clear();
}
}
impl Write for VarWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let vec = buf.to_vec();
let size = vec.len();
self.data.push(Segment::from(vec));
Ok(size)
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl Default for VarWriter {
fn default() -> Self {
Self::new()
}
}