1 #pragma once
2 
3 #include <mbgl/actor/mailbox.hpp>
4 #include <mbgl/actor/message.hpp>
5 
6 #include <memory>
7 
8 namespace mbgl {
9 
10 /*
11     An `ActorRef<O>` is a *non*-owning, weak reference to an actor of type `O`. You can send it
12     messages just like an `Actor<O>`. It's a value object: safe to copy and pass between actors
13     via messages.
14 
15     An `ActorRef<O>` does not extend the lifetime of the corresponding `Actor<O>`. That's determined
16     entirely by whichever object owns the `Actor<O>` -- the actor's "supervisor".
17 
18     It's safe for a `Ref` to outlive its `Actor` -- the reference is "weak", and does not extend
19     the lifetime of the owning Actor, and sending a message to a `Ref` whose `Actor` has died is
20     a no-op. (In the future, a dead-letters queue or log may be implemented.)
21 */
22 
23 template <class Object>
24 class ActorRef {
25 public:
ActorRef(Object & object_,std::weak_ptr<Mailbox> weakMailbox_)26     ActorRef(Object& object_, std::weak_ptr<Mailbox> weakMailbox_)
27         : object(&object_),
28           weakMailbox(std::move(weakMailbox_)) {
29     }
30 
31     template <typename Fn, class... Args>
invoke(Fn fn,Args &&...args)32     void invoke(Fn fn, Args&&... args) {
33         if (auto mailbox = weakMailbox.lock()) {
34             mailbox->push(actor::makeMessage(*object, fn, std::forward<Args>(args)...));
35         }
36     }
37 
38     template <typename Fn, class... Args>
ask(Fn fn,Args &&...args)39     auto ask(Fn fn, Args&&... args) {
40         // Result type is deduced from the function's return type
41         using ResultType = typename std::result_of<decltype(fn)(Object, Args...)>::type;
42 
43         std::promise<ResultType> promise;
44         auto future = promise.get_future();
45 
46         if (auto mailbox = weakMailbox.lock()) {
47             mailbox->push(
48                     actor::makeMessage(
49                             std::move(promise), *object, fn, std::forward<Args>(args)...
50                     )
51             );
52         } else {
53             promise.set_exception(std::make_exception_ptr(std::runtime_error("Actor has gone away")));
54         }
55 
56         return future;
57     }
58 
59 private:
60     Object* object;
61     std::weak_ptr<Mailbox> weakMailbox;
62 };
63 
64 } // namespace mbgl
65