dope-net 0.10.1

The manifold runtime
Documentation
use o3::buffer::Shared;

use super::arena::PreparedChain;
use super::metadata::MetadataQueue;
use super::raw::entry::Entry;
use super::wire::raw::lease::WireLease;

pub struct Stage<'a, B = Shared> {
    wire: &'a mut Option<WireLease>,
    entries: &'a MetadataQueue<Entry<B>>,
    start: usize,
    len: usize,
    overflowed: bool,
    committed: bool,
}

impl<'a, B> Stage<'a, B> {
    pub(super) fn open(
        wire: &'a mut Option<WireLease>,
        entries: &'a MetadataQueue<Entry<B>>,
    ) -> Self {
        let (start, overflowed) = match wire.as_mut() {
            Some(buffer) => (buffer.len(), false),
            None => (0, true),
        };
        Self {
            wire,
            entries,
            start,
            len: 0,
            overflowed,
            committed: false,
        }
    }
}

impl<B> Stage<'_, B> {
    pub fn len(&self) -> usize {
        self.len
    }

    pub fn is_empty(&self) -> bool {
        self.len == 0
    }

    pub fn overflowed(&self) -> bool {
        self.overflowed
    }

    pub fn push(&mut self, byte: u8) {
        if self.overflowed {
            return;
        }
        let Some(buffer) = self.wire.as_mut() else {
            self.overflowed = true;
            return;
        };
        if !buffer.push(byte) {
            self.overflowed = true;
            return;
        }
        self.len += 1;
    }

    pub fn extend_from_slice(&mut self, src: &[u8]) {
        if self.overflowed {
            return;
        }
        let Some(buffer) = self.wire.as_mut() else {
            self.overflowed = true;
            return;
        };
        if !buffer.extend_from_slice(src) {
            self.overflowed = true;
            return;
        }
        self.len += src.len();
    }

    pub fn as_mut_slice(&mut self) -> &mut [u8] {
        let Some(buffer) = self.wire.as_mut() else {
            return &mut [];
        };
        &mut buffer.as_mut_slice()[self.start..self.start + self.len]
    }
}

impl<B: AsRef<[u8]>> Stage<'_, B> {
    pub fn commit(self) -> usize {
        self.commit_with(None::<B>)
    }

    pub(super) fn commit_with(mut self, body: Option<B>) -> usize {
        if self.overflowed || self.len == 0 {
            return 0;
        }
        let Some(buffer) = self.wire.as_ref() else {
            return 0;
        };
        let data = buffer.pointer_at(self.start);
        let mut prepared = PreparedChain::new(&self.entries.arena.pool);
        if !prepared.push_wire(data, self.len) {
            return 0;
        }
        if let Some(body) = body
            && !prepared.push(body)
        {
            return 0;
        }
        if !prepared.commit(self.entries) {
            return 0;
        }
        self.committed = true;
        self.len
    }
}

impl<B> Drop for Stage<'_, B> {
    fn drop(&mut self) {
        if !self.committed
            && let Some(buffer) = self.wire.as_mut()
        {
            buffer.truncate(self.start);
        }
        if self.wire.as_ref().is_some_and(WireLease::is_empty) {
            self.wire.take();
        }
    }
}