busan/actor/
mod.rs

1//! Actor trait and related types necessary for basic actor functionality.
2//!
3//! The [`actor`](crate::actor) module contains the necessary core components when writing
4//! an `Actor` implementation and deals with construction, message sending and receiving, and
5//! various lifecycle hooks.
6//!
7//! ## Actor Construction
8//!
9//! Construction of an actor looks different than how types are normally constructed in Rust. This
10//! is because actors, in order to satisfy certain properties of the actor model, must be isolated.
11//! That is, no state can be shared across the boundary of an actor. To satisfy this, construction
12//! looks like the following:
13//!
14//!   + The constructor is defined within the [`ActorInit`] trait
15//!   + Construction is defined as taking a `[`Message`](crate::message::Message) and returning
16//!     an [`Actor`] instance
17//!   + Construction is performed indirectly through either
18//!     [`ActorSystem::spawn_root_actor`](crate::ActorSystem::spawn_root_actor) or
19//!     [`Context::spawn_child`]
20//!
21//! With this construction, isolation is satisfied by:
22//!   + Instances of actors are only available internally to the actor system while user code
23//!     interacts with actors through [`ActorAddress`] handles.
24//!   + Construction properties can be serialized which ensures no internal state is accidentally
25//!     shared
26//!
27//! ## Actor Implementation
28//!
29//! Actors in busan are currently very simple. They can receive messages and, using the context,
30//! send messages or spawn other actors. There are currently no limitations on the type of internal
31//! state an actor can have other `Actor`s must be `Send`'able (which allows for scheduling across
32//! executors).
33//!
34//! ## Example
35//!
36//! ```rust
37//! use busan::message::common_types::StringWrapper;
38//! use busan::prelude::*;
39//!
40//! #[derive(Clone, PartialEq, prost::Message, busan::Message)]
41//! struct GreeterInit {
42//!   #[prost(string, tag = "1")]
43//!   phrase: String,
44//! }
45//!
46//! struct Greeter {
47//!   phrase: String,
48//!   greet_count: u32,
49//! }
50//!
51//! impl ActorInit for Greeter {
52//!   type Init = GreeterInit;
53//!   fn init(init_msg: &Self::Init) -> Self {
54//!     let mut phrase = init_msg.phrase.clone();
55//!     if phrase.is_empty() {
56//!       phrase = "Hello".to_string();
57//!     }
58//!     Self { phrase, greet_count: 0 }
59//!   }
60//! }
61//!
62//! impl Actor for Greeter {
63//!   fn receive(&mut self, ctx: Context, msg: Box<dyn Message>) {
64//!     if let Some(greet_msg) = msg.as_any().downcast_ref::<StringWrapper>() {
65//!       println!("{} {} (greetings: {})", self.phrase, greet_msg.value, self.greet_count);
66//!       self.greet_count += 1;
67//!     }
68//!   }
69//! }
70//! ```
71//! The example uses a protobuf message type for demonstration, but there are a couple of things to
72//! note:
73//!   + Protobuf types can be generated using a build-script
74//!   + Basic type-wrappers already exist for common values, so we could have used
75//!     [`StringWrapper`](crate::message::common_types::StringWrapper) instead of defining our own
76//!     protobuf message
77//!
78//! <!-- TODO: Link to the 'patterns' module when it exists -->
79
80// Allow this since we're re-exporting everything and just re-using the module name for
81// our own organization of files.
82#![allow(clippy::module_inception)]
83
84// Hide all of the sub-modules. These are broken out for easier organization of the code, but
85// conceptually these all belong in the same module and are re-exported here.
86#[doc(hidden)]
87pub mod actor;
88#[doc(hidden)]
89pub mod address;
90#[doc(hidden)]
91pub mod letter;
92
93#[doc(inline)]
94pub use actor::*;
95#[doc(inline)]
96pub use address::*;
97
98pub(crate) use letter::*;
99pub(crate) type Mailbox = crossbeam_channel::Sender<Letter>;