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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
#![deny(warnings)]
#![deny(missing_docs)]
#![allow(clippy::needless_doctest_main)]
#![cfg_attr(feature = "unstable", feature(fn_traits))]
#![cfg_attr(feature = "unstable", feature(unboxed_closures))]
//! A simple, ergonomic, idiomatic, macro for generating the boilerplate
//! to use rust futures tasks in a concurrent actor style.
//!
//! ## Hello World Example
//!
//! ```rust
//! # use ghost_actor::*;
//! // Most of the GhostActor magic happens in this macro.
//! // Sender and Handler traits will be generated here.
//! ghost_chan! {
//!     pub chan HelloWorldApi<GhostError> {
//!         fn hello_world() -> String;
//!     }
//! }
//!
//! // ... We'll skip implementing a handler for now ...
//! # struct HelloWorldImpl;
//! # impl GhostControlHandler for HelloWorldImpl {}
//! # impl GhostHandler<HelloWorldApi> for HelloWorldImpl {}
//! # impl HelloWorldApiHandler for HelloWorldImpl {
//! #     fn handle_hello_world(
//! #         &mut self,
//! #     ) -> HelloWorldApiHandlerResult<String> {
//! #         Ok(must_future::MustBoxFuture::new(async move {
//! #             Ok("hello world!".to_string())
//! #         }))
//! #     }
//! # }
//! # pub async fn spawn_hello_world(
//! # ) -> Result<GhostSender<HelloWorldApi>, GhostError> {
//! #     let builder = actor_builder::GhostActorBuilder::new();
//! #     let sender = builder
//! #         .channel_factory()
//! #         .create_channel::<HelloWorldApi>()
//! #         .await?;
//! #     tokio::task::spawn(builder.spawn(HelloWorldImpl));
//! #     Ok(sender)
//! # }
//!
//! #[tokio::main]
//! async fn main() -> Result<(), GhostError> {
//!     // spawn our actor, getting the actor sender.
//!     let sender = spawn_hello_world().await?;
//!
//!     // we can make async calls on the sender
//!     assert_eq!("hello world!", &sender.hello_world().await?);
//!     println!("{}", sender.hello_world().await?);
//!
//!     Ok(())
//! }
//! ```
//!
//! What's going on Here?
//!
//! - The `ghost_chan!` macro writes some types and boilerplate for us.
//! - We'll dig into implementing actor handlers below.
//! - We are able to spawn an actor that runs as a futures task.
//! - We can make async requests on that actor, and get results inline.
//!
//! ## The `ghost_chan!` Macro
//!
//! ```rust
//! # use ghost_actor::*;
//! ghost_chan! {
//!     pub chan HelloWorldApi<GhostError> {
//!         fn hello_world() -> String;
//!     }
//! }
//! # pub fn main() {}
//! ```
//!
//! The `ghost_chan!` macro takes care of writing the boilerplate for using
//! async functions to communicate with an "actor" running as a futures
//! task. The tests/examples here use tokio for the task executor, but
//! the GhostActorBuilder returns a driver future for the actor task that you
//! can manage any way you'd like.
//!
//! The `ghost_chan!` macro generates some important types, many of which
//! are derived by pasting words on to the end of your actor name.
//! We'll use the actor name `HelloWorldApi` from above as an example:
//!
//! - `HelloWorldApiSender` - The "Sender" trait generated for your actor
//!   allows users with a `GhostSender<HelloWorldApi>` instance to make
//!   async calls. Basically, this "Sender" trait provides the API that
//!   makes the whole actor system work.
//! - `HelloWorldApiHandler` - This "Handler" trait is what allows you
//!   to implement an actor task that can respond to requests sent by
//!   the "Sender".
//! - `HelloWorldApi` - You may have noticed above, the "Sender" instance
//!   that users of your api will receive is typed as
//!   `GhostSender<HelloWorldApi>`. The item that receives the name of your
//!   actor without having anything pasted on to it is actually a `GhostEvent`
//!   enum designed for carrying messages from your "Sender" to your
//!   "Handler", and then delivering the result back to your API user.
//!
//! ## Implementing an Actor Handler
//!
//! ```rust
//! # use ghost_actor::*;
//! # ghost_chan! {
//! #     pub chan HelloWorldApi<GhostError> {
//! #         fn hello_world() -> String;
//! #     }
//! # }
//! /// We need a struct to implement our handler upon.
//! struct HelloWorldImpl;
//!
//! /// All handlers must implement GhostControlHandler.
//! /// This provides a default no-op handle_ghost_actor_shutdown impl.
//! impl GhostControlHandler for HelloWorldImpl {}
//!
//! /// Implement GhostHandler for your specific GhostEvent type.
//! /// Don't worry, the compiler will let you know if you forget this : )
//! impl GhostHandler<HelloWorldApi> for HelloWorldImpl {}
//!
//! /// Now implement your actual handler -
//! /// auto generated by the `ghost_chan!` macro.
//! impl HelloWorldApiHandler for HelloWorldImpl {
//!     fn handle_hello_world(&mut self) -> HelloWorldApiHandlerResult<String> {
//!         Ok(must_future::MustBoxFuture::new(async move {
//!             // return our results
//!             Ok("hello world!".to_string())
//!         }))
//!     }
//! }
//! # pub fn main() {}
//! ```
//!
//! Pretty straight forward. We implement a couple required traits,
//! then our "Handler" trait that actually defines the logic of our actor.
//! Then, we're ready to spawn it!
//!
//! ## Spawning an Actor
//!
//! ```rust
//! # use ghost_actor::*;
//! # ghost_chan! {
//! #     pub chan HelloWorldApi<GhostError> {
//! #         fn hello_world() -> String;
//! #     }
//! # }
//! # struct HelloWorldImpl;
//! # impl GhostControlHandler for HelloWorldImpl {}
//! # impl GhostHandler<HelloWorldApi> for HelloWorldImpl {}
//! # impl HelloWorldApiHandler for HelloWorldImpl {
//! #     fn handle_hello_world(
//! #         &mut self,
//! #     ) -> HelloWorldApiHandlerResult<String> {
//! #         Ok(must_future::MustBoxFuture::new(async move {
//! #             Ok("hello world!".to_string())
//! #         }))
//! #     }
//! # }
//! /// Use the GhostActorBuilder to construct the actor task.
//! pub async fn spawn_hello_world(
//! ) -> Result<GhostSender<HelloWorldApi>, GhostError> {
//!     // first we need a builder
//!     let builder = actor_builder::GhostActorBuilder::new();
//!
//!     // now let's register an event channel with this actor.
//!     let sender = builder
//!         .channel_factory()
//!         .create_channel::<HelloWorldApi>()
//!         .await?;
//!
//!     // actually spawn the actor driver task
//!     // providing our implementation
//!     tokio::task::spawn(builder.spawn(HelloWorldImpl));
//!
//!     // return the sender that controls the actor
//!     Ok(sender)
//! }
//! # pub fn main() {}
//! ```
//!
//! Note how we actually get access to the cheaply-clonable "Sender"
//! before we have to construct our actor "Handler" item. This means
//! you can create channels that will be able to message the actor,
//! and include those senders in your handler struct. More on this later.
//!
//! ## The Complete Hello World Example
//!
//! - [https://github.com/holochain/ghost_actor/blob/master/crates/ghost_actor/examples/hello_world.rs](https://github.com/holochain/ghost_actor/blob/master/crates/ghost_actor/examples/hello_world.rs)
//!
//! ## Custom Errors
//!
//! A single ghost channel / actor api will use a single error / result type.
//! You can use the provided `ghost_actor::GhostError` type - or you can
//! specify a custom error type.
//!
//! Your custom error type must support `From<GhostError>`.
//!
//! ```rust
//! # use ghost_actor::*;
//! #[derive(Debug, thiserror::Error)]
//! pub enum MyError {
//!     /// Custom error types MUST implement `From<GhostError>`
//!     #[error(transparent)]
//!     GhostError(#[from] GhostError),
//!
//!     /// Of course, you can also have your own variants as well
//!     #[error("My Error Type")]
//!     MyErrorType,
//! }
//!
//! ghost_chan! {
//!     /// The error type for actor apis is specified in the macro
//!     /// as the single generic following the actor name:
//!     pub chan MyActor<MyError> {
//!         fn my_fn() -> ();
//!     }
//! }
//! # pub fn main() {}
//! ```
//!
//! ## Efficiency! - Ghost Actor's Synchronous Handler Blocks
//!
//! GhostActor handler traits are carefully costructed to allow `&'a mut self`
//! access to the handler item, but return a `'static` future. That `'static`
//! means references to the handler item cannot be captured in any async code.
//!
//! This can be frustrating for new users, but serves a specific purpose!
//!
//! We are being good rust futures authors and working around any blocking
//! code in the manner our executor frameworks recommend, so our actor
//! handler can process messages at lightning speed!
//!
//! Our actor doesn't have to context switch, because it has all its mutable
//! internal state right here in this thread handling all these messages. And,
//! when it's done with one message, it moves right onto the next without
//! interuption. When the message queue is drained it schedules a wakeup for
//! when there is more data to process.
//!
//! In writing our code to support this pattern, we find that our code natually
//! tends toward patterns that support parallel work being done to make better
//! use of modern multi-core processors.
//!
//! See especially the "Internal Sender Pattern" in the next section below.
//!
//! ## Advanced Patterns for Working with Ghost Actors
//!
//! - [Internal Sender Pattern](https://github.com/holochain/ghost_actor/blob/master/crates/ghost_actor/examples/pattern_internal_sender.rs) -
//!   Facilitates undertaking async work in GhostActor handler functions.
//! - [Event Publish/Subscribe Pattern](https://github.com/holochain/ghost_actor/blob/master/crates/ghost_actor/examples/pattern_event_pub_sub.rs) -
//!   Facilitates an actor's ability to async emit notifications/requests,
//!   and a "parent" actor being able to handle events from a child actor.
//! - [Clone Channel Factory Pattern](https://github.com/holochain/ghost_actor/blob/master/crates/ghost_actor/examples/pattern_clone_channel_factory.rs) -
//!   Facilitates an actor's ability to absorb additional channel
//!   receivers post-spawn.

/// Re-exported dependencies to help with macro references.
pub mod dependencies {
    pub use futures;
    pub use must_future;
    pub use paste;
    pub use thiserror;
    pub use tracing;
}

mod types;
pub use types::*;

mod chan_macro;
pub use chan_macro::*;

pub mod actor_builder;

mod tests;