ferroui_remote_protocol/i_transport.rs
1//! The contract of a connection that carries the messages of the protocol.
2//!
3//! # Threading contract
4//!
5//! The original is asynchronous: `Send` returns a `Task`, the streams are
6//! read and written with `async` calls and the events are raised on threads
7//! of the thread pool. This library has no asynchronous runtime and gives
8//! the following contract instead (DEVIATIONS.md, Remote protocol):
9//!
10//! - A connection is shared between threads (`Arc<dyn
11//! IFerroRemoteTransportConnection>`, `Send + Sync`) and every member may
12//! be called from any thread.
13//! - Each connection that reads has one reader thread. The message event and
14//! the exception event of a failed read are raised on it, one event at a
15//! time and in the order of arrival; the next message is not read before
16//! the handlers of the previous one have returned. The exception event of
17//! a failed write is raised on the thread that wrote. A handler that is
18//! added to a wrapped connection while events are stashed receives them on
19//! the thread that adds it.
20//! - Handlers are therefore `Send + Sync` and must not block for long. Code
21//! that belongs to another thread (the UI thread) posts to it from the
22//! handler, as the callers in the original do.
23//! - [`IFerroRemoteTransportConnection::send`] returns a [`Task`]. A stream
24//! connection writes on the calling thread and returns the task completed;
25//! a wrapped connection queues the message for its sender thread and
26//! returns at once. [`Task::wait`] blocks the calling thread.
27
28use std::sync::atomic::{AtomicU64, Ordering};
29use std::sync::Arc;
30
31use crate::error::Error;
32use crate::metsys_bson::BsonObject;
33use crate::task::Task;
34
35/// A message of the protocol: `object` in the signatures of the original.
36/// The class of a received message is found with
37/// `message.downcast_ref::<MeasureViewportMessage>()`.
38pub type Message = Arc<dyn BsonObject>;
39
40/// `Action<IFerroRemoteTransportConnection, T>`: a handler of an event of a
41/// connection.
42pub type Handler<T> = Arc<dyn Fn(&dyn IFerroRemoteTransportConnection, &T) + Send + Sync>;
43
44/// A handler of the message event.
45pub type MessageHandler = Handler<Message>;
46
47/// A handler of the exception event.
48pub type ExceptionHandler = Handler<Error>;
49
50/// Makes a handler of the message event from a closure.
51pub fn message_handler(
52 handler: impl Fn(&dyn IFerroRemoteTransportConnection, &Message) + Send + Sync + 'static,
53) -> MessageHandler {
54 Arc::new(handler)
55}
56
57/// Makes a handler of the exception event from a closure.
58pub fn exception_handler(
59 handler: impl Fn(&dyn IFerroRemoteTransportConnection, &Error) + Send + Sync + 'static,
60) -> ExceptionHandler {
61 Arc::new(handler)
62}
63
64/// What adding a handler returns and removing it takes: the identity of a
65/// delegate in `event -= handler`.
66#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
67pub struct HandlerToken(u64);
68
69impl HandlerToken {
70 fn next() -> HandlerToken {
71 static NEXT: AtomicU64 = AtomicU64::new(1);
72 HandlerToken(NEXT.fetch_add(1, Ordering::Relaxed))
73 }
74}
75
76/// A multicast delegate: the handlers of an event in the order they were
77/// added. Public for the connections that are implemented outside this
78/// library (the ones of the designer support), which keep their handlers in
79/// one as the connections here do.
80pub struct Delegate<T> {
81 handlers: Vec<(HandlerToken, Handler<T>)>,
82}
83
84impl<T> Delegate<T> {
85 pub fn new() -> Delegate<T> {
86 Delegate { handlers: Vec::new() }
87 }
88
89 /// `_delegate == null`.
90 pub fn is_null(&self) -> bool {
91 self.handlers.is_empty()
92 }
93
94 /// `_delegate += handler`.
95 pub fn add(&mut self, handler: Handler<T>) -> HandlerToken {
96 let token = HandlerToken::next();
97 self.handlers.push((token, handler));
98 token
99 }
100
101 /// `_delegate -= handler`.
102 pub fn remove(&mut self, token: HandlerToken) {
103 self.handlers.retain(|(t, _)| *t != token);
104 }
105
106 /// The handlers as they are now, to invoke them outside a lock.
107 pub fn snapshot(&self) -> Vec<Handler<T>> {
108 self.handlers.iter().map(|(_, handler)| handler.clone()).collect()
109 }
110}
111
112impl<T> Default for Delegate<T> {
113 fn default() -> Self {
114 Delegate::new()
115 }
116}
117
118/// A connection to the other end of the protocol.
119pub trait IFerroRemoteTransportConnection: Send + Sync {
120 /// `IDisposable.Dispose`: closes the connection. No exception event
121 /// follows from the closing itself.
122 fn dispose(&self);
123 /// Sends a message. The task completes when the message was written (or
124 /// dropped because the connection is broken) and fails when the message
125 /// cannot be sent as it is: its class is not known to the resolver, or
126 /// it cannot be serialized.
127 fn send(&self, data: Message) -> Task;
128 /// `OnMessage += handler`.
129 fn on_message(&self, handler: MessageHandler) -> HandlerToken;
130 /// `OnMessage -= handler`.
131 fn remove_on_message(&self, token: HandlerToken);
132 /// `OnException += handler`.
133 fn on_exception(&self, handler: ExceptionHandler) -> HandlerToken;
134 /// `OnException -= handler`.
135 fn remove_on_exception(&self, token: HandlerToken);
136 fn start(&self);
137}