1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! > Note that this library is in the very early stages of development!
//! > Anything and everything may change!
//!
//! # zedmq
//!
//! ## A Lightweight, Safe, pure-Rust ØMQ/ZMTP library implementation
//!
//! ## Index
//!
//! * [Brief](#brief)
//! * [Examples](#examples)
//!
//! ### Brief
//!
//! _Zedmq_ is a native implementation of ØMQ in Rust focusing on:
//!
//! * being as lightweight as possible.
//! * being completely safe.
//! * providing a simple, blocking, obvious API.
//!
//! This library is lazy and blocking, no work is done unless a call to a
//! `recv` or `send` is made. There is no "background" thread or task accepting
//! new connections or performing reconnections on the users behalf
//! consequently there is no shared state or synchronization being performed.
//!
//! #### Caveats
//!
//! Currently this library only supports connecting sockets
//! over TCP, no binding behaviour is available.
//!
//! Also only a few socket types have been implemented: REQ, REP, PULL, PUSH,
//! and SUB (PUB is being worked on).
//!
//! #### `Frame<'_>` and `FrameBuf`
//!
//! This library also exposes the underlying ZMQ concept of a frame.
//! Additionally a distinction is made with the `Frame` and `FrameBuf` types
//! for optimization purposes.
//!
//! Conceptually a `Frame<'_>` is equivelent to `&'_ [u8]` or `&'_ str` and
//! the `FrameBuf` equivelent is `Vec<u8>` or `String`. This distinction is
//! made in an attempt to make "zero copy" or "zero heap" practice easier.
//!
//! #### `REQ` and `REP`
//!
//! The design of `REQ` and `REP` sockets are symetrical and rendered safe
//! through the use of the type system.
//!
//! A `Req` socket only has `.connect` and `.send` methods, `.send` of which
//! consumes the socket and returns a `ReqPending` socket which only has a `.recv`
//! method which in turn returns a multipart message and `Req` socket tuple.
//!
//! Same goes for the `Rep` socket except that `Rep` has `.recv` and
//! `RepPending` has `.send`.
//!
//! This done on purpose, its value is that there are no accidental footguns
//! involved with accidentially `.send`ing when you are only allowed to `.recv`
//! or vice versa. Plus it removes the cost of runtime checking.
//!
//! ### Examples
//!
//! ```rust,no_run
//! use zedmq::prelude::*;
//!
//! fn main() -> std::io::Result<()> {
//!     let mut socket: Pull = zedmq::connect("tcp", "127.0.0.1:5678")?;
//!
//!     while let Ok(message) = socket.recv() {
//!         dbg!(message);
//!     }
//!
//!     Ok(())
//! }
//! ```

#![forbid(unsafe_code)]
#![warn(missing_docs)]

/// The currently supported ZMQ version.
pub const ZMQ_VERSION: (u8, u8, u8) = (3, 1, 0);

pub(crate) mod codec;
mod socket_type;
pub(crate) mod stream;

pub use socket_type::{
    pull_t::Pull,
    push_t::Push,
    rep_t::{Rep, RepPending},
    req_t::{Req, ReqPending},
    sub_t::Sub,
};

mod sealed {
    pub trait SocketType {
        fn name() -> &'static str;
    }

    macro_rules! impl_socket_type {
        [$( ($name:ident, $st:literal) ),+] => {
            $(
                impl SocketType for $crate::$name { fn name() -> &'static str { $st } }
            )+
        }
    }

    impl_socket_type![
        (Pull, "PULL"),
        (Push, "PUSH"),
        (Sub, "SUB"),
        (Req, "REQ"),
        (Rep, "REP")
    ];
}

use sealed::SocketType;
use socket_type::Socket;
use stream::Stream;

/// Start a ZMQ socket with the specified `transport` to the specified `address`.
pub fn connect<S>(transport: &str, address: &str) -> std::io::Result<S>
where
    S: SocketType + Socket + From<Stream>,
{
    assert_eq!(transport, "tcp", "Only TCP is supported.");

    let name = <S as SocketType>::name();
    let stream = Stream::connected(name, address);

    Ok(stream.into())
}

/// Bind a ZMQ socket with the specified `transport` to the specified `address`.
pub fn bind<S>(_transport: &str, _address: &str) -> std::io::Result<S>
where
    S: SocketType + Socket + From<Stream>,
{
    unimplemented!();
}

/// The library prelude, containing all the stuff you probably want.
pub mod prelude {
    pub use super::*;
}