1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #pragma once
8 
9 #include "td/actor/actor.h"
10 #include "td/actor/PromiseFuture.h"
11 
12 #include "td/utils/common.h"
13 #include "td/utils/Status.h"
14 
15 namespace td {
16 
17 class MultiPromiseInterface {
18  public:
19   virtual void add_promise(Promise<> &&promise) = 0;
20   virtual Promise<> get_promise() = 0;
21 
22   virtual size_t promise_count() const = 0;
23   virtual void set_ignore_errors(bool ignore_errors) = 0;
24 
25   MultiPromiseInterface() = default;
26   MultiPromiseInterface(const MultiPromiseInterface &) = delete;
27   MultiPromiseInterface &operator=(const MultiPromiseInterface &) = delete;
28   MultiPromiseInterface(MultiPromiseInterface &&) = default;
29   MultiPromiseInterface &operator=(MultiPromiseInterface &&) = default;
30   virtual ~MultiPromiseInterface() = default;
31 };
32 
33 class MultiPromise final : public MultiPromiseInterface {
34  public:
add_promise(Promise<> && promise)35   void add_promise(Promise<> &&promise) final {
36     impl_->add_promise(std::move(promise));
37   }
get_promise()38   Promise<> get_promise() final {
39     return impl_->get_promise();
40   }
41 
promise_count()42   size_t promise_count() const final {
43     return impl_->promise_count();
44   }
set_ignore_errors(bool ignore_errors)45   void set_ignore_errors(bool ignore_errors) final {
46     impl_->set_ignore_errors(ignore_errors);
47   }
48 
49   MultiPromise() = default;
MultiPromise(unique_ptr<MultiPromiseInterface> impl)50   explicit MultiPromise(unique_ptr<MultiPromiseInterface> impl) : impl_(std::move(impl)) {
51   }
52 
53  private:
54   unique_ptr<MultiPromiseInterface> impl_;
55 };
56 
57 class MultiPromiseActor final
58     : public Actor
59     , public MultiPromiseInterface {
60  public:
MultiPromiseActor(string name)61   explicit MultiPromiseActor(string name) : name_(std::move(name)) {
62   }
63 
64   void add_promise(Promise<Unit> &&promise) final;
65 
66   Promise<Unit> get_promise() final;
67 
68   void set_ignore_errors(bool ignore_errors) final;
69 
70   size_t promise_count() const final;
71 
72  private:
73   void set_result(Result<Unit> &&result);
74 
75   string name_;
76   vector<Promise<Unit>> promises_;     // promises waiting for result
77   vector<FutureActor<Unit>> futures_;  // futures waiting for result of the queries
78   size_t received_results_ = 0;
79   bool ignore_errors_ = false;
80   Result<Unit> result_;
81 
82   void raw_event(const Event::Raw &event) final;
83 
84   void tear_down() final;
85 
on_start_migrate(int32)86   void on_start_migrate(int32) final {
87     UNREACHABLE();
88   }
on_finish_migrate()89   void on_finish_migrate() final {
90     UNREACHABLE();
91   }
92 };
93 
94 template <>
95 class ActorTraits<MultiPromiseActor> {
96  public:
97   static constexpr bool need_context = false;
98   static constexpr bool need_start_up = true;
99 };
100 
101 class MultiPromiseActorSafe final : public MultiPromiseInterface {
102  public:
103   void add_promise(Promise<Unit> &&promise) final;
104   Promise<Unit> get_promise() final;
105   void set_ignore_errors(bool ignore_errors) final;
106   size_t promise_count() const final;
MultiPromiseActorSafe(string name)107   explicit MultiPromiseActorSafe(string name) : multi_promise_(td::make_unique<MultiPromiseActor>(std::move(name))) {
108   }
109   MultiPromiseActorSafe(const MultiPromiseActorSafe &other) = delete;
110   MultiPromiseActorSafe &operator=(const MultiPromiseActorSafe &other) = delete;
111   MultiPromiseActorSafe(MultiPromiseActorSafe &&other) = delete;
112   MultiPromiseActorSafe &operator=(MultiPromiseActorSafe &&other) = delete;
113   ~MultiPromiseActorSafe() final;
114 
115  private:
116   unique_ptr<MultiPromiseActor> multi_promise_;
117 };
118 
119 }  // namespace td
120