libkazv
context.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 <lager/deps.hpp>
10 
11 #include <boost/hana.hpp>
12 
13 #include <jsonwrap.hpp>
14 #include <promise-interface.hpp>
15 
16 namespace Kazv
17 {
19  {
20  public:
21  inline EffectStatus() : m_succ(true) {}
22  inline EffectStatus(bool succ) : m_succ(succ) {}
23  inline EffectStatus(bool succ, JsonWrap d) : m_succ(succ), m_data(d) {}
24 
30  inline bool success() const { return m_succ; }
36  inline explicit operator bool() const { return success(); }
42  inline const JsonWrap &data() const { return m_data; }
43 
52  inline const json &dataJson(std::string key) const {
53  return data().get().at(key);
54  }
55 
65  inline const json &dataJson(int index, std::string key) const {
66  return data().get().at(index).at(key);
67  }
68 
78  inline std::string dataStr(std::string key) const {
79  return dataJson(key).template get<std::string>();
80  }
81 
92  inline std::string dataStr(int index, std::string key) const {
93  return dataJson(index, key).template get<std::string>();
94  }
95  private:
96  bool m_succ;
97  JsonWrap m_data;
98  };
99 
101  {
102  return EffectStatus{true, json::array()};
103  }
104 
106  {
107  auto succ = a.success() && b.success();
108  auto data = a.data().get().is_array()
109  ? a.data().get()
110  : json::array({a.data().get()});
111  if (b.data().get().is_array()) {
112  for (const auto &i: b.data().get()) {
113  data.push_back(i);
114  }
115  } else {
116  data.push_back(b.data().get());
117  }
118  return {succ, data};
119  }
120 
122  {
123  return EffectStatus(true);
124  }
125 
127 
128  template<class T, class Action, class Deps = lager::deps<>>
129  class ContextBase : public Deps
130  {
131  public:
132  using RetType = T;
135  template<class Func>
136  ContextBase(Func &&dispatcher, PromiseInterfaceT ph, Deps deps)
137  : Deps(std::move(deps))
138  , m_ph(ph)
139  , m_dispatcher(std::forward<Func>(dispatcher))
140  {
141  }
142 
143  template<class AnotherAction, class AnotherDeps,
144  std::enable_if_t<std::is_convertible_v<Action, AnotherAction>
145  && std::is_convertible_v<AnotherDeps, Deps>, int> = 0>
147  : Deps(that)
148  , m_ph(that.m_ph)
149  , m_dispatcher(that.m_dispatcher)
150  {
151  }
152 
153  template<class AnotherAction, class AnotherDeps, class Conv,
154  std::enable_if_t<std::is_convertible_v<std::invoke_result_t<Conv, Action>, AnotherAction>
155  && std::is_convertible_v<AnotherDeps, Deps>, int> = 0>
157  : Deps(that)
158  , m_ph(that.m_ph)
159  , m_dispatcher([=,
160  thatDispatcher=that.m_dispatcher,
161  conv=std::forward<Conv>(conv)](Action a) {
162  thatDispatcher(conv(std::move(a)));
163  })
164  {
165  }
166 
167  PromiseT dispatch(Action a) const {
168  return m_dispatcher(std::move(a));
169  }
170 
171  decltype(auto) deps() {
172  return static_cast<Deps &>(*this);
173  }
174 
175  template<class Func>
176  PromiseT createPromise(Func func) const {
177  return m_ph.create(std::move(func));
178  }
179 
180  template<class Func>
181  PromiseT createWaitingPromise(Func func) const {
182  return m_ph.createResolveToPromise(std::move(func));
183  }
184 
186  return m_ph.createResolved(v);
187  }
188 
190  return m_ph;
191  }
192 
193  private:
194  template<class R2, class A2, typename D2>
195  friend class ContextBase;
196  PromiseInterfaceT m_ph;
197  std::function<PromiseT(Action)> m_dispatcher;
198  };
199 
200  template<class A, class D = lager::deps<>>
202 
203  template<class T, class Action, class Deps = lager::deps<>>
205  {
206  public:
207  using RetType = T;
210 
226  template<class Func>
227  EffectBase(Func func) {
228  if constexpr (std::is_same_v<std::invoke_result_t<Func, ContextT>, void>) {
229  m_d = [func=std::move(func)](const auto &ctx) {
230  return ctx.createPromise(
231  [ctx,
232  func](auto resolve) {
233  func(ctx);
235  });
236  };
237  } else {
238  m_d = [func=std::move(func)](const auto &ctx) {
239  return ctx.createResolvedPromise(PromiseCombination::defaultForPromiseThen(RetType()))
240  .then([ctx,
241  func](auto) {
242  return func(ctx);
243  });
244  };
245  }
246  }
247 
248  PromiseT operator()(const ContextT &ctx) const {
249  return m_d(ctx);
250  }
251 
252  private:
253  std::function<PromiseT(const ContextT &)> m_d;
254  };
255 
256  template<class A, class D = lager::deps<>>
258 
259  template<class Reducer, class RetType, class Model, class Action, class Deps>
260  constexpr bool hasEffect = boost::hana::is_valid(
261  []() -> decltype((void)EffectBase<RetType, Action, Deps>(
262  std::get<1>(std::declval<std::invoke_result_t<Reducer, Model, Action>>()))) {}
263  )();
264 
265 }
Definition: context.hpp:130
PromiseT createWaitingPromise(Func func) const
Definition: context.hpp:181
PromiseT dispatch(Action a) const
Definition: context.hpp:167
PromiseT createResolvedPromise(RetType v) const
Definition: context.hpp:185
PromiseInterfaceT promiseInterface() const
Definition: context.hpp:189
PromiseT createPromise(Func func) const
Definition: context.hpp:176
decltype(auto) deps()
Definition: context.hpp:171
SingleTypePromise< RetType > PromiseT
Definition: context.hpp:134
ContextBase(const ContextBase< RetType, AnotherAction, AnotherDeps > &that, Conv &&conv)
Definition: context.hpp:156
ContextBase(Func &&dispatcher, PromiseInterfaceT ph, Deps deps)
Definition: context.hpp:136
ContextBase(const ContextBase< RetType, AnotherAction, AnotherDeps > &that)
Definition: context.hpp:146
T RetType
Definition: context.hpp:132
Definition: context.hpp:205
EffectBase(Func func)
Constructor.
Definition: context.hpp:227
PromiseT operator()(const ContextT &ctx) const
Definition: context.hpp:248
T RetType
Definition: context.hpp:207
SingleTypePromise< RetType > PromiseT
Definition: context.hpp:208
ContextBase< RetType, Action, Deps > ContextT
Definition: context.hpp:209
Definition: context.hpp:19
EffectStatus()
Definition: context.hpp:21
bool success() const
Get whether this is successful.
Definition: context.hpp:30
EffectStatus(bool succ, JsonWrap d)
Definition: context.hpp:23
std::string dataStr(std::string key) const
Get the data string at key.
Definition: context.hpp:78
const JsonWrap & data() const
Get the attached data.
Definition: context.hpp:42
EffectStatus(bool succ)
Definition: context.hpp:22
const json & dataJson(int index, std::string key) const
Get the data at index at key.
Definition: context.hpp:65
const json & dataJson(std::string key) const
Get the data at key.
Definition: context.hpp:52
std::string dataStr(int index, std::string key) const
Get the data at index at key.
Definition: context.hpp:92
Definition: jsonwrap.hpp:23
const json & get() const
Definition: jsonwrap.hpp:38
PromiseT createResolveToPromise(std::function< void(ResolveToPromiseT)> f) const
Definition: promise-interface.hpp:280
PromiseT create(std::function< void(ResolveT)> f) const
Definition: promise-interface.hpp:276
PromiseT createResolved(DataT v) const
Definition: promise-interface.hpp:284
Definition: promise-interface.hpp:122
constexpr T defaultForPromiseThen(T)
Definition: promise-interface.hpp:113
Definition: location.hpp:10
EffectStatus dataCombineNone(EffectStatus)
Definition: context.hpp:121
EffectStatus createDefaultForPromiseThen(EffectStatus)
Definition: context.hpp:100
nlohmann::json json
Definition: jsonwrap.hpp:20
EffectStatus dataCombine(EffectStatus a, EffectStatus b)
Definition: context.hpp:105
constexpr bool hasEffect
Definition: context.hpp:260
Definition: clientutil.hpp:217