Skip to main content

monocoque_zmtp/
socket_trait.rs

1//! Trait-based socket API for polymorphic socket handling.
2//!
3//! This module provides a generic `Socket` trait that enables working with
4//! different socket types in a uniform way, particularly useful for:
5//! - Generic proxy implementations
6//! - Testing and mocking
7//! - Dynamic socket type selection
8//! - Library APIs that work with any socket type
9
10use bytes::Bytes;
11use std::io;
12
13use crate::SocketType;
14
15/// Generic socket trait for polymorphic handling of different socket types.
16///
17/// All ZeroMQ socket types (DEALER, ROUTER, REQ, REP, PAIR, PUSH, PULL, SUB, XSUB, XPUB, PUB)
18/// implement this trait, enabling:
19/// - Generic functions that work with any socket type
20/// - Proxy implementations (e.g., `proxy<F, B>()` where F, B: Socket)
21/// - Testing with mock sockets
22/// - Runtime socket type selection
23///
24/// # Examples
25///
26/// ```no_run
27/// use monocoque_zmtp::{Socket, DealerSocket, RouterSocket};
28/// use std::io;
29///
30/// async fn forward_messages<S1, S2>(from: &mut S1, to: &mut S2) -> io::Result<()>
31/// where
32///     S1: Socket,
33///     S2: Socket,
34/// {
35///     while let Some(msg) = from.recv().await? {
36///         to.send(msg).await?;
37///     }
38///     Ok(())
39/// }
40/// ```
41#[async_trait::async_trait(?Send)]
42pub trait Socket {
43    /// Send a multipart message on the socket.
44    ///
45    /// # Arguments
46    ///
47    /// * `msg` - Multipart message as a vector of frames
48    ///
49    /// # Returns
50    ///
51    /// - `Ok(())` - Message sent successfully
52    /// - `Err(io::Error)` - Send failed (timeout, disconnection, etc.)
53    async fn send(&mut self, msg: Vec<Bytes>) -> io::Result<()>;
54
55    /// Receive a multipart message from the socket.
56    ///
57    /// # Returns
58    ///
59    /// - `Ok(Some(msg))` - Message received successfully
60    /// - `Ok(None)` - No message available (non-blocking mode)
61    /// - `Err(io::Error)` - Receive failed (timeout, disconnection, etc.)
62    async fn recv(&mut self) -> io::Result<Option<Vec<Bytes>>>;
63
64    /// Get the socket type.
65    ///
66    /// Returns the ZeroMQ socket type enum (DEALER, ROUTER, REQ, etc.).
67    fn socket_type(&self) -> SocketType;
68
69    /// Check if socket has more message frames pending.
70    ///
71    /// Equivalent to ZMQ_RCVMORE option. Returns true if the last recv()
72    /// operation received a partial message with more frames to follow.
73    fn has_more(&self) -> bool {
74        // Default implementation - sockets can override if they track this
75        false
76    }
77}
78
79/// Macro to implement the Socket trait for socket types with standard send/recv methods.
80///
81/// This macro generates boilerplate trait implementations for socket types that follow
82/// the standard pattern of having `send(&mut self, Vec<Bytes>)` and `recv(&mut self)` methods.
83///
84/// # Usage
85///
86/// ```ignore
87/// impl_socket_trait!(DealerSocket<S>, SocketType::Dealer);
88/// ```
89#[macro_export]
90macro_rules! impl_socket_trait {
91    ($socket_type:ty, $zmq_type:expr) => {
92        #[async_trait::async_trait(?Send)]
93        impl<S> $crate::Socket for $socket_type
94        where
95            S: compio_io::AsyncRead + compio_io::AsyncWrite + Unpin + 'static,
96        {
97            async fn send(&mut self, msg: Vec<bytes::Bytes>) -> std::io::Result<()> {
98                self.send(msg).await
99            }
100
101            async fn recv(&mut self) -> std::io::Result<Option<Vec<bytes::Bytes>>> {
102                self.recv().await
103            }
104
105            fn socket_type(&self) -> $crate::SocketType {
106                $zmq_type
107            }
108        }
109    };
110}