libkazv
store.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/state.hpp>
10 #include <lager/deps.hpp>
11 #include <lager/util.hpp>
12 #include <lager/context.hpp>
13 #include <lager/store.hpp>
14 #include "context.hpp"
15 
16 namespace Kazv
17 {
18  template<class Action,
19  class EffectRetType,
20  class Model,
21  class Reducer,
22  class Deps = lager::deps<>,
23  class Tag = lager::automatic_tag>
24  class StoreBase
25  {
26  public:
27  using RetType = EffectRetType;
31 
32  template<class PH>
33  StoreBase(Model initialModel, Reducer reducer, PH &&ph, Deps deps)
34  : m_d{std::make_shared<Private>(
35  lager::make_state(std::move(initialModel), Tag{}),
36  reducer,
37  PromiseInterfaceT{std::forward<PH>(ph)},
38  deps)}
39  {}
40 
41  StoreBase(const StoreBase &that) = delete;
42  StoreBase &operator=(const StoreBase &that) = delete;
43 
45  : m_d(std::move(that.m_d))
46  {}
47 
49  m_d = std::move(that.m_d);
50  return *this;
51  }
52 
53  auto dispatch(Action a) -> PromiseT {
54  return m_d->dispatch(std::move(a));
55  };
56 
57  operator lager::reader<Model>() const {
58  return m_d->state;
59  }
60 
61  lager::reader<Model> reader() const {
62  return m_d->state;
63  }
64 
65  template<class A2, class D2>
66  operator Context<A2, D2>() const {
67  return m_d->ctx;
68  }
69 
70  ContextT context() const {
71  return m_d->ctx;
72  }
73 
74  private:
75  struct Private
76  {
77  Private(lager::state<Model, Tag> state,
78  Reducer reducer,
80  Deps deps)
81  : state(std::move(state))
82  , reducer(std::move(reducer))
83  , ph(std::move(ph))
84  // this Private will remain untouched between moves of StoreBases
85  // so it is safe to capture by referenced
86  , ctx([this](auto a) { return dispatch(std::move(a)); }, this->ph, deps)
87  {}
88  ~Private() = default;
89  lager::state<Model, Tag> state;
90  Reducer reducer;
92  ContextT ctx;
93 
94  auto dispatch(Action a) -> PromiseT {
95  return ph.createResolved(true)
96  .then(
97  [this, a=std::move(a)](auto) {
98  if constexpr (hasEffect<Reducer, RetType, Model, Action, Deps>) {
99  auto [newModel, eff] = reducer(state.get(), a);
100  state.set(newModel);
101  return eff(ctx);
102  } else {
103  auto newModel = reducer(state.get(), a);
104  state.set(newModel);
105  return ph.createResolved(true);
106  }
107  });
108  }
109  };
110  std::shared_ptr<Private> m_d;
111  };
112 
113  template<class Action,
114  class Model,
115  class Reducer,
116  class Deps = lager::deps<>,
117  class Tag = lager::automatic_tag>
119 
120  namespace detail
121  {
122  constexpr auto compose()
123  {
124  return zug::identity;
125  }
126 
127  template<class F1, class ...Fs>
128  constexpr auto compose(F1 &&f1, Fs &&...fs)
129  {
130  return zug::comp(std::forward<F1>(f1), std::forward<Fs>(fs)...);
131  }
132  }
133 
134  template<class Action,
135  class Tag = lager::automatic_tag,
136  class Model,
137  class Reducer,
138  class PH,
139  class ...Enhancers
140  >
141  auto makeStore(Model &&initialModel, Reducer &&reducer, PH &&ph, Enhancers &&...enhancers)
142  {
143  auto enhancer = detail::compose(std::forward<Enhancers>(enhancers)...);
144  auto factory = enhancer(
145  [&](auto actionTraits,
146  auto &&model,
147  auto &&reducer,
148  auto &&ph,
149  auto &&deps,
150  auto &&) {
151  using ActionTraits = decltype(actionTraits);
152 
153  using ModelF = decltype(model);
154  using ReducerF = decltype(reducer);
155  using PHF = decltype(ph);
156  using DepsF = decltype(deps);
157 
158  using ActionT = typename ActionTraits::type;
159  using ModelT = std::decay_t<ModelF>;
160  using ReducerT = std::decay_t<ReducerF>;
161  using DepsT = std::decay_t<DepsF>;
163  std::forward<ModelF>(initialModel), std::forward<ReducerF>(reducer),
164  std::forward<PHF>(ph), std::forward<DepsF>(deps));
165  });
166  return factory(
167  lager::type_<Action>{},
168  std::forward<Model>(initialModel), std::forward<Reducer>(reducer),
169  std::forward<PH>(ph), lager::deps<>{}, Tag{});
170  }
171 }
Definition: promise-interface.hpp:122
Definition: store.hpp:25
StoreBase(const StoreBase &that)=delete
ContextBase< RetType, Action, Deps > ContextT
Definition: store.hpp:30
auto dispatch(Action a) -> PromiseT
Definition: store.hpp:53
StoreBase & operator=(const StoreBase &that)=delete
lager::reader< Model > reader() const
Definition: store.hpp:61
SingleTypePromiseInterface< RetType > PromiseInterfaceT
Definition: store.hpp:28
StoreBase(Model initialModel, Reducer reducer, PH &&ph, Deps deps)
Definition: store.hpp:33
StoreBase(StoreBase &&that)
Definition: store.hpp:44
StoreBase & operator=(StoreBase &&that)
Definition: store.hpp:48
EffectRetType RetType
Definition: store.hpp:27
ContextT context() const
Definition: store.hpp:70
SingleTypePromise< RetType > PromiseT
Definition: store.hpp:29
constexpr auto compose()
Definition: store.hpp:122
Definition: location.hpp:10
@ Private
Definition: client-model.hpp:41
auto makeStore(Model &&initialModel, Reducer &&reducer, PH &&ph, Enhancers &&...enhancers)
Definition: store.hpp:141
Definition: clientutil.hpp:217