libkazv
asio-promise-handler.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of libkazv.
3  * SPDX-FileCopyrightText: 2021 Tusooa Zhu <tusooa@kazv.moe>
4  * SPDX-License-Identifier: AGPL-3.0-or-later
5  */
6 
7 #pragma once
8 
9 #include <boost/asio.hpp>
10 
11 #include <promise-interface.hpp>
12 
13 namespace Kazv
14 {
15  template<class Exec, class T>
16  class AsioPromise;
17 
18  namespace detail
19  {
20  template<class Exec>
21  struct AsioPromiseHelper
22  {
23  template<class T>
24  using PromiseType = AsioPromise<Exec, T>;
25  };
26 
27  struct IdentityFunc
28  {
29  template<class T>
30  constexpr T &&operator()(T &&t) const {
31  return std::forward<T>(t);
32  }
33  };
34  }
35 
36  template<class Exec, class T>
37  class AsioPromise : public AbstractPromise<detail::AsioPromiseHelper<Exec>::template PromiseType, T>
38  {
40 
41  template<class FuncT, class PromiseT, class ResolveT>
42  struct WaitHelper
43  {
44  void wait() const {
45  if (p.ready()) {
46  auto res = func(p.get());
47  using ResT = decltype(res);
48  if constexpr (isPromise<ResT>) {
49  boost::asio::post(
50  executor,
51  [w=WaitHelper<detail::IdentityFunc, ResT, ResolveT>{
52  executor,
53  res,
54  detail::IdentityFunc{},
55  resolve,
56  }]() mutable {
57  w.wait();
58  });
59  } else {
60  resolve(res);
61  }
62  } else {
63  boost::asio::post(
64  executor,
65  [*this]() mutable {
66  wait();
67  }
68  );
69  }
70  }
71 
72  Exec executor;
73  PromiseT p;
74  FuncT func;
75  ResolveT resolve;
76  };
77 
78  struct ResolveHelper
79  {
80  template<class ValT>
81  void operator()(ValT val) const {
82  using ResT = std::decay_t<decltype(val)>;
83  if constexpr (isPromise<ResT>) {
84  auto w = WaitHelper<detail::IdentityFunc, ResT, ResolveHelper>{
85  executor,
86  val,
87  detail::IdentityFunc{},
88  *this
89  };
90  w.wait();
91  } else {
92  p->set_value(std::move(val));
93  }
94  }
95 
96  Exec executor;
97  std::shared_ptr<std::promise<T>> p;
98  };
99  public:
100  AsioPromise(Exec executor, T value)
101  : BaseT(this)
102  , m_executor(std::move(executor)) {
103  std::promise<T> p;
104  m_val = p.get_future().share();
105  p.set_value(std::move(value));
106  }
107 
108  template<class Func>
109  AsioPromise(Exec executor, Func &&callback)
110  : BaseT(this)
111  , m_executor(std::move(executor)) {
112  auto p = std::make_shared<std::promise<T>>();
113  m_val = p->get_future().share();
114  auto resolve = ResolveHelper{m_executor, p};
115 
116  boost::asio::post(
117  m_executor,
118  [=, callback=std::forward<Func>(callback),
119  resolve=std::move(resolve),
120  guard=boost::asio::make_work_guard(m_executor)]() {
121  callback(resolve);
122  });
123  }
124 
125  // FuncT: (DataT) -> AnotherDataT
126  // where AnotherDataT = PromiseThenResult<FuncT, typename BaseT::DataT>
127  template<class FuncT>
128  auto then(FuncT &&func)
129  -> AsioPromise<Exec,
131  return AsioPromise<Exec,
133  m_executor,
134  [=, func=std::forward<FuncT>(func), *this](auto resolve) {
135  auto waitHelper = WaitHelper<std::decay_t<FuncT>,
136  AsioPromise,
137  std::decay_t<decltype(resolve)>>{
138  m_executor,
139  *this,
140  func,
141  resolve
142  };
143  waitHelper.wait();
144  });
145  }
146 
147  bool ready() const {
148  return m_val.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
149  }
150 
151  T get() const {
152  return m_val.get();
153  }
154  private:
155  Exec m_executor;
156  std::shared_future<T> m_val;
157  };
158 
159  template<class Exec>
160  class AsioPromiseHandler : public PromiseInterface<AsioPromiseHandler<Exec>,
161  detail::AsioPromiseHelper<Exec>::template PromiseType>
162  {
164  detail::AsioPromiseHelper<Exec>::template PromiseType>;
165  public:
166  template<class T>
168 
169  AsioPromiseHandler(Exec executor)
170  : BaseT(this)
171  , m_executor(executor)
172  {}
173 
175  : BaseT(this)
176  , m_executor(that.m_executor)
177  {}
178 
180  : BaseT(this)
181  , m_executor(std::move(that.m_executor))
182  {}
183 
185  m_executor = that.m_executor;
186  return *this;
187  }
188 
190  m_executor = std::move(that.m_executor);
191  return *this;
192  }
193 
194  template<class T, class FuncT>
195  PromiseT<T> create(FuncT &&func) {
196  return PromiseT<T>(m_executor, std::forward<FuncT>(func));
197  }
198 
199  template<class T>
201  return PromiseT<T>(m_executor, std::move(val));
202  }
203 
204  private:
205  Exec m_executor;
206  };
207 
208  template<class Exec>
210 }
Definition: promise-interface.hpp:74
Definition: asio-promise-handler.hpp:162
AsioPromiseHandler(Exec executor)
Definition: asio-promise-handler.hpp:169
PromiseT< T > create(FuncT &&func)
Definition: asio-promise-handler.hpp:195
PromiseT< T > createResolved(T val)
Definition: asio-promise-handler.hpp:200
AsioPromiseHandler & operator=(const AsioPromiseHandler &that)
Definition: asio-promise-handler.hpp:184
AsioPromiseHandler(const AsioPromiseHandler &that)
Definition: asio-promise-handler.hpp:174
AsioPromiseHandler(AsioPromiseHandler &&that)
Definition: asio-promise-handler.hpp:179
AsioPromiseHandler & operator=(AsioPromiseHandler &&that)
Definition: asio-promise-handler.hpp:189
Definition: asio-promise-handler.hpp:38
bool ready() const
Definition: asio-promise-handler.hpp:147
T get() const
Definition: asio-promise-handler.hpp:151
AsioPromise(Exec executor, Func &&callback)
Definition: asio-promise-handler.hpp:109
auto then(FuncT &&func) -> AsioPromise< Exec, PromiseThenResult< FuncT, typename BaseT::DataT >>
Definition: asio-promise-handler.hpp:128
AsioPromise(Exec executor, T value)
Definition: asio-promise-handler.hpp:100
Definition: promise-interface.hpp:210
Definition: location.hpp:10
AsioPromiseHandler(Exec) -> AsioPromiseHandler< Exec >
typename detail::PromiseThenResultT< T, P >::type PromiseThenResult
Definition: promise-interface.hpp:67
Definition: clientutil.hpp:217