1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! In order for an [`Actor`] to be able to process messages,
//! it should have logic associated with them.
//!
//! For that matter, `messages` provides two traits:
//!
//! - [`Notifiable`]: handler for notifications, e.g. messages that do not require response.
//! - [`Handler`]: handler that produces some data as a response to the sent message.
//!
//! Note that [`Actor`] can implement both [`Notifiable`] and [`Handler`] traits in case
//! the calculated data is important for some modules, but not so much for others.
//!
//! [`Notifiable`] crate is generally more performant than [`Handler`] since it does not
//! include overhead to return result back to the original message sender.

use async_trait::async_trait;

use crate::{
    cfg_runtime,
    prelude::{Actor, Context},
};

/// `Notifiable` is an extension trait for [`Actor`] that enables it
/// to process notifications.
///
/// **Note:** Handler workflow guarantees that sent messages will be delivered in
/// order.
///
/// ## Examples
///
/// This example assumes that `messages` is used with `rt-tokio` feature enabled.
///
/// ```rust
/// # use messages::prelude::*;
/// struct Ping;
///
/// #[async_trait]
/// impl Actor for Ping {}
///
/// #[async_trait]
/// impl Notifiable<u8> for Ping {
///     async fn notify(&mut self, input: u8, context: &Context<Self>) {
///         println!("Received number {}", input);
///     }
/// }
///
/// #[tokio::main]
/// async fn main() {
///    let mut addr = Ping.spawn();
///    addr.notify(42).await.unwrap();
///    # addr.stop().await;
///    # addr.wait_for_stop().await;  
/// }
/// ```
#[async_trait]
pub trait Notifiable<IN>: Sized + Actor {
    /// Processes notification.
    async fn notify(&mut self, input: IN, context: &Context<Self>);
}

/// `Handler` is an extension trait for [`Actor`] that enables it
/// to process messages and return results of the message processing.
///
/// **Note:** Handler workflow guarantees that sent messages will be delivered in
/// order.
///
/// ## Examples
///
/// This example assumes that `messages` is used with `rt-tokio` feature enabled.
///
/// ```rust
/// # use messages::prelude::*;
/// struct Sum;
///
/// #[async_trait]
/// impl Actor for Sum {}
///
/// #[async_trait]
/// impl Handler<(u8, u8)> for Sum {
///     type Result = u16;
///
///     async fn handle(&mut self, (a, b): (u8, u8), context: &Context<Self>) -> u16 {
///         (a as u16) + (b as u16)
///     }
/// }
///
/// #[tokio::main]
/// async fn main() {
///    let mut addr = Sum.spawn();
///    let result = addr.send((22, 20)).await.unwrap();
///    assert_eq!(result, 42);
///    # addr.stop().await;
///    # addr.wait_for_stop().await;  
/// }
/// ```
#[async_trait]
pub trait Handler<IN>: Sized + Actor {
    /// Result of the message processing.
    type Result;

    /// Processes a message.
    async fn handle(&mut self, input: IN, context: &Context<Self>) -> Self::Result;
}

cfg_runtime! {

/// Alternative to [`Handler`] that allows parallel message processing.
///
/// By default, messages for an [`Actor`] are processed sequentially, thus efficiently
/// will use a single core.
///
/// However, in some cases it makes more sense to allow parallel processing, if it's some
/// kind of caluclation or an access to a shared resource.
///
/// ## Examples
///
/// This example assumes that `messages` is used with `rt-tokio` feature enabled.
///
/// ```rust
/// # use messages::prelude::*;
/// #[derive(Clone)]
/// struct Sum;
///
/// #[async_trait]
/// impl Actor for Sum {}
///
/// #[async_trait]
/// impl Coroutine<(u8, u8)> for Sum {
///     type Result = u16;
///
///     // Note that in this impl the first argument is `self` rather than `&mut self`
///     // and there is no `Context` argument.
///     async fn calculate(self, (a, b): (u8, u8)) -> u16 {
///         (a as u16) + (b as u16)
///     }
/// }
///
/// #[tokio::main]
/// async fn main() {
///    let mut addr = Sum.spawn();
///    let result = addr.calculate((22, 20)).await.unwrap();
///    assert_eq!(result, 42);
///    # addr.stop().await;
///    # addr.wait_for_stop().await;
/// }
/// ```
#[async_trait]
pub trait Coroutine<IN>: Sized + Actor + Clone {
    /// Result of the message processing.
    type Result;

    /// Processes a message.
    async fn calculate(self, input: IN) -> Self::Result;
}
}