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}