ump_ng_server/
lib.rs

1//! _ump-ng-server_ is an abstraction on top of [`ump-ng`](ump_ng) that is used
2//! to hide boilerplate code used to implement intra-process message passing
3//! servers.
4//!
5//! # Dispatch loop
6//! The core functionality of _ump-ng-server_ is a dispatch loop, whose role it
7//! is to pull messages off the message queue and pass them to the
8//! application-supplied message handler.
9//!
10//! There are two different ways to run the dispatcher loop: On a non-async
11//! thread or as an async task.  The former is launched using
12//! [`thread::spawn()`] and the latter [`task::spawn()`] (only available using
13//! the `tokio` feature).
14//!
15//! The `spawn()` functions return a tuple containing a `Client` (that can be
16//! used to send pass messages to the server) and a `JoinHandle` that can be
17//! used to wait for the dispatch loop thread/task to terminate (and retreive
18//! its return value).
19//!
20//! The returned `JoinHandle` will, once joined, return an `Option<RV>`.
21//! If this is `None` the server was terminated because all the `Client`
22//! endpoints were dropped.  If this is `Some(RV)` the server was terminated
23//! because a callback requested its termination by returning
24//! `ControlFlow::Break(RV)`.
25//!
26//! There are two ways to terminate the dispatch loop:
27//! - The message processing handler returns `ControlFlow::Break(RV)` (rather
28//!   than `ControlFlow::Continue(())`).  This would cause the thread/task to
29//!   return `Some(RV)`.
30//! - The message queue is empty and all the associated [`Client`]s have been
31//!   released.  This would cause the thread to return `None`.
32//!
33//! # Application message handlers
34//! Message handlers are implemented using the [`thread::Handler`] trait (for
35//! the threaded dispatch loop) and [`task::Handler`] (for the async dispatch
36//! loop).
37//!
38//! There are cases where the handler needs to store a clone of the client
39//! end-point of the message passing channel used to issue requests to the
40//! server (so that message handlers can issue new requests).  In order to
41//! facilitate this, the application must pass a `Handler`-construction closure
42//! to `spawn()`.  The closure will be called after the message passing channel
43//! has been created so it can be passed a reference to the client end-point.
44//!
45//! If the dispatch loop should terminate once all the application's client
46//! end-points have been dropped, then the handler can store a [`WeakClient`]
47//! instead (as storing a cloned [`Client`] object will preventing the dispatch
48//! loop from terminating due to all clients being lost).  The examples in the
49//! [`task`] and [`thread`] modules illustrate how to do this.
50
51#![cfg_attr(docsrs, feature(doc_cfg))]
52
53#[cfg(feature = "watchdog")]
54mod wdog;
55
56#[cfg(feature = "tokio")]
57#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
58pub mod task;
59
60pub mod thread;
61
62pub use ump_ng::{
63  self, channel, Client, MsgType, ReplyContext, Server, WeakClient
64};
65
66pub use thread::{spawn as spawn_thread, Handler as ThreadedHandler};
67
68#[cfg(feature = "tokio")]
69#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
70pub use task::{spawn as spawn_task, Handler as AsyncHandler};
71
72#[cfg(feature = "tokio")]
73#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
74pub use async_trait::async_trait;
75
76// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :