use std::num;
use crate::buffer::{self, write, write::consume::Error};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct Gap(num::NonZero<u32>, u32);
#[must_use = "commit the initialized span to publish bytes"]
pub struct Writer<'writer, 'target, const EXACT: bool> {
spare: &'writer mut write::Spare<'target>,
limit: u32,
len: u32,
}
impl Gap {
pub(in crate::buffer) fn check(expected: u32, actual: u32) -> Result<(), Self> {
if let Some(expected) = num::NonZero::new(expected)
&& actual < expected.get()
{
return Err(Self(expected, actual));
}
Ok(())
}
pub const fn into_parts(self) -> (num::NonZero<u32>, u32) {
(self.0, self.1)
}
}
impl<'writer, 'target, const EXACT: bool> Writer<'writer, 'target, EXACT> {
pub(in crate::buffer::write) fn new(spare: &'writer mut write::Spare<'target>) -> Self {
let limit = buffer::raw::Space::remaining(spare) as u32;
Self {
spare,
limit,
len: 0,
}
}
pub(in crate::buffer) fn try_new(
spare: &'writer mut write::Spare<'target>,
len: usize,
) -> Result<Self, Error> {
Error::check(len, buffer::raw::Space::remaining(spare))?;
Ok(Self {
spare,
limit: len as u32,
len: 0,
})
}
pub(in crate::buffer) fn suffix(&mut self) -> (*mut u8, usize) {
let start = self.spare.len() + self.len as usize;
(self.spare.pointer.as_ptr().cast(), start)
}
pub(in crate::buffer) unsafe fn extend(&mut self, copied: usize) {
self.len += copied as u32;
}
fn publish(self) {
self.spare.len += self.len;
}
pub fn try_init<I: buffer::raw::Initializer + ?Sized>(
&mut self,
source: &I,
) -> Result<(), Error> {
let len = source.len();
Error::check(len, buffer::raw::Space::remaining(self))?;
let (target, start) = self.suffix();
unsafe { source.initialize(target.add(start).cast()) };
unsafe { self.extend(len) };
Ok(())
}
}
impl<'writer, 'target> Writer<'writer, 'target, false> {
pub fn commit(self) {
self.publish();
}
}
impl<'writer, 'target> Writer<'writer, 'target, true> {
pub fn try_commit(self) -> Result<(), Gap> {
Gap::check(self.limit, self.len)?;
self.publish();
Ok(())
}
}
impl AsMut<[u8]> for Writer<'_, '_, true> {
fn as_mut(&mut self) -> &mut [u8] {
unsafe {
buffer::raw::range_mut(
self.spare.pointer.as_ptr().cast(),
self.spare.len(),
self.len as usize,
)
}
}
}
impl<const EXACT: bool> write::Sink for Writer<'_, '_, EXACT> {
type Error = Error;
fn write_slices<const N: usize>(&mut self, slices: [&[u8]; N]) -> Result<(), Self::Error> {
use buffer::raw::SliceExt as _;
let len = Error::checked_end(0, buffer::raw::Space::remaining(self), &slices)?;
let (target, start) = self.suffix();
unsafe {
slices.copy_to(target.add(start));
self.extend(len);
}
Ok(())
}
}
impl<const EXACT: bool> buffer::raw::Space for Writer<'_, '_, EXACT> {
fn remaining(&self) -> usize {
(self.limit - self.len) as usize
}
}
const _: () = assert!(size_of::<Gap>() == size_of::<u64>());
const _: () = assert!(size_of::<Option<Gap>>() == size_of::<u64>());
const _: () = assert!(size_of::<Result<(), Gap>>() == size_of::<u64>());
const _: () = assert!(size_of::<Writer<'static, 'static, false>>() == size_of::<usize>() * 2);
const _: () = assert!(size_of::<Writer<'static, 'static, true>>() == size_of::<usize>() * 2);