Patrick Kelley 8fd444092b initial
2025-05-07 15:35:15 -04:00

146 lines
4.1 KiB
C++

/******************************************************************************\
* This example is a very basic, non-interactive math service implemented *
* for both the blocking and the event-based API. *
\******************************************************************************/
#include <iostream>
#include "caf/all.hpp"
using std::endl;
using namespace caf;
namespace {
// --(rst-calculator-actor-begin)--
using calculator_actor
= typed_actor<result<int32_t>(add_atom, int32_t, int32_t),
result<int32_t>(sub_atom, int32_t, int32_t)>;
// --(rst-calculator-actor-end)--
// --(rst-prototypes-begin)--
behavior calculator_fun(event_based_actor* self);
void blocking_calculator_fun(blocking_actor* self);
calculator_actor::behavior_type typed_calculator_fun();
class calculator;
class blocking_calculator;
class typed_calculator;
// --(rst-prototypes-end)--
// --(rst-function-based-begin)--
// function-based, dynamically typed, event-based API
behavior calculator_fun(event_based_actor*) {
return {
[](add_atom, int32_t a, int32_t b) { return a + b; },
[](sub_atom, int32_t a, int32_t b) { return a - b; },
};
}
// function-based, dynamically typed, blocking API
void blocking_calculator_fun(blocking_actor* self) {
bool running = true;
self->receive_while(running)( //
[](add_atom, int32_t a, int32_t b) { return a + b; },
[](sub_atom, int32_t a, int32_t b) { return a - b; },
[&](exit_msg& em) {
if (em.reason) {
self->fail_state(std::move(em.reason));
running = false;
}
});
}
// function-based, statically typed, event-based API
calculator_actor::behavior_type typed_calculator_fun() {
return {
[](add_atom, int32_t a, int32_t b) { return a + b; },
[](sub_atom, int32_t a, int32_t b) { return a - b; },
};
}
// --(rst-function-based-end)--
// --(rst-class-based-begin)--
// class-based, dynamically typed, event-based API
class calculator : public event_based_actor {
public:
calculator(actor_config& cfg) : event_based_actor(cfg) {
// nop
}
behavior make_behavior() override {
return calculator_fun(this);
}
};
// class-based, dynamically typed, blocking API
class blocking_calculator : public blocking_actor {
public:
blocking_calculator(actor_config& cfg) : blocking_actor(cfg) {
// nop
}
void act() override {
blocking_calculator_fun(this);
}
};
// class-based, statically typed, event-based API
class typed_calculator : public calculator_actor::base {
public:
typed_calculator(actor_config& cfg) : calculator_actor::base(cfg) {
// nop
}
behavior_type make_behavior() override {
return typed_calculator_fun();
}
};
// --(rst-class-based-end)--
void tester(scoped_actor&) {
// end of recursion
}
// tests a calculator instance
template <class Handle, class... Ts>
void tester(scoped_actor& self, const Handle& hdl, int32_t x, int32_t y,
Ts&&... xs) {
auto handle_err = [&](const error& err) {
aout(self) << "AUT (actor under test) failed: " << to_string(err) << endl;
};
// first test: x + y = z
self->request(hdl, infinite, add_atom_v, x, y)
.receive(
[&](int32_t res1) {
aout(self) << x << " + " << y << " = " << res1 << endl;
// second test: x - y = z
self->request(hdl, infinite, sub_atom_v, x, y)
.receive(
[&](int32_t res2) {
aout(self) << x << " - " << y << " = " << res2 << endl;
},
handle_err);
},
handle_err);
tester(self, std::forward<Ts>(xs)...);
}
void caf_main(actor_system& sys) {
// --(rst-spawn-begin)--
auto a1 = sys.spawn(blocking_calculator_fun);
auto a2 = sys.spawn(calculator_fun);
auto a3 = sys.spawn(typed_calculator_fun);
auto a4 = sys.spawn<blocking_calculator>();
auto a5 = sys.spawn<calculator>();
auto a6 = sys.spawn<typed_calculator>();
// --(rst-spawn-end)--
scoped_actor self{sys};
tester(self, a1, 1, 2, a2, 3, 4, a3, 5, 6, a4, 7, 8, a5, 9, 10, a6, 11, 12);
self->send_exit(a1, exit_reason::user_shutdown);
self->send_exit(a4, exit_reason::user_shutdown);
}
} // namespace
CAF_MAIN()