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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#![warn(missing_debug_implementations, unreachable_pub)]
#![deny(unused_must_use)]
//! An intuitive actor model for Rust with minimal boilerplate, no manual messages and typed arguments.
//!
//! **Note that this crate is under construction. Although used in production, work is done on making an intuitive API, documententation and remaining features. Pre 1.0 the API may break at any time!**
//!
//! Actify is an actor model built on [Tokio][tokio] that allows annotating any regular implementation block of your own type with the actify! macro.
//! By generating the boilerplate code for you, a few key benefits are provided:
//!
//! * Async actor model build on Tokio and channels
//! * Access to actors through clonable handles
//! * Types arguments on the methods from your actor, exposed through the handle
//! * No need to define message structs or enums!
//!
//! [tokio]: https://docs.rs/tokio/latest/tokio/
//!
//! # Main functionality of actify!
//!
//! Consider the following example, in which you want to turn your custom Greeter into an actor:
//! ```
//! # use actify::{Handle, actify};
//! # use std::fmt::Debug;
//! # #[derive(Clone, Debug)]
//! # struct Greeter {}
//! #[actify]
//! impl Greeter {
//!     fn say_hi(&self, name: String) -> String {
//!         format!("hi {}", name)
//!     }
//! }
//!
//! #[tokio::main]
//! async fn main() {
//!     // An actify handle is created and initialized with the Greeter struct
//!     let handle = Handle::new(Greeter {});
//!
//!     // The say_hi method is made available on its handle through the actify! macro
//!     let greeting = handle.say_hi("Alfred".to_string()).await.unwrap();
//!
//!     // The method is executed on the initialized Greeter and returned through the handle
//!     assert_eq!(greeting, "hi Alfred".to_string())
//! }
//! ```
//!
//! This roughly desugars to:
//! ```
//! # use actify::{Handle, actify, ActorError, Actor, FnType};
//! # #[derive(Clone, Debug)]
//! # struct Greeter {}
//! impl Greeter {
//!     fn say_hi(&self, name: String) -> String {
//!         format!("hi {}", name)
//!     }
//! }
//!
//! // Defines the custom function signatures that should be added to the handle
//! #[async_trait::async_trait]
//! pub trait GreeterHandle {
//!     async fn say_hi(&self, name: String) -> Result<String, ActorError>;
//! }
//!
//! // Implements the methods on the handle, and calls the generated method for the actor
//! #[async_trait::async_trait]
//! impl GreeterHandle for Handle<Greeter> {
//!     async fn say_hi(&self, name: String) -> Result<String, ActorError> {
//!         let res = self
//!             .send_job(FnType::Inner(Box::new(GreeterActor::_say_hi)), Box::new(name))
//!             .await?;
//!         Ok(*res.downcast().unwrap())
//!     }
//! }
//!
//! // Defines the wrappers that execute the original methods on the struct in the actor
//! trait GreeterActor {
//!     fn _say_hi(&mut self, args: Box<dyn std::any::Any + Send>) -> Result<Box<dyn std::any::Any + Send>, ActorError>;
//! }
//!
//! // Implements the methods on the actor for this specific type
//! impl GreeterActor for Actor<Greeter>
//! {
//!     fn _say_hi(&mut self, args: Box<dyn std::any::Any + Send>) -> Result<Box<dyn std::any::Any + Send>, ActorError> {
//!         let name: String = *args.downcast().unwrap();
//!
//!         // This call is the actual execution of the method from the user-defined impl block, on the struct held by the actor
//!         let result: String = self.inner.say_hi(name);  
//!         Ok(Box::new(result))
//!     }
//! }
//!
//! #[tokio::main]
//! async fn main() {
//!     let handle = Handle::new(Greeter {});
//!     let greeting = handle.say_hi("Alfred".to_string()).await.unwrap();
//!     assert_eq!(greeting, "hi Alfred".to_string())
//! }
//! ```
//!
//! ## Async functions in impl blocks
//! Async function are fully supported, and work as you would expect:
//! ```
//! # use actify::{Handle, actify};
//! # use std::fmt::Debug;
//! # #[derive(Clone, Debug)]
//! # struct AsyncGreeter {}
//! #[actify]
//! impl AsyncGreeter {
//!     async fn async_hi(&self, name: String) -> String {
//!         format!("hi {}", name)
//!     }
//! }
//!
//! #[tokio::main]
//! async fn main() {
//!     let handle = Handle::new(AsyncGreeter {});
//!     let greeting = handle.async_hi("Alfred".to_string()).await.unwrap();
//!     assert_eq!(greeting, "hi Alfred".to_string())
//! }
//! ```
//!
//! ## Generics in the actor type
//! Generics in the actor type are fully supported, as long as they implement Clone, Debug, Send, Sync and 'static:
//! ```
//! # use actify::{Handle, actify};
//! # use std::fmt::Debug;
//! # #[derive(Clone, Debug)]
//! struct GenericGreeter<T> {
//!     inner: T
//! }
//!
//! #[actify]
//! impl<T> GenericGreeter<T>
//! where
//!     T: Clone + Debug + Send + Sync + 'static,
//! {
//!     async fn generic_hi(&self, name: String) -> String {
//!         format!("hi {} from {:?}", name, self.inner)
//!     }
//! }
//!
//! #[tokio::main]
//! async fn main() {
//!     let handle = Handle::new(GenericGreeter { inner: usize::default() });
//!     let greeting = handle.generic_hi("Alfred".to_string()).await.unwrap();
//!     assert_eq!(greeting, "hi Alfred from 0".to_string())
//! }
//!```
//!
//! ## Generics in the method arguments
//! Unfortunately, passing generics by arguments is not yet supported. It is technically possible, and will be added in the near future.
//! ```compile_fail
//! # use actify::{Handle, actify};
//! # use std::fmt::Debug;
//! # #[derive(Clone, Debug)]
//! # struct Greeter { }
//! #[actify]
//! impl Greeter
//! {
//!     async fn generic_hi<F>(&self, name: String, f: F) -> String
//!     where
//!         F: Debug + Send + Sync,
//!     {
//!         format!("hi {} with {:?}", name, f)
//!     }
//! }
//!```
//!
//! TODO: show temporary workaround with PhantomData in the actor struct
//!
//! ## Passing arguments by reference
//! As referenced arguments cannot be send to the actor, they are forbidden. All arguments must be owned:
//! ```compile_fail
//! # struct MyActor {}
//! #[actify::actify]
//! impl MyActor {
//!     fn foo(&self, forbidden_reference: &usize) {
//!         println!("Hello foo: {}", forbidden_reference);
//!     }
//! }
//! ```
//!
//! ## Standard actor methods
//! TODO: add documentation on the standard actor methods like get and set
//!
//! ## Atomicity
//! TODO: add documentation on how to guarantee atomocity by preventing updating actors with gets and sets
//!
//! ## Preventing cycles
//! TODO: add documentation on how to prevent cycles when actors use eachothers handles

mod actors;
mod cache;
mod extensions;
mod throttle;

// Reexport for easier reference
pub use actify_macros::{actify, skip_broadcast};
pub use actors::ActorError;
pub use actors::{Actor, FnType, Handle};
pub use async_trait::async_trait;
pub use cache::{Cache, CacheRecvError, CacheRecvNewestError};
pub use extensions::{map::HashMapHandle, option::OptionHandle, vec::VecHandle};
pub use throttle::{Frequency, ThrottleBuilder, ThrottleError, Throttled};

#[cfg(feature = "profiler")]
pub use actors::{get_broadcast_counts, get_sorted_broadcast_counts};