libkazv
types.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of libkazv.
3  * SPDX-FileCopyrightText: 2020-2021 Tusooa Zhu <tusooa@kazv.moe>
4  * SPDX-License-Identifier: AGPL-3.0-or-later
5  */
6 
7 
8 #pragma once
9 #include "libkazv-config.hpp"
10 
11 #include <optional>
12 #include <string>
13 #include <variant>
14 
15 #include <nlohmann/json.hpp>
16 #include <immer/array.hpp>
17 #include <immer/flex_vector.hpp>
18 #include <immer/map.hpp>
19 #include <boost/hana/type.hpp>
20 #include <lager/util.hpp>
21 
22 #include "jsonwrap.hpp"
23 #include "event.hpp"
24 
25 namespace Kazv
26 {
27  using Bytes = std::string;
28 
29  enum Status : bool
30  {
33  };
34 
35  namespace detail
36  {
37  constexpr auto hasEmptyMethod = boost::hana::is_valid(
38  [](auto t) -> decltype((void)std::declval<typename decltype(t)::type>().empty()) {});
39  template<class U>
40  struct AddToJsonIfNeededT
41  {
42  template<class T>
43  static void call(json &j, std::string name, T &&arg) {
44  using Type = std::decay_t<T>;
45  if constexpr (detail::hasEmptyMethod(boost::hana::type_c<Type>)) {
46  if (! arg.empty()) {
47  j[name] = std::forward<T>(arg);
48  }
49  } else {
50  j[name] = std::forward<T>(arg);
51  }
52  }
53  };
54 
55  template<class U>
56  struct AddToJsonIfNeededT<std::optional<U>>
57  {
58  template<class T>
59  static void call(json &j, std::string name, T &&arg) {
60  if (arg.has_value()) {
61  j[name] = std::forward<T>(arg).value();
62  }
63  }
64  };
65 
66  template<>
67  struct AddToJsonIfNeededT<JsonWrap>
68  {
69  template<class T>
70  static void call(json &j, std::string name, T &&arg) {
71  if (!arg.get().is_null()) {
72  j[name] = std::forward<T>(arg).get();
73  }
74  }
75  };
76 
77  }
78 
79  template<class T>
80  inline void addToJsonIfNeeded(json &j, std::string name, T &&arg)
81  {
82  detail::AddToJsonIfNeededT<std::decay_t<T>>::call(j, name, std::forward<T>(arg));
83  };
84 
85  // Provide a non-destructive way to add the map
86  // to json.
87  template<class MapT,
88  // disallow json object here
89  std::enable_if_t<!std::is_same_v<std::decay_t<MapT>, json>
90  && !std::is_same_v<std::decay_t<MapT>, JsonWrap>, int> = 0>
91  inline void addPropertyMapToJson(json &j, MapT &&arg)
92  {
93  for (auto kv : std::forward<MapT>(arg)) {
94  auto [k, v] = kv;
95  j[k] = v;
96  }
97  };
98 
99  inline void addPropertyMapToJson(json &j, const json &arg)
100  {
101  for (auto kv : arg.items()) {
102  auto [k, v] = kv;
103  j[k] = v;
104  }
105  };
106 
107  using EventList = immer::flex_vector<Event>;
108 
109  using namespace std::string_literals;
110 
111  struct Null {};
112  using Variant = std::variant<std::string, JsonWrap, Null>;
113 
114  namespace detail
115  {
116  struct DefaultValT
117  {
118  template<class T>
119  constexpr operator T() const {
120  return T();
121  }
122  };
123  }
124 
125  constexpr detail::DefaultValT DEFVAL;
126 
128  {
130  };
131 
132  namespace detail
133  {
134  // emulates declval() but returns lvalue reference
135  template<class T>
136  typename std::add_lvalue_reference<T>::type declref() noexcept;
137  }
138 }
139 
140 namespace nlohmann {
141  template <class T, class V>
142  struct adl_serializer<immer::map<T, V>> {
143  static void to_json(json& j, immer::map<T, V> map) {
144  if constexpr (std::is_same_v<T, std::string>) {
145  j = json::object();
146  for (auto [k, v] : map) {
147  j[k] = v;
148  }
149  } else {
150  j = json::array();
151  for (auto [k, v] : map) {
152  j.push_back(k);
153  j.push_back(v);
154  }
155  }
156  }
157 
158  static void from_json(const json& j, immer::map<T, V> &m) {
159  immer::map<T, V> ret;
160  if constexpr (std::is_same_v<T, std::string>) {
161  for (const auto &[k, v] : j.items()) {
162  ret = std::move(ret).set(k, v);
163  }
164  } else {
165  for (std::size_t i = 0; i < j.size(); i += 2) {
166  ret = std::move(ret).set(j[i], j[i+1]);
167  }
168  }
169  m = ret;
170  }
171  };
172 
173  template <class T>
174  struct adl_serializer<immer::array<T>> {
175  static void to_json(json& j, immer::array<T> arr) {
176  j = json::array();
177  for (auto i : arr) {
178  j.push_back(json(i));
179  }
180  }
181 
182  static void from_json(const json& j, immer::array<T> &a) {
183  immer::array<T> ret;
184  if (j.is_array()) {
185  for (const auto &i : j) {
186  ret = std::move(ret).push_back(i);
187  }
188  }
189  a = ret;
190  }
191  };
192 
193  template <class T>
194  struct adl_serializer<immer::flex_vector<T>> {
195  static void to_json(json& j, immer::flex_vector<T> arr) {
196  j = json::array();
197  for (auto i : arr) {
198  j.push_back(json(i));
199  }
200  }
201 
202  static void from_json(const json& j, immer::flex_vector<T> &a) {
203  immer::flex_vector<T> ret;
204  if (j.is_array()) {
205  for (const auto &i : j) {
206  ret = std::move(ret).push_back(i.get<T>());
207  }
208  }
209  a = ret;
210  }
211  };
212 
213  template <>
214  struct adl_serializer<Kazv::Variant> {
215  static void to_json(json& j, const Kazv::Variant &var) {
216  std::visit(lager::visitor{
217  [&j](std::string i) { j = i; },
218  [&j](Kazv::JsonWrap i) { j = i; },
219  [&j](Kazv::Null) { j = nullptr; }
220  }, var);
221  }
222 
223  static void from_json(const json& j, Kazv::Variant &var) {
224  if (j.is_string()) {
225  var = j.get<std::string>();
226  } else if (j.is_null()) {
227  var = Kazv::Null{};
228  } else { // is object
229  var = Kazv::Variant(Kazv::JsonWrap(j));
230  }
231  }
232  };
233 }
Kazv::Invite
@ Invite
Definition: types.hpp:129
Kazv::FAIL
@ FAIL
Definition: types.hpp:31
nlohmann::adl_serializer< immer::array< T > >::from_json
static void from_json(const json &j, immer::array< T > &a)
Definition: types.hpp:182
nlohmann::adl_serializer< immer::map< T, V > >::from_json
static void from_json(const json &j, immer::map< T, V > &m)
Definition: types.hpp:158
Kazv::Null
Definition: types.hpp:111
Kazv::Join
@ Join
Definition: types.hpp:129
Kazv::RoomMembership
RoomMembership
Definition: types.hpp:127
nlohmann
Definition: location.hpp:26
event.hpp
Kazv
Definition: location.hpp:10
Kazv::addPropertyMapToJson
void addPropertyMapToJson(json &j, MapT &&arg)
Definition: types.hpp:91
Kazv::Status
Status
Definition: types.hpp:29
nlohmann::adl_serializer< immer::array< T > >::to_json
static void to_json(json &j, immer::array< T > arr)
Definition: types.hpp:175
nlohmann::adl_serializer< Kazv::Variant >::to_json
static void to_json(json &j, const Kazv::Variant &var)
Definition: types.hpp:215
nlohmann::adl_serializer< Kazv::Variant >::from_json
static void from_json(const json &j, Kazv::Variant &var)
Definition: types.hpp:223
Kazv::DEFVAL
constexpr detail::DefaultValT DEFVAL
Definition: types.hpp:125
Kazv::json
nlohmann::json json
Definition: jsonwrap.hpp:20
nlohmann::adl_serializer< immer::flex_vector< T > >::from_json
static void from_json(const json &j, immer::flex_vector< T > &a)
Definition: types.hpp:202
Kazv::addToJsonIfNeeded
void addToJsonIfNeeded(json &j, std::string name, T &&arg)
Definition: types.hpp:80
Kazv::detail::declref
std::add_lvalue_reference< T >::type declref() noexcept
Kazv::detail::hasEmptyMethod
constexpr auto hasEmptyMethod
Definition: types.hpp:37
Kazv::JsonWrap
Definition: jsonwrap.hpp:22
jsonwrap.hpp
Kazv::Bytes
std::string Bytes
Definition: types.hpp:27
Kazv::Leave
@ Leave
Definition: types.hpp:129
std
Definition: clientutil.hpp:216
Kazv::Variant
std::variant< std::string, JsonWrap, Null > Variant
Definition: types.hpp:112
Kazv::SUCC
@ SUCC
Definition: types.hpp:32
libkazv-config.hpp
nlohmann::adl_serializer< immer::flex_vector< T > >::to_json
static void to_json(json &j, immer::flex_vector< T > arr)
Definition: types.hpp:195
nlohmann::adl_serializer< immer::map< T, V > >::to_json
static void to_json(json &j, immer::map< T, V > map)
Definition: types.hpp:143
Kazv::EventList
immer::flex_vector< Event > EventList
Definition: types.hpp:107