gaia-binary 0.1.1

Binary encoding and decoding for Gaia project
Documentation
use crate::{traits::BinaryFormat, TrackingWriter};
use gaia_types::{GaiaError, QualifiedName, Result};
use std::io::Write;

/// Generic binary writer with position tracking.
pub struct BinaryWriter<W: Write, F: BinaryFormat> {
    inner: TrackingWriter<W>,
    diagnostics: Vec<GaiaError>,
    _marker: std::marker::PhantomData<F>,
}

impl<W: Write, F: BinaryFormat> BinaryWriter<W, F> {
    /// Create a new binary writer.
    pub fn new(inner: W) -> Self {
        Self { inner: TrackingWriter { inner, position: 0 }, diagnostics: Vec::new(), _marker: std::marker::PhantomData }
    }

    /// Get current position.
    pub fn position(&self) -> u64 {
        self.inner.position
    }

    /// Add a diagnostic error.
    pub fn add_error(&mut self, error: GaiaError) {
        self.diagnostics.push(error);
    }

    /// Take all collected diagnostic errors.
    pub fn take_errors(&mut self) -> Vec<GaiaError> {
        std::mem::take(&mut self.diagnostics)
    }

    /// Write a u8 value.
    pub fn write_u8(&mut self, value: u8) -> Result<()> {
        self.inner.write_all(&[value]).map_err(|_| GaiaError::truncated())
    }

    /// Write a u16 value.
    pub fn write_u16(&mut self, value: u16) -> Result<()> {
        F::write_u16(&mut self.inner, value)
    }

    /// Write a u32 value.
    pub fn write_u32(&mut self, value: u32) -> Result<()> {
        F::write_u32(&mut self.inner, value)
    }

    /// Write a u64 value.
    pub fn write_u64(&mut self, value: u64) -> Result<()> {
        F::write_u64(&mut self.inner, value)
    }

    /// Write an i16 value.
    pub fn write_i16(&mut self, value: i16) -> Result<()> {
        F::write_i16(&mut self.inner, value)
    }

    /// Write an i32 value.
    pub fn write_i32(&mut self, value: i32) -> Result<()> {
        F::write_i32(&mut self.inner, value)
    }

    /// Write an i64 value.
    pub fn write_i64(&mut self, value: i64) -> Result<()> {
        F::write_i64(&mut self.inner, value)
    }

    /// Write an f32 value.
    pub fn write_f32(&mut self, value: f32) -> Result<()> {
        F::write_f32(&mut self.inner, value)
    }

    /// Write an f64 value.
    pub fn write_f64(&mut self, value: f64) -> Result<()> {
        F::write_f64(&mut self.inner, value)
    }

    /// Write raw bytes.
    pub fn write_bytes(&mut self, buf: &[u8]) -> Result<()> {
        self.inner.write_all(buf).map_err(|_| GaiaError::truncated())
    }

    /// Write all bytes from a slice.
    pub fn write_all(&mut self, buf: &[u8]) -> Result<()> {
        self.inner.write_all(buf).map_err(|_| GaiaError::truncated())
    }

    /// Write a string.
    pub fn write_string(&mut self, s: &str) -> Result<()> {
        let bytes = s.as_bytes();
        self.write_u32(bytes.len() as u32)?;
        self.write_bytes(bytes)
    }

    /// Write a qualified name.
    pub fn write_qualified_name(&mut self, qn: &QualifiedName) -> Result<()> {
        self.write_u32(qn.namespace.len() as u32)?;
        for part in &qn.namespace {
            self.write_string(part)?;
        }
        self.write_string(&qn.name)
    }

    /// Flush the writer.
    pub fn flush(&mut self) -> Result<()> {
        self.inner.flush().map_err(|_| GaiaError::truncated())
    }

    /// Consume the writer and return the inner writer.
    pub fn into_inner(self) -> W {
        self.inner.inner
    }
}

impl<W: Write + std::io::Seek, F: BinaryFormat> std::io::Seek for BinaryWriter<W, F> {
    fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
        self.inner.seek(pos)
    }
}

impl<W: Write + std::fmt::Debug, F: BinaryFormat> std::fmt::Debug for BinaryWriter<W, F> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("BinaryWriter").field("inner", &self.inner).field("position", &self.position()).finish()
    }
}