thruput-xdrs 0.17.1

XDR Serialization Library
Documentation
//! TXS buffer writer implementation.
//!
//! This module provides [`BufWriter`], which implements [`Writer`]
//! for writing TXS-encoded XDR data to a growable buffer.

use super::put::*;
use crate::serialize::writer::*;

use alloc::{vec, vec::Vec};

/// A writer for TXS-encoded XDR data to a growable buffer.
///
/// This writer implements the [`Writer`] trait for the TXS (Traditional XDR
/// Serialization) format. It writes data to an internal `Vec<u8>` buffer that
/// grows as needed.
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub struct BufWriter(Vec<u8>);

impl BufWriter {
    /// Creates a new `BufWriter` with an empty buffer.
    pub fn new() -> Self {
        Self(vec![])
    }

    /// Clear the buffer, to later reuse the memory
    /// for another encoding
    pub fn clear(&mut self) {
        self.0.clear();
    }

    /// Reserve space for the given number of bytes
    pub fn reserve(&mut self, len: usize) {
        self.0.reserve(len);
    }

    /// Returns the length of the buffer in bytes.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns `true` if the buffer contains no bytes.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Creates a new `BufWriter` with the specified capacity.
    pub fn with_capacity(cap: usize) -> Self {
        Self(Vec::with_capacity(cap))
    }
}

impl Default for BufWriter {
    fn default() -> Self {
        Self::new()
    }
}

impl From<Vec<u8>> for BufWriter {
    fn from(vec: Vec<u8>) -> Self {
        Self(vec)
    }
}

impl AsRef<[u8]> for BufWriter {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl AsMut<Vec<u8>> for BufWriter {
    fn as_mut(&mut self) -> &mut Vec<u8> {
        &mut self.0
    }
}

impl From<BufWriter> for Vec<u8> {
    fn from(w: BufWriter) -> Self {
        w.0
    }
}

// Implement the basic byte operations in order
// to get a Writer implementation for free
impl Put for BufWriter {
    #[inline]
    fn put_bytes(&mut self, bytes: &[u8]) -> WriteResult<()> {
        if bytes.len() > u32::MAX as usize {
            return Err(WriteError::InvalidArrayLength);
        }

        self.0.extend_from_slice(bytes);

        Ok(())
    }

    #[inline]
    fn put_opaque_variable(&mut self, bytes: &[u8]) -> WriteResult<()> {
        debug_assert!(bytes.len() <= u32::MAX as usize);

        let len = bytes.len();
        let rem = if len.is_multiple_of(4) {
            0
        } else {
            4 - len % 4
        };
        let size = 4 + len + rem;
        debug_assert!(size.is_multiple_of(4));

        self.0.reserve(size);

        static PAD: [u8; 3] = [0; 3];

        self.0.extend_from_slice(&(len as u32).to_be_bytes());
        self.0.extend_from_slice(bytes);
        self.0.extend_from_slice(&PAD[0..rem]);

        Ok(())
    }

    #[inline]
    fn put_opaque_fixed(&mut self, bytes: &[u8]) -> WriteResult<()> {
        debug_assert!(bytes.len() <= u32::MAX as usize);

        let len = bytes.len();
        let rem = if len.is_multiple_of(4) {
            0
        } else {
            4 - len % 4
        };
        let size = len + rem;
        debug_assert!(size.is_multiple_of(4));

        self.0.reserve(size);

        static PAD: [u8; 3] = [0; 3];

        self.0.extend_from_slice(bytes);
        self.0.extend_from_slice(&PAD[0..rem]);

        Ok(())
    }
}