[−][src]Crate ump
Micro Message Pass (ump) is a library for passing messages between
thread/tasks. It has some similarities with the common mpsc channel
libraries, but with the most notable difference that in ump
the channel
is bidirectional. The terms "client"/"server" are used rather than
"tx"/"rx". In ump
the client initiates all message transfers, and every
message pass from a client to a server requires a response from the server.
The primary purpose of ump is to create simple RPC like designs, but between threads/tasks within a process rather than between processes over networks.
High-level usage overview
An application calls channel
to create a linked pair
of a Server
and a Client
.
The server calls
Server::wait()
/
Server::async_wait()
, which
blocks and waits for an incoming message from a client.
A client, on a separate thread, calls
Client::send()
/
Client::asend()
to send a message to
the server.
The server's wait call returns two objects: The message sent by the
client, and a ReplyContext
. After processing
its application-defined message, the server must call the
ReplyContext::reply()
on the
returned reply context object to return a reply message to the client.
Typically the server calls wait again to wait for next message from a
client.
The client receives the reply from the server and processes it.
Example
use std::thread; use ump::channel; fn main() { let (server, client) = channel::<String, String>(); let server_thread = thread::spawn(move || { // Wait for data to arrive from a client println!("Server waiting for message .."); let (data, mut rctx) = server.wait(); println!("Server received: '{}'", data); // Process data from client // Reply to client let reply = format!("Hello, {}!", data); println!("Server replying '{}'", reply); rctx.reply(reply); println!("Server done"); }); let msg = String::from("Client"); println!("Client sending '{}'", msg); let reply = client.send(String::from(msg)).unwrap(); println!("Client received reply '{}'", reply); println!("Client done"); server_thread.join().unwrap(); }
(In practice it's more likely that the channel types are enum
s used to
indicate command/return type with associated data).
Semantics
There are some potentially useful semantics quirks that can be good to know about, but some of them should be used with caution.
Stable invariants
These are behaviors which should not change in coming versions.
- The reply contexts are independent of the
Server
context. This has some useful implications for server threads that spawn separate threads to process messages and return replies: The server can safely terminate while there are clients waiting for replies (implied: the server can safely terminate while there are reply contexts in-flight). - A cloned client is paired with the same server as its origin, but in all other respects the clone and its origin are independent of each other.
- A client can be moved to a new thread.
- Any permutation of sync/async server/clients can be combined.
async
code must use the async method variants when available.
Unstable invariants
These are invaiants you can trust will work in the current version, but they exist merely as a side-effect of the current implementation. Avoid using these if possible.
- A single client can be used from two different threads. If a
Client
object in placed in an Arc, is cloned and passed to another thread/task then both the clone and the original can be used simultaneously. In the future this may not be allowed. It is recommended that a new clone of the client be created instead.
Structs
Client | Representation of a clonable client object. |
ReplyContext | Public-facing sender part of the |
Server | Representation of a server object. |
Enums
Error | Module-specific error codes. |
Functions
channel | Create a pair of linked |