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
//! # act-zero-macro
//!
//! Procedural macros for the `act-zero` crate.
use TokenStream;
use TokenStream as TokenStream2;
/// # The `#[act_zero]` macro.
///
/// This macro is used in two locations, which will be documented separately:
///
/// ## Trait position
///
/// ```nocompile
/// #[act_zero]
/// trait Greeter {
/// fn greet(&self, name: String, res: Sender<String>);
/// }
/// ```
///
/// This is used to define an *actor trait*. Actor traits (much like normal traits) define a
/// set of methods to be implemented by the actor type. However, there are a number of
/// constraints:
/// - Methods must take `&self` as the receiver.
/// - All argument types must be `Send + 'static`.
/// - Generic methods must have a `where Self: Sized` bound.
/// - There must be no return type.
/// - If the last argument is named `res`, it must be of type `Sender<_>`.
///
/// These last two constraints are related: actor systems work by passing messages and
/// processing them asynchronously. Any return value would not be immediately available,
/// so instead the caller passes in a `Sender<_>` to receive the result.
///
/// As a convenience, there will be an asynchronous `call_xyz()` method to hide this
/// complexity from the caller:
/// ```nocompile
/// let addr: Addr<dyn Greeter> = ...;
/// let res = addr.call_greet("John".into()).await?;
/// ```
///
/// Internally, this macro defines several additional items:
/// - `trait GreeterImpl`
/// You will never use this trait directly, but if you want your trait to be implementable
/// by downstream crates, you must export this trait under the same path as the actor trait
/// itself.
/// - `enum GreeterMsg`
/// This enum contains a variant for each object-safe method in the trait. It is used in
/// remoting scenarios when messages may need to be trasferred between processes or over
/// the network, but is otherwise not used.
/// - `trait GreeterExt`
/// This trait is implemented for the `Addr` and `WeakAddr` types when they contain a type
/// implementing the actor trait. Methods on this trait are the primary way you would
/// interact with the actor, and this is where helper methods like `call_greeter` are
/// defined.
///
/// ## Trait implementation position
///
/// ```nocompile
/// #[act_zero]
/// impl Greeter for SimpleGreeter {
/// async fn greet(&mut self, name: String, res: Sender<String>) {
/// self.number_of_greets += 1;
/// res.send(format!(
/// "Hello, {}. You are number {}!",
/// name, self.number_of_greets
/// ))
/// .ok();
/// }
/// }
/// ```
///
/// This is used to implement an actor trait for an actor. The signature of the methods
/// in the implementation differ substantially from those signature in the trait definition:
///
/// - All methods must be `async`. This may be optional in future.
/// - Methods can return any type implementing `IntoResult`. If an error variant is returned
/// it will be passed to the appropriate error handler implemented for the actor.
/// - The receiver type can be any of:
///
/// 1) `&mut self`
/// The method will run to completion with exclusive access to the actor state.
/// No methods taking `&self` or `&mut self` can run concurrently. Long running
/// methods taking `&mut self` should be avoided if you want your actor to stay
/// responsive to new messages.
///
/// 2) `&self`
/// The method will run to completion with shared access to the actor state.
/// Other methods taking `&self` can run concurrently, but methods taking
/// `&mut self` cannot.
///
/// 3) `self: Addr<Local<Self>>`
/// The method has no direct access to the actor state, but can run concurrently
/// with any other methods, including those taking `&mut self`. This can be useful
/// for implementing delayed or timed events without blocking the actor.
/// Access to the actor state can be achieved by awaiting another method on the
/// actor to do the update.
///
/// No additional items are generated by the expansion of this variant of the macro.