| 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: |
| 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> |
| 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> |
| 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(ex: 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 | |