rustzmq2 0.1.0

A native async Rust implementation of ZeroMQ
Documentation
//! Per-peer identity as defined by [ZMTP RFC 23](https://rfc.zeromq.org/spec/23/),
//! corresponding to libzmq's `ZMQ_ROUTING_ID` / historic `ZMQ_IDENTITY` option.

use crate::ZmqError;

use bytes::Bytes;
use uuid::Uuid;

use std::convert::TryFrom;
use std::ops::Deref;
use std::str::FromStr;

/// Per-peer identity (up to 255 bytes). Equivalent to libzmq's
/// `ZMQ_ROUTING_ID` — used to address a specific peer through a ROUTER
/// socket and surfaced in [`SocketEvent`](crate::SocketEvent)s.
///
/// # Examples
///
/// ```
/// use rustzmq2::PeerIdentity;
/// use std::str::FromStr;
///
/// // Identities are arbitrary bytes up to 255 long; > 255 errors out.
/// let id = PeerIdentity::try_from(&b"worker-1"[..]).unwrap();
/// assert_eq!(id.as_ref(), b"worker-1");
///
/// // Display is hex (safe for arbitrary bytes); use `as_ref()` for raw bytes.
/// assert_eq!(format!("{id}"), "776f726b65722d31");
///
/// // String parsing.
/// let parsed = PeerIdentity::from_str("worker-1").unwrap();
/// assert_eq!(id, parsed);
///
/// // No identity set → a fresh UUID is generated.
/// let _auto = PeerIdentity::new();
/// ```
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Clone)]
pub struct PeerIdentity(Bytes);

impl PeerIdentity {
    pub const MAX_LENGTH: usize = 255;

    pub fn new() -> Self {
        let id = Uuid::new_v4();
        Self(Bytes::copy_from_slice(id.as_bytes()))
    }
}

impl AsRef<[u8]> for PeerIdentity {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl std::borrow::Borrow<[u8]> for PeerIdentity {
    fn borrow(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl std::fmt::Display for PeerIdentity {
    /// Render the identity as hex. Identities can be arbitrary bytes —
    /// hex is the safe lossless rendering. Use `as_ref()` if you need
    /// the raw bytes.
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for byte in self.0.as_ref() {
            write!(f, "{:02x}", byte)?;
        }
        Ok(())
    }
}

impl Deref for PeerIdentity {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl Default for PeerIdentity {
    fn default() -> Self {
        Self::new()
    }
}

impl FromStr for PeerIdentity {
    type Err = ZmqError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::try_from(s.as_bytes())
    }
}

impl TryFrom<Bytes> for PeerIdentity {
    type Error = ZmqError;

    fn try_from(data: Bytes) -> Result<Self, ZmqError> {
        if data.is_empty() {
            Ok(Self::new())
        } else if data.len() > Self::MAX_LENGTH {
            Err(ZmqError::PeerIdentity)
        } else {
            Ok(Self(data))
        }
    }
}

impl TryFrom<&[u8]> for PeerIdentity {
    type Error = ZmqError;

    fn try_from(data: &[u8]) -> Result<Self, ZmqError> {
        Self::try_from(Bytes::copy_from_slice(data))
    }
}

impl TryFrom<Vec<u8>> for PeerIdentity {
    type Error = ZmqError;

    fn try_from(data: Vec<u8>) -> Result<Self, ZmqError> {
        Self::try_from(Bytes::from(data))
    }
}

impl From<PeerIdentity> for Bytes {
    fn from(p_id: PeerIdentity) -> Self {
        p_id.0
    }
}

impl From<PeerIdentity> for Vec<u8> {
    fn from(p_id: PeerIdentity) -> Self {
        p_id.0.to_vec()
    }
}