From 81e9ed7fdd65ca4816ac6a76139d6c18d5182a21 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Fri, 21 Jul 2017 11:26:40 +0300 Subject: [core] add ask pattern to actor ref --- include/mbgl/actor/actor_ref.hpp | 21 +++++++++++++++ test/actor/actor_ref.test.cpp | 58 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/include/mbgl/actor/actor_ref.hpp b/include/mbgl/actor/actor_ref.hpp index aeb5bb4507..958ee3777c 100644 --- a/include/mbgl/actor/actor_ref.hpp +++ b/include/mbgl/actor/actor_ref.hpp @@ -35,6 +35,27 @@ public: } } + template + auto ask(Fn fn, Args&&... args) { + // Result type is deduced from the function's return type + using ResultType = typename std::result_of::type; + + std::promise promise; + auto future = promise.get_future(); + + if (auto mailbox = weakMailbox.lock()) { + mailbox->push( + actor::makeMessage( + std::move(promise), *object, fn, std::forward(args)... + ) + ); + } else { + promise.set_exception(std::make_exception_ptr(std::runtime_error("Actor has gone away"))); + } + + return future; + } + private: Object* object; std::weak_ptr weakMailbox; diff --git a/test/actor/actor_ref.test.cpp b/test/actor/actor_ref.test.cpp index 78721c965e..52b0de295b 100644 --- a/test/actor/actor_ref.test.cpp +++ b/test/actor/actor_ref.test.cpp @@ -3,12 +3,9 @@ #include -#include -#include #include using namespace mbgl; -using namespace std::chrono_literals; TEST(ActorRef, CanOutliveActor) { // An ActorRef can outlive its actor. Doing does not extend the actor's lifetime. @@ -40,3 +37,58 @@ TEST(ActorRef, CanOutliveActor) { EXPECT_TRUE(died); test.invoke(&Test::receive); } + +TEST(ActorRef, Ask) { + // Ask returns a Future eventually returning the result + + struct Test { + + Test(ActorRef) {} + + int gimme() { + return 20; + } + + int echo(int i) { + return i; + } + }; + + ThreadPool pool { 1 }; + Actor actor(pool); + ActorRef ref = actor.self(); + + EXPECT_EQ(20, ref.ask(&Test::gimme).get()); + EXPECT_EQ(30, ref.ask(&Test::echo, 30).get()); +} + + +TEST(ActorRef, AskOnDestroyedActor) { + // Tests behavior when calling ask() after the + // Actor has gone away. Should set a exception_ptr. + + struct Test { + bool& died; + + Test(ActorRef, bool& died_) : died(died_) {} + + ~Test() { + died = true; + } + + int receive() { + return 1; + } + }; + bool died = false; + + ThreadPool pool { 1 }; + auto actor = std::make_unique>(pool, died); + ActorRef ref = actor->self(); + + actor.reset(); + EXPECT_TRUE(died); + + auto result = ref.ask(&Test::receive); + EXPECT_ANY_THROW(result.get()); +} -- cgit v1.2.1