intercomm/
lib.rs

1#![warn(missing_docs)]
2#![warn(clippy::missing_safety_doc)]
3#![warn(clippy::missing_panics_doc)]
4
5//! Asynchronous inter-component communication library
6//!
7//! ## Example
8//!
9//! ```rust
10//! use intercomm::{broadcast, notification, request};
11//!
12//! intercomm::declare! {
13//!     request Sum((i32, i32)) -> i32;
14//!     request Mul((i32, i32)) -> i32;
15//!
16//!     notification[2] Ready(());
17//!     broadcast[1] Close(());
18//! }
19//!
20//! async fn sum_listener() {
21//!     let mut listener = request::listen::<Sum>().await.expect("Sum listen twice");
22//!     let mut close = broadcast::subscribe::<Close>().await;
23//!     Ready::notify(()).await.expect("Cannot send Ready");
24//!
25//!     loop {
26//!         tokio::select! {
27//!             _ = close.recv() => {
28//!                 listener.close().await;
29//!                 close.close().await;
30//!                 return;
31//!             }
32//!             _ = listener.accept(|(a, b)| async move {
33//!                 println!("Sum requested with: ({}, {})", a, b);
34//!                 a + b
35//!             }) => {}
36//!         }
37//!     }
38//! }
39//!
40//! async fn mul_listener() {
41//!     let mut listener = request::listen::<Mul>().await.expect("Mul listen twice");
42//!     let mut close = broadcast::subscribe::<Close>().await;
43//!     Ready::notify(()).await.expect("Cannot send Ready");
44//!
45//!     loop {
46//!         tokio::select! {
47//!             _ = close.recv() => {
48//!                 listener.close().await;
49//!                 close.close().await;
50//!                 return;
51//!             }
52//!             _ = listener.accept(|(a, b)| async move {
53//!                 println!("Mul requested with: ({}, {})", a, b);
54//!                 a * b
55//!             }) => {}
56//!         }
57//!     }
58//! }
59//!
60//! #[tokio::main]
61//! async fn main() {
62//!     let mut ready = notification::subscribe::<Ready>()
63//!         .await
64//!         .expect("Ready subscribed twice");
65//!     let sum_join = tokio::spawn(sum_listener());
66//!     let mul_join = tokio::spawn(mul_listener());
67//!     for _ in 0..2 {
68//!         ready.recv().await;
69//!     }
70//!     ready.close().await;
71//!
72//!     let sum = Sum::request((5, 10)).await.expect("Cannot request Sum");
73//!     println!("5 + 10 = {}", sum);
74//!
75//!     let mul = Mul::request((5, 10)).await.expect("Cannot request Mul");
76//!     println!("5 * 10 = {}", mul);
77//!
78//!     Close::notify(()).await;
79//!     sum_join.await.expect("sum_listener panicked");
80//!     mul_join.await.expect("mul_listener panicked");
81//! }
82//! ```
83
84#[macro_use]
85mod common;
86
87pub mod broadcast;
88pub mod notification;
89pub mod request;
90
91/// Declare types for
92/// [Broadcast](crate::broadcast::Broadcast),
93/// [Notification](crate::notification::Notification),
94/// [Request](crate::request::Request)
95///
96/// ## Syntax
97///
98/// `<visibility>? broadcast[<buffer size>] <name>(<payload type>);` \
99/// `<visibility>? notification[<buffer size>] <name>(<payload type>);` \
100/// `<visibility>? request[<buffer size>] <name>(<payload type>) -> <response type>;` \
101///
102/// `<buffer size>` is optional for `notification` & `request` and required for `broadcast`
103///
104///
105/// ## Example
106///
107/// ```rust
108/// intercomm::declare! {
109///    /// B1 broadcast
110///    broadcast[4] B1(i32);
111///    /// B2 broadcast
112///    pub(crate) broadcast[8] B2(i32);
113///    /// B3 broadcast
114///    pub broadcast[16] B3(i32);
115///
116///    /// N1 notification
117///    notification N1(i32);
118///    /// N2 notification
119///    pub(crate) notification[1] N2(i32);
120///    /// N3 notification
121///    pub notification[4] N3(i32);
122///
123///    /// R1 request
124///    request R1((i32, i32)) -> i32;
125///    /// R2 request
126///    pub(crate) request[4] R2((i32, i32)) -> i32;
127///    /// R3 request
128///    pub request[4] R3((i32, i32)) -> i32;
129/// }
130/// ```
131#[macro_export]
132macro_rules! declare {
133    () => {};
134
135    (
136        $(#[$attr:meta])*
137        $v:vis broadcast [$buffer_size:expr] $name:ident ($payload:ty);
138        $($next:tt)*
139    ) => {
140        $(#[$attr])*
141        $v struct $name;
142
143        impl $crate::broadcast::Broadcast for $name {
144            type Payload = $payload;
145            const BUFFER_SIZE: usize = $buffer_size;
146            const DEBUG_NAME: &'static str = stringify!($name);
147        }
148
149        impl $name {
150            /// Sends a payload to the Subscription
151            $v async fn notify(payload: $payload) {
152                $crate::broadcast::notify::<$name>(payload).await
153            }
154        }
155
156        $crate::declare!($($next)*);
157    };
158
159    (
160        $(#[$attr:meta])*
161        $v:vis notification $([$buffer_size:expr])? $name:ident ($payload:ty);
162        $($next:tt)*
163    ) => {
164        $(#[$attr])*
165        $v struct $name;
166
167        impl $crate::notification::Notification for $name {
168            type Payload = $payload;
169            const BUFFER_SIZE: usize = $crate::declare!(@buffer-size $($buffer_size)?);
170            const DEBUG_NAME: &'static str = stringify!($name);
171        }
172
173        impl $name {
174            /// Sends a payload to the Subscription
175            $v async fn notify(payload: $payload) -> Result<(), $crate::notification::NotifyError<$name>> {
176                $crate::notification::notify::<$name>(payload).await
177            }
178        }
179
180        $crate::declare!($($next)*);
181    };
182
183    (
184        $(#[$attr:meta])*
185        $v:vis request $([$buffer_size:expr])? $name:ident ($payload:ty) -> $response:ty;
186        $($next:tt)*
187    ) => {
188        $(#[$attr])*
189        $v struct $name;
190
191        impl $crate::request::Request for $name {
192            type Payload = $payload;
193            type Response = $response;
194            const BUFFER_SIZE: usize = $crate::declare!(@buffer-size $($buffer_size)?);
195            const DEBUG_NAME: &'static str = stringify!($name);
196        }
197
198        impl $name {
199            /// Sends a payload to the Listener
200            $v async fn request(payload: $payload) -> Result<$response, $crate::request::RequestError<$name>> {
201                $crate::request::request::<$name>(payload).await
202            }
203        }
204
205        $crate::declare!($($next)*);
206    };
207
208    (@buffer-size) => { 0 };
209    (@buffer-size $buffer_size:expr) => { $buffer_size };
210}