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; } }