zmux 1.0.2

Rust implementation of the ZMux v1 stream multiplexing protocol
Documentation
use crate::config::OpenOptions;
use crate::error::{Error, Result};
use std::borrow::Cow;
use std::io::IoSlice;
use std::time::Duration;

/// Request parameters for opening a stream.
///
/// Open metadata is carried inside `OpenOptions` and is opaque binary data.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct OpenRequest {
    options: OpenOptions,
    timeout: Option<Duration>,
}

impl OpenRequest {
    #[inline]
    #[must_use]
    pub fn new() -> Self {
        Self::default()
    }

    #[inline]
    #[must_use]
    pub fn options(mut self, options: OpenOptions) -> Self {
        self.options = options;
        self
    }

    #[inline]
    #[must_use]
    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = Some(timeout);
        self
    }

    #[inline]
    pub fn open_options(&self) -> &OpenOptions {
        &self.options
    }

    #[inline]
    pub fn timeout_duration(&self) -> Option<Duration> {
        self.timeout
    }

    #[inline]
    pub fn into_parts(self) -> (OpenOptions, Option<Duration>) {
        (self.options, self.timeout)
    }
}

impl From<OpenOptions> for OpenRequest {
    #[inline]
    fn from(options: OpenOptions) -> Self {
        Self::new().options(options)
    }
}

/// Binary payload for write operations.
///
/// Borrowed buffers stay borrowed until the operation returns. Owned buffers
/// can be moved into the runtime without another caller-side copy.
#[derive(Debug, Clone)]
pub enum WritePayload<'a> {
    Bytes(Cow<'a, [u8]>),
    Vectored(&'a [IoSlice<'a>]),
}

impl<'a> WritePayload<'a> {
    #[inline]
    #[must_use]
    pub fn bytes(data: &'a [u8]) -> Self {
        Self::Bytes(Cow::Borrowed(data))
    }

    #[inline]
    #[must_use]
    pub fn vectored(parts: &'a [IoSlice<'a>]) -> Self {
        Self::Vectored(parts)
    }

    #[inline]
    pub fn checked_len(&self) -> Result<usize> {
        match self {
            Self::Bytes(data) => Ok(data.len()),
            Self::Vectored(parts) => parts.iter().try_fold(0usize, |total, part| {
                total
                    .checked_add(part.len())
                    .ok_or_else(|| Error::local("zmux: vectored write length overflow"))
            }),
        }
    }

    #[inline]
    #[must_use]
    pub fn is_empty(&self) -> bool {
        match self {
            Self::Bytes(data) => data.is_empty(),
            Self::Vectored(parts) => parts.iter().all(|part| part.is_empty()),
        }
    }
}

impl<'a> From<&'a [u8]> for WritePayload<'a> {
    #[inline]
    fn from(data: &'a [u8]) -> Self {
        Self::bytes(data)
    }
}

impl<'a> From<&'a Vec<u8>> for WritePayload<'a> {
    #[inline]
    fn from(data: &'a Vec<u8>) -> Self {
        Self::bytes(data.as_slice())
    }
}

impl<'a> From<&'a mut Vec<u8>> for WritePayload<'a> {
    #[inline]
    fn from(data: &'a mut Vec<u8>) -> Self {
        Self::bytes(data.as_slice())
    }
}

impl<'a> From<Vec<u8>> for WritePayload<'a> {
    #[inline]
    fn from(data: Vec<u8>) -> Self {
        Self::Bytes(Cow::Owned(data))
    }
}

impl<'a> From<Cow<'a, [u8]>> for WritePayload<'a> {
    #[inline]
    fn from(data: Cow<'a, [u8]>) -> Self {
        Self::Bytes(data)
    }
}

impl<'a, const N: usize> From<&'a [u8; N]> for WritePayload<'a> {
    #[inline]
    fn from(data: &'a [u8; N]) -> Self {
        Self::bytes(data.as_slice())
    }
}

impl<'a, const N: usize> From<[u8; N]> for WritePayload<'a> {
    #[inline]
    fn from(data: [u8; N]) -> Self {
        Self::Bytes(Cow::Owned(Vec::from(data)))
    }
}

impl<'a> From<&'a [IoSlice<'a>]> for WritePayload<'a> {
    #[inline]
    fn from(parts: &'a [IoSlice<'a>]) -> Self {
        Self::vectored(parts)
    }
}

/// Complete request for opening a stream and immediately sending binary data.
#[derive(Debug, Clone)]
pub struct OpenSend<'a> {
    options: OpenOptions,
    payload: WritePayload<'a>,
    timeout: Option<Duration>,
}

impl<'a> OpenSend<'a> {
    #[inline]
    #[must_use]
    pub fn new(payload: impl Into<WritePayload<'a>>) -> Self {
        Self {
            options: OpenOptions::default(),
            payload: payload.into(),
            timeout: None,
        }
    }

    #[inline]
    #[must_use]
    pub fn vectored(parts: &'a [IoSlice<'a>]) -> Self {
        Self::new(WritePayload::vectored(parts))
    }

    #[inline]
    #[must_use]
    pub fn options(mut self, options: OpenOptions) -> Self {
        self.options = options;
        self
    }

    #[inline]
    #[must_use]
    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = Some(timeout);
        self
    }

    #[inline]
    pub fn open_options(&self) -> &OpenOptions {
        &self.options
    }

    #[inline]
    pub fn payload(&self) -> &WritePayload<'a> {
        &self.payload
    }

    #[inline]
    pub fn timeout_duration(&self) -> Option<Duration> {
        self.timeout
    }

    #[inline]
    pub fn into_parts(self) -> (OpenOptions, WritePayload<'a>, Option<Duration>) {
        (self.options, self.payload, self.timeout)
    }
}

impl<'a> From<&'a [u8]> for OpenSend<'a> {
    #[inline]
    fn from(data: &'a [u8]) -> Self {
        Self::new(data)
    }
}

impl<'a> From<&'a Vec<u8>> for OpenSend<'a> {
    #[inline]
    fn from(data: &'a Vec<u8>) -> Self {
        Self::new(data.as_slice())
    }
}

impl<'a> From<&'a mut Vec<u8>> for OpenSend<'a> {
    #[inline]
    fn from(data: &'a mut Vec<u8>) -> Self {
        Self::new(data.as_slice())
    }
}

impl<'a> From<Vec<u8>> for OpenSend<'a> {
    #[inline]
    fn from(data: Vec<u8>) -> Self {
        Self::new(data)
    }
}

impl<'a> From<Cow<'a, [u8]>> for OpenSend<'a> {
    #[inline]
    fn from(data: Cow<'a, [u8]>) -> Self {
        Self::new(data)
    }
}

impl<'a, const N: usize> From<&'a [u8; N]> for OpenSend<'a> {
    #[inline]
    fn from(data: &'a [u8; N]) -> Self {
        Self::new(data.as_slice())
    }
}

impl<'a, const N: usize> From<[u8; N]> for OpenSend<'a> {
    #[inline]
    fn from(data: [u8; N]) -> Self {
        Self::new(data)
    }
}

impl<'a> From<&'a [IoSlice<'a>]> for OpenSend<'a> {
    #[inline]
    fn from(parts: &'a [IoSlice<'a>]) -> Self {
        Self::vectored(parts)
    }
}

impl<'a> From<WritePayload<'a>> for OpenSend<'a> {
    #[inline]
    fn from(payload: WritePayload<'a>) -> Self {
        Self::new(payload)
    }
}