messages/handler.rs
1//! In order for an [`Actor`] to be able to process messages,
2//! it should have logic associated with them.
3//!
4//! For that matter, `messages` provides two traits:
5//!
6//! - [`Notifiable`]: handler for notifications, e.g. messages that do not require response.
7//! - [`Handler`]: handler that produces some data as a response to the sent message.
8//!
9//! Note that [`Actor`] can implement both [`Notifiable`] and [`Handler`] traits in case
10//! the calculated data is important for some modules, but not so much for others.
11//!
12//! [`Notifiable`] crate is generally more performant than [`Handler`] since it does not
13//! include overhead to return result back to the original message sender.
14
15use async_trait::async_trait;
16
17use crate::{
18 cfg_runtime,
19 prelude::{Actor, Context},
20};
21
22/// `Notifiable` is an extension trait for [`Actor`] that enables it
23/// to process notifications.
24///
25/// **Note:** Handler workflow guarantees that sent messages will be delivered in
26/// order.
27///
28/// ## Examples
29///
30/// This example assumes that `messages` is used with `rt-tokio` feature enabled.
31///
32/// ```rust
33/// # use messages::prelude::*;
34/// struct Ping;
35///
36/// #[async_trait]
37/// impl Actor for Ping {}
38///
39/// #[async_trait]
40/// impl Notifiable<u8> for Ping {
41/// async fn notify(&mut self, input: u8, context: &Context<Self>) {
42/// println!("Received number {}", input);
43/// }
44/// }
45///
46/// #[tokio::main]
47/// async fn main() {
48/// let mut addr = Ping.spawn();
49/// addr.notify(42).await.unwrap();
50/// # addr.stop().await;
51/// # addr.wait_for_stop().await;
52/// }
53/// ```
54#[async_trait]
55pub trait Notifiable<IN>: Sized + Actor {
56 /// Processes notification.
57 async fn notify(&mut self, input: IN, context: &Context<Self>);
58}
59
60/// `Handler` is an extension trait for [`Actor`] that enables it
61/// to process messages and return results of the message processing.
62///
63/// **Note:** Handler workflow guarantees that sent messages will be delivered in
64/// order.
65///
66/// ## Examples
67///
68/// This example assumes that `messages` is used with `rt-tokio` feature enabled.
69///
70/// ```rust
71/// # use messages::prelude::*;
72/// struct Sum;
73///
74/// #[async_trait]
75/// impl Actor for Sum {}
76///
77/// #[async_trait]
78/// impl Handler<(u8, u8)> for Sum {
79/// type Result = u16;
80///
81/// async fn handle(&mut self, (a, b): (u8, u8), context: &Context<Self>) -> u16 {
82/// (a as u16) + (b as u16)
83/// }
84/// }
85///
86/// #[tokio::main]
87/// async fn main() {
88/// let mut addr = Sum.spawn();
89/// let result = addr.send((22, 20)).await.unwrap();
90/// assert_eq!(result, 42);
91/// # addr.stop().await;
92/// # addr.wait_for_stop().await;
93/// }
94/// ```
95#[async_trait]
96pub trait Handler<IN>: Sized + Actor {
97 /// Result of the message processing.
98 type Result;
99
100 /// Processes a message.
101 async fn handle(&mut self, input: IN, context: &Context<Self>) -> Self::Result;
102}
103
104cfg_runtime! {
105
106/// Alternative to [`Handler`] that allows parallel message processing.
107///
108/// By default, messages for an [`Actor`] are processed sequentially, thus efficiently
109/// will use a single core.
110///
111/// However, in some cases it makes more sense to allow parallel processing, if it's some
112/// kind of caluclation or an access to a shared resource.
113///
114/// ## Examples
115///
116/// This example assumes that `messages` is used with `rt-tokio` feature enabled.
117///
118/// ```rust
119/// # use messages::prelude::*;
120/// #[derive(Clone)]
121/// struct Sum;
122///
123/// #[async_trait]
124/// impl Actor for Sum {}
125///
126/// #[async_trait]
127/// impl Coroutine<(u8, u8)> for Sum {
128/// type Result = u16;
129///
130/// // Note that in this impl the first argument is `self` rather than `&mut self`
131/// // and there is no `Context` argument.
132/// async fn calculate(self, (a, b): (u8, u8)) -> u16 {
133/// (a as u16) + (b as u16)
134/// }
135/// }
136///
137/// #[tokio::main]
138/// async fn main() {
139/// let mut addr = Sum.spawn();
140/// let result = addr.calculate((22, 20)).await.unwrap();
141/// assert_eq!(result, 42);
142/// # addr.stop().await;
143/// # addr.wait_for_stop().await;
144/// }
145/// ```
146#[async_trait]
147pub trait Coroutine<IN>: Sized + Actor + Clone {
148 /// Result of the message processing.
149 type Result;
150
151 /// Processes a message.
152 async fn calculate(self, input: IN) -> Self::Result;
153}
154}