thruput-xdrs 0.17.1

XDR Serialization Library
Documentation
//! CXS writer that writes into a pre-allocated buffer.
//!
//! This module provides [`IntoBufWriter`], which implements [`Writer`] for
//! writing CXS-encoded XDR data into a pre-allocated buffer of
//! `MaybeUninit<u8>`.

use super::put::*;
use crate::serialize::writer::*;
use core::mem::MaybeUninit;

type Mu8 = MaybeUninit<u8>;

/// A writer for CXS-encoded XDR data into a pre-allocated buffer.
///
/// This writer implements the [`Writer`] trait for the CXS (Compact XDR
/// Serialization) format. It writes data into a provided buffer of
/// `MaybeUninit<u8>`, which is useful for `no_std` environments where
/// allocation is not available.
///
/// The buffer must be large enough to hold all the data being written, or
/// [`WriteError::SpaceExhausted`] will be returned.
///
pub struct IntoBufWriter<'a> {
    buf: &'a mut [Mu8],
    written: usize,
}

impl<'a> IntoBufWriter<'a> {
    /// Creates a new `IntoBufWriter` that writes into the given buffer.
    pub fn new(buf: &'a mut [Mu8]) -> Self {
        Self { buf, written: 0 }
    }

    /// Returns the number of bytes written so far.
    pub fn written(&self) -> usize {
        self.written
    }

    #[inline]
    fn reserve<'s>(&'s mut self, len: usize) -> WriteResult<&'s mut [Mu8]>
    where
        'a: 's,
    {
        let extent = self.written + len;
        if extent > self.buf.len() {
            return Err(WriteError::SpaceExhausted);
        }

        let start = self.written;
        self.written = extent;

        // SAFETY: we just verified extent <= self.buf.len(), and
        // start <= extent (since len >= 0 and start = old written).
        let reserved = unsafe { self.buf.get_unchecked_mut(start..extent) };

        Ok(reserved)
    }
}

impl<'a> Put for IntoBufWriter<'a> {
    #[inline]
    fn put_byte(&mut self, b: u8) -> WriteResult<()> {
        let p = self.reserve(1)?;
        p[0].write(b);
        Ok(())
    }

    #[inline]
    fn put_bytes(&mut self, bytes: &[u8]) -> WriteResult<()> {
        let len = bytes.len();
        let buf = self.reserve(len)?;

        // Cannot panic: reserve returns a slice of exactly `len` bytes,
        // and bytes.len() == len.
        buf.write_copy_of_slice(bytes);

        Ok(())
    }
}