# Riker Patterns
## Overview
The patterns crate provides a collection of common patterns used in actor systems.
Currently this only includes the Ask pattern and a behavior change pattern that provides a `transform!` macro.
The intention is to add many patterns, some of which are well documented in popular actor programming books, such as [Reactive Messaging Patterns with the Actor Model](https://www.safaribooksonline.com/library/view/reactive-messaging-patterns/9780133846904/).
## Patterns:
### Ask
The Ask pattern allows values to be sent by actors to outside of the actor system. The value is delivered as a `Future`.
Let's look at how this works:
`Cargo.toml`:
```toml
[dependencies]
riker = "0.3.0"
riker-patterns = "0.3.0"
```
`main.rs`:
```rust
use futures::future::RemoteHandle;
use riker_patterns::ask::*;
struct MyActor;
impl Actor for MyActor {
type Msg = u32;
fn recv(&mut self,
ctx: &Context<Self::Msg>,
msg: Self::Msg,
sender: Sender) {
// sender is the Ask, waiting to a message to be sent back to it
sender.try_tell(msg * 2, Some(ctx.myself().into()));
}
}
fn main() {
let sys = ActorSystem::new().unwrap();
let props = Props::new(Box::new(MyActor::new));
let my_actor = sys.actor_of(props, "my-actor");
// ask returns a future that automatically is driven
// to completion by the system.
let res: RemoteHandle<u32> = ask(&sys, &my_actor, 100);
// the result future can be passed to a library or fuction that
// expects a future, or it can be extracted locally using `block_on`.
let res = block_on(res).unwrap();
println!("The result value is: {}", res);
}
```
In the background Ask sets up a temporary intermediate actor that lives for the lifetime of the ask. Other actors see this temporary actor as the `sender` and can send a message back to it. When the temporary ask actor receives a message it fulfills the outstanding future and performs a `stop` on itself to cleanup.
Ask is particularly useful when you have part of an application that runs outside of the actor system, or in another actor system, such as a web server (e.g. Hyper) serving API requests. The resulting future can then be chained as part of the future stack.
### Transform
Transform makes changing actor behavior based on its current state easier to reason about. Since actors maintain state, and indeed is a primary concern, being able to handle messages differently based on that state is important. The Transform pattern separates message handling by dedicating a receive function per state. This saves excessive `match`ing to handle several possible states, i.e. handling behavior is pre-empted at the time of state change instead of on each message receive.
!!! info
If you're familair with Akka on the JVM, `transform` resembles `become`.
Example:
```rust
#[macro_use]
use riker_patterns::transform::*;
impl ShoppingCart {
// created state
fn created(&mut self,
ctx: &Context<MyMsg>,
msg: MyMsg,
sender: Sender) {
match msg {
MyMsg::AddItem(item) => {
// add item to cart
...
}
MyMsg::Cancel => {
// future messages will be handled by `fn cancelled`
transform!(self, UserActor::cancelled);
}
MyMsg::Checkout => {
// future messages will be handled by `fn checkout`
transform!(self, UserActor::checkout);
}
}
}
// cancelled state
fn cancelled(&mut self,
ctx: &Context<MyMsg>,
msg: MyMsg,
sender: Sender) {
match msg {
MyMsg::AddItem(item) => {
// can't add item to cancelled cart
...
}
MyMsg::Cancel => {
// can't cancel an already cancelled cart
...
}
MyMsg::Checkout => {
// can't checkout out a canclled cart
...
}
}
}
// checkout state
fn checkout(&mut self,
ctx: &Context<MyMsg>,
msg: MyMsg,
sender: Sender) {
match msg {
MyMsg::AddItem(item) => {
// can't add item to cart during checkout
...
}
MyMsg::Cancel => {
// future messages will be handled by `fn cancelled`
transform!(self, UserActor::cancelled);
}
MyMsg::Checkout => {
// cart already in checkout process
...
}
}
}
}
impl Actor for ShoppingCart {
type Msg = MyMsg;
fn recv(&mut self,
ctx: &Context<Self::Msg>,
msg: Self::Msg,
sender: Sender) {
// just call the currently set transform function
(self.rec)(self, ctx, msg, sender)
}
}
```
The `transform!` macro expects the field name of the current receive function on `self` to be named `rec`. It's easy to use a different name and either use your own macro, or just set the fuction using standard code. The advantage of `transform!` is that it is easy to read and identify when transformation is happening since it is distinct from standard code.