ruststream-zeromq 0.7.0

ZeroMQ transport implementation of the RustStream broker contract, for bridging to non-Rust peers.
Documentation
//! The imports a routes file that mounts more than one `ZeroMQ` form writes, in one glob.
//!
//! The framework's prelude, the shared [`ZmqEndpoint`], the [`RequestReply`] capability, the
//! three broker types with their publish policies, and the three form modules (for the connected
//! forms and live publishers, which a service rarely names).
//!
//! Policies keep their prefixed names here, because all three forms call theirs `Publish` and one
//! glob cannot carry three. A routes file on a single form imports that form's prelude instead -
//! [`queue::prelude`], [`fanout::prelude`], [`rpc::prelude`] - and writes the bare `Publish`.
//!
//! # Examples
//!
//! A worker that takes jobs from a queue and announces each result to every listener on a fan-out:
//!
//! ```
//! use ruststream_zeromq::prelude::*;
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Deserialize)]
//! struct Job {
//!     id: u64,
//! }
//!
//! #[derive(Serialize, Outgoing)]
//! #[outgoing(name = "jobs.done")]
//! struct Done {
//!     id: u64,
//! }
//!
//! #[subscriber("jobs", reply)]
//! async fn work(job: &Job) -> Done {
//!     Done { id: job.id }
//! }
//!
//! #[ruststream::app]
//! fn app() -> impl App {
//!     let events = ZmqFanout::new(ZmqEndpoint::bind("tcp://0.0.0.0:5556")).bindable();
//!     let announce = events.bind(ZmqFanoutPublish);
//!     RustStream::new(AppInfo::new("worker", "0.1.0"))
//!         .with_broker(ZmqQueue::new(ZmqEndpoint::bind("tcp://0.0.0.0:5555")), |b| {
//!             b.include(work).out_reply(announce);
//!         })
//!         .register_broker(events)
//! }
//! ```

pub use ruststream::RequestReply;
pub use ruststream::prelude::*;

pub use crate::endpoint::ZmqEndpoint;

// Prefixed here, aliased to the bare `Publish` in each form prelude: three forms cannot share
// one bare name in a single glob, and a routes file that mounts two of them is exactly the file
// that needs to tell them apart.
pub use crate::{
    ZmqFanout, ZmqFanoutPublish, ZmqQueue, ZmqQueuePublish, ZmqRpc, ZmqRpcPublish, fanout, queue,
    rpc,
};

#[cfg(test)]
mod tests {
    //! What each prelude must carry, checked by globbing it exactly as a file would.
    //!
    //! A handler bound names a broker capability trait ([`Publisher`] and its siblings) and a
    //! mount site names a policy, so both vocabularies have to survive the glob: the capability
    //! trait as a bound, the policy as a value. A form prelude offers its policy under the bare
    //! `Publish`; the crate prelude cannot, because three forms would collide, so it offers the
    //! prefixed names and this pins that difference.

    mod queue {
        use crate::queue::prelude::*;

        #[expect(dead_code, reason = "the bound is the assertion; nothing calls it")]
        fn handler_bound<T: Publisher>() {}

        #[test]
        fn the_mount_site_vocabulary_is_the_bare_name() {
            let _: Publish = Publish;
        }
    }

    mod fanout {
        use crate::fanout::prelude::*;

        #[expect(dead_code, reason = "the bound is the assertion; nothing calls it")]
        fn handler_bound<T: Publisher>() {}

        #[test]
        fn the_mount_site_vocabulary_is_the_bare_name() {
            let _: Publish = Publish;
        }
    }

    mod rpc {
        use crate::rpc::prelude::*;

        #[expect(dead_code, reason = "the bounds are the assertion; nothing calls them")]
        fn handler_bound<T: Publisher>() {}

        // The request side rides the same policy, so `RequestReply` is a bound like any other.
        #[expect(dead_code, reason = "the bounds are the assertion; nothing calls them")]
        fn request_bound<T: RequestReply>() {}

        #[test]
        fn the_mount_site_vocabulary_is_the_bare_name() {
            let _: Publish = Publish;
        }
    }

    mod root {
        use crate::prelude::*;

        #[expect(dead_code, reason = "the bound is the assertion; nothing calls it")]
        fn handler_bound<T: Publisher>() {}

        #[test]
        fn the_three_policies_arrive_under_their_prefixed_names() {
            let _: ZmqQueuePublish = ZmqQueuePublish;
            let _: ZmqFanoutPublish = ZmqFanoutPublish;
            let _: ZmqRpcPublish = ZmqRpcPublish;
        }
    }
}