1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
use std::io::Write;
use crate::Segment;
/// A writer for sending several segments over a stream using variable length encoding
/// Data is written in little-endian if the feature "big-endian" is not enabled
/// # Example
/// ```
/// use send_it::writer::VarWriter;
///
/// let mut sender = VarWriter::new();
///
/// sender.add_string("Hello");
/// sender.add_string("World");
///
/// let mut buffer = Vec::new();
/// sender.send(&mut buffer).unwrap();
/// ```
pub struct VarWriter {
data: Vec<Segment>,
}
impl VarWriter {
/// Create a new VarWriter
pub fn new() -> VarWriter {
VarWriter {
data: Vec::new(),
}
}
/// Add a segment to the writer
pub fn add(&mut self, segment: Segment) {
self.data.push(segment);
}
/// Add a string to the writer
/// # Example
/// ```
/// use send_it::writer::VarWriter;
///
/// let mut sender = VarWriter::new();
///
/// sender.add_string("Hello");
/// ```
pub fn add_string<S: Into<String>>(&mut self, string: S) {
self.add(Segment::from(string.into()))
}
/// Add raw data to the writer
/// # Example
/// ```
/// use send_it::writer::VarWriter;
///
/// let mut sender = VarWriter::new();
///
/// sender.add_raw(&[0x48, 0x65, 0x6C, 0x6C, 0x6F]);
/// ```
pub fn add_raw(&mut self, raw: &[u8]) {
self.data.push(Segment::from(raw));
}
/// Encodes the data and sends it over the stream.
/// * The data is cleared after sending.
/// # Example
/// ```
/// use send_it::writer::VarWriter;
///
/// let mut sender = VarWriter::new();
///
/// sender.add_string("Hello");
/// sender.add_string("World");
///
/// let mut buffer = Vec::new();
/// sender.send(&mut buffer).unwrap();
/// ```
pub fn send<W: Write>(&mut self, stream: &mut W) -> std::io::Result<()> {
self.send_without_clearing(stream)?;
// Clear the internal data after sending
self.clear();
Ok(())
}
/// Encodes the data and sends it over the stream.
/// * The data is not cleared after sending.
/// # Example
/// ```
/// use send_it::writer::VarWriter;
///
/// let mut sender = VarWriter::new();
///
/// sender.add_string("Hello");
/// sender.add_string("World");
///
/// let mut buffer = Vec::new();
/// sender.send_without_clearing(&mut buffer).unwrap();
/// ```
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();
// Write the total size as varint
self.write_varint(stream, total_size)?;
// Write each segment's size and the segment itself
for segment in &self.data {
self.write_u32(stream, segment.len() as u32)?;
// write the segment
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<()> {
// writes little-endian
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<()> {
// writes big-endian
writer.write_all(&[
((value >> 24) & 0xFF) as u8,
((value >> 16) & 0xFF) as u8,
((value >> 8) & 0xFF) as u8,
(value & 0xFF) as u8,
])?;
Ok(())
}
/// Removes all segments from the writer
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<()> {
// nothing to do
Ok(())
}
}
impl Default for VarWriter {
fn default() -> Self {
Self::new()
}
}