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  }
67 
68  template<class T>
69  inline void addToJsonIfNeeded(json &j, std::string name, T &&arg)
70  {
71  detail::AddToJsonIfNeededT<std::decay_t<T>>::call(j, name, std::forward<T>(arg));
72  };
73 
74  // Provide a non-destructive way to add the map
75  // to json.
76  template<class MapT,
77  // disallow json object here
78  std::enable_if_t<!std::is_same_v<std::decay_t<MapT>, json>
79  && !std::is_same_v<std::decay_t<MapT>, JsonWrap>, int> = 0>
80  inline void addPropertyMapToJson(json &j, MapT &&arg)
81  {
82  for (auto kv : std::forward<MapT>(arg)) {
83  auto [k, v] = kv;
84  j[k] = v;
85  }
86  };
87 
88  inline void addPropertyMapToJson(json &j, const json &arg)
89  {
90  for (auto kv : arg.items()) {
91  auto [k, v] = kv;
92  j[k] = v;
93  }
94  };
95 
96  using EventList = immer::flex_vector<Event>;
97 
98  using namespace std::string_literals;
99 
100  struct Null {};
101  using Variant = std::variant<std::string, JsonWrap, Null>;
102 
103  namespace detail
104  {
105  struct DefaultValT
106  {
107  template<class T>
108  constexpr operator T() const {
109  return T();
110  }
111  };
112  }
113 
114  constexpr detail::DefaultValT DEFVAL;
115 
117  {
119  };
120 
121  namespace detail
122  {
123  // emulates declval() but returns lvalue reference
124  template<class T>
125  typename std::add_lvalue_reference<T>::type declref() noexcept;
126  }
127 }
128 
129 namespace nlohmann {
130  template <class T, class V>
131  struct adl_serializer<immer::map<T, V>> {
132  static void to_json(json& j, immer::map<T, V> map) {
133  if constexpr (std::is_same_v<T, std::string>) {
134  j = json::object();
135  for (auto [k, v] : map) {
136  j[k] = v;
137  }
138  } else {
139  j = json::array();
140  for (auto [k, v] : map) {
141  j.push_back(k);
142  j.push_back(v);
143  }
144  }
145  }
146 
147  static void from_json(const json& j, immer::map<T, V> &m) {
148  immer::map<T, V> ret;
149  if constexpr (std::is_same_v<T, std::string>) {
150  for (const auto &[k, v] : j.items()) {
151  ret = std::move(ret).set(k, v);
152  }
153  } else {
154  for (std::size_t i = 0; i < j.size(); i += 2) {
155  ret = std::move(ret).set(j[i], j[i+1]);
156  }
157  }
158  m = ret;
159  }
160  };
161 
162  template <class T>
163  struct adl_serializer<immer::array<T>> {
164  static void to_json(json& j, immer::array<T> arr) {
165  j = json::array();
166  for (auto i : arr) {
167  j.push_back(json(i));
168  }
169  }
170 
171  static void from_json(const json& j, immer::array<T> &a) {
172  immer::array<T> ret;
173  if (j.is_array()) {
174  for (const auto &i : j) {
175  ret = std::move(ret).push_back(i);
176  }
177  }
178  a = ret;
179  }
180  };
181 
182  template <class T>
183  struct adl_serializer<immer::flex_vector<T>> {
184  static void to_json(json& j, immer::flex_vector<T> arr) {
185  j = json::array();
186  for (auto i : arr) {
187  j.push_back(json(i));
188  }
189  }
190 
191  static void from_json(const json& j, immer::flex_vector<T> &a) {
192  immer::flex_vector<T> ret;
193  if (j.is_array()) {
194  for (const auto &i : j) {
195  ret = std::move(ret).push_back(i.get<T>());
196  }
197  }
198  a = ret;
199  }
200  };
201 
202  template <>
203  struct adl_serializer<Kazv::Variant> {
204  static void to_json(json& j, const Kazv::Variant &var) {
205  std::visit(lager::visitor{
206  [&j](std::string i) { j = i; },
207  [&j](Kazv::JsonWrap i) { j = i; },
208  [&j](Kazv::Null) { j = nullptr; }
209  }, var);
210  }
211 
212  static void from_json(const json& j, Kazv::Variant &var) {
213  if (j.is_string()) {
214  var = j.get<std::string>();
215  } else if (j.is_null()) {
216  var = Kazv::Null{};
217  } else { // is object
218  var = Kazv::Variant(Kazv::JsonWrap(j));
219  }
220  }
221  };
222 }
Kazv::Invite
@ Invite
Definition: types.hpp:118
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:171
nlohmann::adl_serializer< immer::map< T, V > >::from_json
static void from_json(const json &j, immer::map< T, V > &m)
Definition: types.hpp:147
Kazv::Null
Definition: types.hpp:100
Kazv::Join
@ Join
Definition: types.hpp:118
Kazv::RoomMembership
RoomMembership
Definition: types.hpp:116
nlohmann
Definition: location.hpp:26
event.hpp
Kazv
Definition: location.hpp:10
Kazv::addPropertyMapToJson
void addPropertyMapToJson(json &j, MapT &&arg)
Definition: types.hpp:80
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:164
nlohmann::adl_serializer< Kazv::Variant >::to_json
static void to_json(json &j, const Kazv::Variant &var)
Definition: types.hpp:204
nlohmann::adl_serializer< Kazv::Variant >::from_json
static void from_json(const json &j, Kazv::Variant &var)
Definition: types.hpp:212
Kazv::DEFVAL
constexpr detail::DefaultValT DEFVAL
Definition: types.hpp:114
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:191
Kazv::addToJsonIfNeeded
void addToJsonIfNeeded(json &j, std::string name, T &&arg)
Definition: types.hpp:69
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:118
std
Definition: clientutil.hpp:216
Kazv::Variant
std::variant< std::string, JsonWrap, Null > Variant
Definition: types.hpp:101
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:184
nlohmann::adl_serializer< immer::map< T, V > >::to_json
static void to_json(json &j, immer::map< T, V > map)
Definition: types.hpp:132
Kazv::EventList
immer::flex_vector< Event > EventList
Definition: types.hpp:96