use zerocopy::IntoBytes;
extern crate alloc;
use alloc::vec::Vec;
pub type Result<T> = core::result::Result<T, BinaryWriterError>;
pub struct BinaryWriter {
pub out: Vec<u8>,
}
impl BinaryWriter {
pub fn wrap(out: Vec<u8>) -> Self {
Self { out }
}
pub fn into_inner(self) -> Vec<u8> {
self.out
}
pub fn inner_mut(&mut self) -> &mut Vec<u8> {
&mut self.out
}
pub fn new() -> Self {
Self { out: Vec::new() }
}
pub fn with_capacity(len: usize) -> Self {
Self {
out: Vec::with_capacity(len),
}
}
pub fn write_bytes(&mut self, bytes: &[u8]) {
self.out.extend_from_slice(bytes);
}
pub fn write_cbytes<const N: usize>(&mut self, value: [u8; N]) {
self.write_bytes(&value)
}
pub fn write_u8(&mut self, value: u8) {
self.write_bytes(&[value])
}
pub fn write_i8(&mut self, value: i8) {
self.write_bytes(&[value as u8])
}
pub fn write_u16(&mut self, value: u16) {
self.write_cbytes(value.to_le_bytes())
}
pub fn write_u32(&mut self, value: u32) {
self.write_cbytes(value.to_le_bytes())
}
pub fn write_u64(&mut self, value: u64) {
self.write_cbytes(value.to_le_bytes())
}
pub fn write_i16(&mut self, value: i16) {
self.write_cbytes(value.to_le_bytes())
}
pub fn write_i32(&mut self, value: i32) {
self.write_cbytes(value.to_le_bytes())
}
pub fn write_i64(&mut self, value: i64) {
self.write_cbytes(value.to_le_bytes())
}
pub fn write_7bit_encoded_i32(&mut self, value: i32) {
const MORE: u8 = 0x80; const MASK: u8 = 0x7f;
let w0: u8 = value as u8 & MASK; let w1: u8 = (value >> 7) as u8 & MASK; let w2: u8 = (value >> 14) as u8 & MASK; let w3: u8 = (value >> 21) as u8 & MASK; let w4: u8 = (value >> 28) as u8 & 0xF;
if w4 != 0 {
self.write_cbytes([w0 | MORE, w1 | MORE, w2 | MORE, w3 | MORE, w4]);
} else if w3 != 0 {
self.write_cbytes([w0 | MORE, w1 | MORE, w2 | MORE, w3]);
} else if w2 != 0 {
self.write_cbytes([w0 | MORE, w1 | MORE, w2]);
} else if w1 != 0 {
self.write_cbytes([w0 | MORE, w1]);
} else {
self.write_cbytes([w0]);
}
}
pub fn write_7bit_encoded_i64(&mut self, value: i64) {
let mut n: u64 = value as u64;
loop {
if n < 0x80 {
self.write_u8(n as u8);
break;
}
self.write_u8((n & 0x7f) as u8 | 0x80);
n >>= 7;
}
}
pub fn write_bool(&mut self, value: bool) {
self.write_u8(value as u8)
}
pub fn write_f32(&mut self, value: f32) {
self.write_cbytes(value.to_le_bytes());
}
pub fn write_f64(&mut self, value: f64) {
self.write_cbytes(value.to_le_bytes());
}
pub fn write_utf8_str(&mut self, s: &str) -> Result<()> {
let len_i32 = i32::try_from(s.len()).map_err(|_| BinaryWriterError::CannotEncode)?;
self.write_7bit_encoded_i32(len_i32);
self.write_bytes(s.as_bytes());
Ok(())
}
pub fn write_utf8_bytes(&mut self, s: &[u8]) -> Result<()> {
let len_i32 = i32::try_from(s.len()).map_err(|_| BinaryWriterError::CannotEncode)?;
self.write_7bit_encoded_i32(len_i32);
self.write_bytes(s);
Ok(())
}
pub fn write_utf16_wchars(&mut self, s: &[u16]) -> Result<()> {
let s_bytes = s.as_bytes();
let len_i32 = i32::try_from(s_bytes.len()).map_err(|_| BinaryWriterError::CannotEncode)?;
self.write_7bit_encoded_i32(len_i32);
self.write_bytes(s_bytes);
Ok(())
}
pub fn write_utf16_encode(&mut self, s: &str) {
let num_utf16_code_units = s.encode_utf16().count();
let len_bytes: usize = num_utf16_code_units * 2;
self.write_7bit_encoded_i32(len_bytes as i32);
self.out.reserve(len_bytes);
for c in s.encode_utf16() {
self.write_u16(c);
}
}
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum BinaryWriterError {
CannotEncode,
}
impl core::error::Error for BinaryWriterError {}
impl core::fmt::Display for BinaryWriterError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::CannotEncode => f.write_str("The data cannot be encoded"),
}
}
}