dope-tls 0.19.0

TCP TLS streams for dope runtime, shin-backed
Documentation
use std::ops;

use crate::error;
use o3::buffer::PrefixConsumer as _;
use o3::buffer::{self, bytes, pool};

pub(super) struct ReceiveOverflow;

pub(super) enum Pending<'a, 'd> {
    Pooled {
        buffer: &'a mut Option<pool::BorrowedCursor<'d>>,
        pool: &'d buffer::Pool,
    },
    Borrowed(&'a mut pool::BorrowedCursor<'d>),
}

impl<'d> Pending<'_, 'd> {
    pub(super) fn try_buffer(&mut self) -> Option<&mut pool::BorrowedCursor<'d>> {
        match self {
            Self::Pooled { buffer, pool } => {
                if buffer.is_none() {
                    **buffer = pool.try_acquire_borrowed_buffer();
                }
                buffer.as_mut()
            }
            Self::Borrowed(buffer) => Some(buffer),
        }
    }
}

pub(crate) struct Buffers<'d> {
    recv: Option<pool::BorrowedCursor<'d>>,
    recv_pool: &'d buffer::Pool,
    pub(super) pending: Option<pool::BorrowedCursor<'d>>,
    pending_pool: &'d buffer::Pool,
}

impl<'d> Buffers<'d> {
    pub(crate) fn pooled(recv_pool: &'d buffer::Pool, pending_pool: &'d buffer::Pool) -> Self {
        Self {
            recv: None,
            recv_pool,
            pending: None,
            pending_pool,
        }
    }

    pub(crate) fn pooled_with_pending(
        recv_pool: &'d buffer::Pool,
        pending_pool: &'d buffer::Pool,
        pending: pool::BorrowedCursor<'d>,
    ) -> Self {
        Self {
            recv: None,
            recv_pool,
            pending: Some(pending),
            pending_pool,
        }
    }

    pub(super) fn append_recv(&mut self, bytes: &[u8]) -> Result<usize, ReceiveOverflow> {
        if bytes.is_empty() {
            return Ok(0);
        }
        if self.recv.is_none() {
            self.recv = Some(
                self.recv_pool
                    .try_acquire_borrowed_buffer()
                    .ok_or(ReceiveOverflow)?,
            );
        }
        let recv = self.recv.as_mut().ok_or(ReceiveOverflow)?;
        let take = bytes.len().min(recv.spare_capacity());
        recv.try_extend(&bytes[..take])
            .map_err(|_| ReceiveOverflow)?;
        Ok(take)
    }

    pub(super) fn recv(&self) -> &[u8] {
        self.recv.as_ref().map_or(&[], |cursor| cursor.as_slice())
    }

    pub(super) fn recv_record_and_pending(
        &mut self,
        total: usize,
    ) -> Result<(&mut [u8], Pending<'_, 'd>), error::Error> {
        let recv = self.recv.as_mut().ok_or(error::Error::BufferUnavailable)?;
        Ok((
            &mut recv.as_mut_slice()[..total],
            Pending::Pooled {
                buffer: &mut self.pending,
                pool: self.pending_pool,
            },
        ))
    }

    pub(super) fn try_consume_recv(&mut self, n: usize) -> bool {
        let Some(recv) = self.recv.as_mut() else {
            return n == 0;
        };
        let Ok(prefix) = recv.try_consume_prefix(n) else {
            return false;
        };
        prefix.commit();
        if recv.is_empty() {
            self.recv = None;
        }
        true
    }

    pub(super) fn take_recv_range(
        &mut self,
        range: ops::Range<usize>,
    ) -> Option<bytes::Bytes<bytes::Pooled<'d>>> {
        self.recv.take()?.freeze().get(range)
    }

    pub(super) fn pending(&self) -> &[u8] {
        self.pending
            .as_ref()
            .map_or(&[], |cursor| cursor.as_slice())
    }

    pub(super) fn pending_output(&mut self) -> Pending<'_, 'd> {
        Pending::Pooled {
            buffer: &mut self.pending,
            pool: self.pending_pool,
        }
    }

    pub(super) fn pending_spare(&self) -> usize {
        self.pending.as_ref().map_or_else(
            || self.pending_pool.capacity(),
            |cursor| cursor.spare_capacity(),
        )
    }

    pub(super) fn pending_pool(&self) -> &'d buffer::Pool {
        self.pending_pool
    }

    pub(super) fn try_consume_pending(&mut self, n: usize) -> bool {
        let Some(pending) = self.pending.as_mut() else {
            return n == 0;
        };
        let Ok(prefix) = pending.try_consume_prefix(n) else {
            return false;
        };
        prefix.commit();
        if pending.is_empty() {
            self.pending = None;
        }
        true
    }

    pub(crate) fn reserve_recv(&mut self) -> bool {
        if self.recv.is_none() {
            self.recv = self.recv_pool.try_acquire_borrowed_buffer();
        }
        self.recv.is_some()
    }

    pub(crate) fn release_recv_if_empty(&mut self) -> bool {
        let released = self.recv.as_ref().is_some_and(|cursor| cursor.is_empty());
        if released {
            self.recv = None;
        }
        released
    }
}