virthttp  0.0
libvirt http interface
json2virt.hpp
Go to the documentation of this file.
1 #pragma once
2 #include <rapidjson/document.h>
3 #include "../utils.hpp"
5 #include "json_utils.hpp"
6 
7 std::optional<virt::TypedParams> json_to_typed_parameters(const rapidjson::Value& val);
8 
9 enum class JTag {
10  None,
11  // Object,
12  Array,
13  Bool,
14  Int32,
15  Uint32,
16  Int64,
17  Uint64,
18  Float,
19  Double,
20  String,
21  Enum,
22 };
23 
24 template <JTag tag, class = void> struct JTagRepr { using type = void; };
25 
26 template <> struct JTagRepr<JTag::Bool, void> { using type = bool; };
27 template <> struct JTagRepr<JTag::Int32, void> { using type = long; };
28 template <> struct JTagRepr<JTag::Uint32, void> { using type = unsigned; };
29 template <> struct JTagRepr<JTag::Int64, void> { using type = long long; };
30 template <> struct JTagRepr<JTag::Uint64, void> { using type = unsigned long long; };
31 template <> struct JTagRepr<JTag::Float, void> { using type = float; };
32 template <> struct JTagRepr<JTag::Double, void> { using type = double; };
33 template <> struct JTagRepr<JTag::String, void> { using type = std::string; };
34 template <class F> struct JTagRepr<JTag::Enum, F> { using type = F; };
35 
36 template <class> struct JTagReverse;
37 
38 template <JTag tag_, class Extra_> struct JTagReverse<JTagRepr<tag_, Extra_>> {
39  using Extra = Extra_;
40  constexpr static JTag tag = tag_;
41 };
42 
43 template <JTag tag, class Extra = void> using JTagRepr_t = typename JTagRepr<tag, Extra>::type;
44 
45 template <JTag type, JTag nested_type = JTag::None, class Extra = void>
46 auto extract_param_val(const rapidjson::Value& el_json, JsonRes& json_res) noexcept {
47  static_assert(type != JTag::None, "Extracted type must exist");
48  using SubRepr = JTagRepr_t<nested_type, Extra>;
49  using RawRepr = JTagRepr<type, Extra>;
50  using Repr = std::conditional_t<type != JTag::Array, JTagRepr_t<type, Extra>, std::vector<SubRepr>>;
51  using Ret = std::optional<Repr>;
52  auto error = [&](auto... args) { return json_res.error(args...), Ret{std::nullopt}; };
53 
54  Ret ret{};
55  auto& ret_val = ret.emplace();
56 
57  if constexpr (type == JTag::Array) {
58  static_assert(nested_type != JTag::None, "Sub-extracted type must exist");
59 
60  if (!el_json.IsArray())
61  return error(0);
62  const auto el_jsonarr = el_json.GetArray();
63  ret_val.reserve(el_jsonarr.Size());
64  for (const auto& sub_el : el_jsonarr) {
65  auto res = extract_param_val<nested_type, JTag::None>(sub_el, json_res);
66  if (!res)
67  return Ret{std::nullopt};
68  ret_val.push_back(std::move(*res));
69  }
70  } else {
71  static_assert(nested_type == JTag::None, "Sub-extracted type shall not exist");
72  if constexpr (type == JTag::Bool) {
73  if (!el_json.IsBool())
74  return error(0);
75  ret_val = el_json.GetBool();
76  } else if constexpr (type == JTag::Int32) {
77  if (!el_json.IsInt())
78  return error(0);
79  ret_val = el_json.GetInt();
80  } else if constexpr (type == JTag::Uint32) {
81  if (!el_json.IsUint())
82  return error(0);
83  ret_val = el_json.GetUint();
84  } else if constexpr (type == JTag::Int64) {
85  if (!(el_json.IsInt() || el_json.IsInt64()))
86  return error(0);
87  ret_val = el_json.IsInt64() ? el_json.GetInt64() : el_json.GetInt();
88  } else if constexpr (type == JTag::Uint64) {
89  if (!(el_json.IsUint() || el_json.IsUint64()))
90  return error(0);
91  ret_val = el_json.IsUint64() ? el_json.GetUint64() : el_json.GetUint();
92  } else if constexpr (type == JTag::Float) {
93  if (!el_json.IsFloat())
94  return error(0);
95  ret_val = el_json.GetFloat();
96  } else if constexpr (type == JTag::Double) {
97  if (!el_json.IsDouble())
98  return error(0);
99  ret_val = el_json.GetDouble();
100  } else if constexpr (type == JTag::String) {
101  if (!el_json.IsString())
102  return error(0);
103  ret_val = std::string{el_json.GetString(), el_json.GetStringLength()};
104  } else if constexpr (type == JTag::Enum) {
105  if (!el_json.IsString())
106  return error(0);
107  const auto enum_opt = Repr::from_string({el_json.GetString(), el_json.GetStringLength()});
108  if (!enum_opt)
109  return Ret{std::nullopt};
110  ret_val = *enum_opt;
111  }
112  }
113  return ret;
114 }
115 
116 template <JTag type, JTag nested_type = JTag::None, class Extra = void>
117 auto extract_param(const rapidjson::Value& val, gsl::czstring<> name, JsonRes& json_res, bool consider_optional = false) noexcept
118  -> decltype(extract_param_val<type, nested_type, Extra>(std::declval<decltype(val)>(), json_res)) {
119  using Ret = decltype(extract_param_val<type, nested_type, Extra>(std::declval<decltype(val)>(), json_res));
120  auto error = [&](auto... args) { return json_res.error(args...), std::nullopt; };
121  const auto el_it = val.FindMember(name);
122  if (el_it == val.MemberEnd()) {
123  if (consider_optional) {
124  Ret ret{};
125  ret.emplace(); // Requires the type to have a default ctor
126  return ret;
127  }
128  return std::nullopt;
129  }
130  const auto& el_json = el_it->value;
131  return extract_param_val<type, nested_type, Extra>(el_json, json_res);
132 }
133 
134 template <JTag tag, JTag nested_type_ = JTag::None, class Extra = void> struct WArg {
136  using Ret =
137  RemoveOptional_t<decltype(extract_param_val<tag, nested_type_, Extra>(std::declval<const rapidjson::Value&>(), std::declval<JsonRes&>()))>;
138  constexpr static auto nested_type = nested_type_;
139 
140  gsl::czstring<> name;
141  bool optional = false;
142 };
143 
144 template <size_t... I, class... Args>
145 auto wrap_fcn_args_impl(const rapidjson::Value& val, JsonRes& json_res, std::index_sequence<I...> is, Args... args) noexcept {
146  using Tup = std::tuple<typename Args::Ret...>;
147  std::optional<Tup> ret{};
148  auto& vals = ret.emplace();
149 
150  if constexpr (sizeof...(args) > 1) {
151  if (!val.IsObject())
152  return json_res.error(0), decltype(ret){std::nullopt};
153  auto proc_parm = [&](auto warg, auto ic) {
155  using Extra = typename JTagRev::Extra;
156  constexpr JTag tag = JTagRev::tag;
157  constexpr JTag nested_tag = decltype(warg)::nested_type;
158  constexpr auto idx = decltype(ic)::value;
159  const auto res = extract_param<tag, nested_tag, Extra>(val, warg.name, json_res);
160  if (res)
161  std::get<idx>(vals) = std::move(*res);
162  return static_cast<bool>(res);
163  };
164  return (proc_parm(args, std::integral_constant<size_t, I>{}) && ...) ? ret : std::nullopt; // Done this way to use lazy evaluation
165  } else if constexpr (sizeof...(args) == 1) {
166  auto proc_parm = [&](auto warg) {
168  using Extra = typename JTagRev::Extra;
169  constexpr JTag tag = JTagRev::tag;
170  constexpr JTag nested_tag = decltype(warg)::nested_type;
171  const auto res = extract_param_val<tag, nested_tag, Extra>(val, json_res);
172  if (res)
173  std::get<0>(vals) = std::move(*res);
174  return static_cast<bool>(res);
175  };
176  return (proc_parm(args) && ...) ? ret : std::nullopt;
177  } else {
178  return std::optional{std::tuple<>{}};
179  }
180 }
181 
182 template <class... Args> auto wrap_fcn_args(const rapidjson::Value& val, JsonRes& json_res, Args... args) noexcept {
183  return wrap_fcn_args_impl(val, json_res, std::index_sequence_for<Args...>{}, args...);
184 }
185 
186 template <class Fcn, class... Args> auto wrap_fcn(const rapidjson::Value& val, JsonRes& json_res, Fcn fcn, Args... args) noexcept {
187  const auto tup = wrap_fcn_args(val, json_res, args...);
188  return tup ? std::optional{std::apply(fcn, *tup)} : std::nullopt;
189 }
typename JTagRepr< tag, Extra >::type JTagRepr_t
Definition: json2virt.hpp:43
unsigned long long type
Definition: json2virt.hpp:30
auto wrap_fcn(const rapidjson::Value &val, JsonRes &json_res, Fcn fcn, Args...args) noexcept
Definition: json2virt.hpp:186
Extra_ Extra
Definition: json2virt.hpp:39
Definition: json2virt.hpp:24
void error(int code)
Definition: json_utils.hpp:57
float type
Definition: json2virt.hpp:31
std::string type
Definition: json2virt.hpp:33
::JTagRepr< tag, Extra > JTagRepr
Definition: json2virt.hpp:135
JTag
Definition: json2virt.hpp:9
Definition: json2virt.hpp:134
unsigned type
Definition: json2virt.hpp:28
STL namespace.
void type
Definition: json2virt.hpp:24
long type
Definition: json2virt.hpp:27
RemoveOptional_t< decltype(extract_param_val< tag, nested_type_, Extra >(std::declval< const rapidjson::Value & >(), std::declval< JsonRes & >()))> Ret
Definition: json2virt.hpp:137
auto wrap_fcn_args_impl(const rapidjson::Value &val, JsonRes &json_res, std::index_sequence< I... > is, Args...args) noexcept
Definition: json2virt.hpp:145
auto wrap_fcn_args(const rapidjson::Value &val, JsonRes &json_res, Args...args) noexcept
Definition: json2virt.hpp:182
std::optional< virt::TypedParams > json_to_typed_parameters(const rapidjson::Value &val)
Definition: json2virt.cpp:3
Definition: json_utils.hpp:21
bool type
Definition: json2virt.hpp:26
typename RemoveOptional< OptT >::type RemoveOptional_t
Definition: utility.hpp:33
Definition: json2virt.hpp:36
long long type
Definition: json2virt.hpp:29
auto extract_param_val(const rapidjson::Value &el_json, JsonRes &json_res) noexcept
Definition: json2virt.hpp:46
double type
Definition: json2virt.hpp:32
gsl::czstring name
Definition: json2virt.hpp:140
auto extract_param(const rapidjson::Value &val, gsl::czstring<> name, JsonRes &json_res, bool consider_optional=false) noexcept-> decltype(extract_param_val< type, nested_type, Extra >(std::declval< decltype(val)>(), json_res))
Definition: json2virt.hpp:117
F type
Definition: json2virt.hpp:34