pong.cpp

This example shows how to implement actors and send messages between them.

Output of this example:

Ping: Message(GameBall(hits = 0))
Pong: Message(GameBall(hits = 1))
Ping: Message(GameBall(hits = 2))
Pong: Message(GameBall(hits = 3))
Ping: Message(GameBall(hits = 4))
Pong: Message(GameBall(hits = 5))
Ping: Message(GameBall(hits = 6))
Pong: Message(GameBall(hits = 7))
Ping: Message(GameBall(hits = 8))
Pong: Message(GameBall(hits = 9))
Ping: Message(GameBall(hits = 10))

pong.hpp:

// acedia includes
#include "acedia/actor.hpp"
#include "acedia/invoker.hpp"

// other includes
#include <iostream>
#include <boost/cstdint.hpp>

typedef boost::int32_t i32;

// the ball that's sended between Ping and Pong
ACEDIA_DECLARE_CASE_TUPLE1((GameBall), hits, i32)

class Ping : public acedia::Actor
{

    void returnPass(i32 hits)
    {
        // lastReceivedMessage() returns the current processed
        // message in 'original' form which then is converted to
        // a string and printed to stdout
        std::cout << "Ping: "
                  << lastReceivedMessage().toString().const_str()
                  << std::endl;

        // inrement the hit counter and pass the ball back to Pong
        reply(GameBall(hits+1));
    }

public:

    // this is the only method you must override in your own actor class
    virtual void act()
    {
        using acedia::on;

        acedia::Invoker i;

        // Step by step:
        // on<GameBall>() => declares a pattern that matches instances
        //                   of GameBall
        // .unbox()       => unboxing a tuple means: throw away the tuple
        //                   and handle the elements; in this case
        //                   all further operations see only a i32
        // >>             => if the left hand rule does match then invoke
        //                   the following callback
        // method(...)    => declare a callback that invokes a member method
        i.add(on<GameBall>().unbox() >> method(&Ping::returnPass));

        // call receiveAndInvoke until the actor dies
        for (;;) receiveAndInvoke(i);
    }

};

class Pong : public acedia::Actor
{

    acedia::ActorRef ping;

    void returnPass(i32 hits)
    {
        std::cout << "Pong: "
                  << lastReceivedMessage().toString().const_str()
                  << std::endl;
        reply(GameBall(hits+1));
    }

    void die()
    {
        // do exit with a non-normal reason
        // a non-normal exit reason will cause all links to exit too
        // in this case Ping will die because it's linked with Pong and Pong
        // dies with USER_DEFINED_REASON (and not with NORMAL_EXIT)
        doExit(acedia::exit_reasons::USER_DEFINED_REASON);
    }

public:

    Pong(acedia::ActorRef myPing) : ping(myPing) { }

    virtual void act()
    {
        using acedia::on;
        using acedia::isGt;

        // kickoff
        send(ping, GameBall(0));

        acedia::Invoker i;

        i
         // on a GameBall message unbox it and check the guard isGt(9)
         // which returns true if GameBall::hits() > 9
         .add(on<GameBall>().unbox().guard(isGt((i32) 9))

              // invoke Pong::die if the patter does match
              // note that die does not take any arguments but is a valid
              // invoke target because you can ignore any number of
              // message elements
              //
              // e.g.:
              // you receive a message <int, string, float, double>
              // valid callback signatures are:
              // (int, string, float, double)
              // (string, float, double)
              // (float, double)
              // (double)
              // ()
              >> method(&Pong::die))

         // the second rule is only checked if the first rule did not match
         .add(on<GameBall>().unbox() >> method(&Pong::returnPass))
        ;

        for (;;) receiveAndInvoke(i);
    }

};
#include "pong.hpp"

int main(int, char**)
{
    using namespace acedia;
    // spawn ping
    ActorRef ping = spawn<Ping>();
    // spawn pong as a link of ping to enforce ping to exit if pong dies
    link(ping, spawn<Pong>(ping));
    // wait until ping and pong are done
    waitForAllActorsDone();
    // quit acedia
    shutdown();
    return 0;
}

Generated by  doxygen 1.6.2