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}