thin-fetch 0.1.0

Low-level Git crate to fetch objects with high granularity
Documentation
use std::io::Write;

use crate::{Error, WithError as _, bail};

use super::{MARKER_END, MARKER_SEP};

pub struct ParcelEncoder<W: Write> {
    writer: W,
}

impl<W: Write> ParcelEncoder<W> {
    pub fn new(writer: W) -> Self {
        Self { writer }
    }

    /// Write a data packet to the output stream.
    ///
    /// # Errors
    ///
    /// Returns an error when data packet size exceeds 65531,
    /// or when cannot write the data to the writer.
    pub fn write_data(&mut self, data: &[u8]) -> Result<(), Error> {
        let len = data.len() + 4;

        let mut len_bytes = vec![];
        write!(len_bytes, "{len:04x}").with_err_msg("could not format length")?;
        if len_bytes.len() > 4 {
            bail!("payload too long");
        }

        self.writer
            .write_all(&len_bytes)
            .with_err_msg("could not write length")?;

        self.writer
            .write_all(data)
            .with_err_msg("could not write data")?;

        Ok(())
    }

    /// Writes a section separator marker to the output stream.
    ///
    /// # Errors
    ///
    /// Returns an error when cannot write data to the writer.
    pub fn new_section(&mut self) -> Result<(), Error> {
        self.writer
            .write_all(&MARKER_SEP)
            .with_err_msg("could not write separator marker")
    }

    /// Writes a stream end marker to the output stream.
    ///
    /// # Errors
    ///
    /// Returns an error when cannot write data to the writer.
    pub fn finish(mut self) -> Result<(), Error> {
        self.writer
            .write_all(&MARKER_END)
            .with_err_msg("could not write end marker")
    }
}