Skip to main content

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}