ghost_actor
A simple, ergonomic, idiomatic, macro for generating the boilerplate to use rust futures tasks in a concurrent actor style.
Hello World Example
// Most of the GhostActor magic happens in this macro.
// Sender and Handler traits will be generated here.
ghost_actor!
// ... We'll skip implementing a handler for now ...
async
What's going on Here?
- The
ghost_actor!
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_actor!
Macro
ghost_actor!
The ghost_actor!
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_actor!
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 HelloWorldActor
from above as an example:
HelloWorldActorSender
- The "Sender" trait generated for your actor allows users with aGhostSender<HelloWorldActor>
instance to make async calls. Basically, this "Sender" trait provides the API that makes the whole actor system work.HelloWorldActorHandler
- This "Handler" trait is what allows you to implement an actor task that can respond to requests sent by the "Sender".HelloWorldActor
- You may have noticed above, the "Sender" instance that users of your api will receive is typed asGhostSender<HelloWorldActor>
. The item that receives the name of your actor without having anything pasted on to it is actually aGhostEvent
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
// We need a struct to implement our handler upon.
;
// All handlers must implement GhostControlHandler.
// This provides a default no-op handle_ghost_actor_shutdown impl.
// Implement GhostHandler for your specific GhostEvent type.
// Don't worry, the compiler will let you know if you forget this : )
// Now implement your actual handler -
// auto generated by the `ghost_event!` macro.
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
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
// Most of the GhostActor magic happens in this macro.
// Sender and Handler traits will be generated here.
ghost_actor!
// We need a struct to implement our handler upon.
;
// All handlers must implement GhostControlHandler.
// This provides a default no-op handle_ghost_actor_shutdown impl.
// Implement GhostHandler for your specific GhostEvent type.
// Don't worry, the compiler will let you know if you forget this : )
// Now implement your actual handler -
// auto generated by the `ghost_event!` macro.
async