pupene  0.2.0
json-puppers.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <iostream>
4 #include <json.hpp>
5 #include "pupper.h"
6 
7 using json = nlohmann::json;
8 
9 /** \file
10  * Optional JSON serialization support
11  */
12 namespace pupene {
13  using std::literals::string_literals::operator""s;
14 
15  class JsonWriter : public Pupper<JsonWriter> {
16  public:
17  explicit JsonWriter(std::ostream& stream) : stream(stream) {}
18  ~JsonWriter() override = default;
19 
20  template <typename T>
21  PupPolicy begin(T& /*value*/, const Meta& meta) {
22  if (!stack.empty()) {
23  if (stack.back() > 0)
24  stream << ", " << std::endl;
25 
26  stack.back()++;
27  }
28 
29  if (strlen(meta.name) > 0)
30  stream << quote(meta.name) << ": ";
31 
32  switch (meta.type) {
33  case Meta::Type::Array:
34  stream << '[';
35  break;
36  case Meta::Type::Object:
37  stream << '{';
38  break;
39  default:
40  throw std::runtime_error("expected array or object");
41  }
42 
43  stack.emplace_back(0);
44  graph.emplace_back(meta.type);
45 
46  return PupPolicy::pup_object;
47  }
48  void end(const Meta& /*meta*/);
49 
50  template <typename T,
51  typename = enable_if_puppable<T>>
52  void pup(T& value, const Meta& meta) {
53  if (stack.empty())
54  throw std::invalid_argument("begin(meta) not called");
55 
56  if (stack.back() > 0)
57  stream << ',';
58 
59  stream << std::endl;
60 
61  if (strlen(meta.name) > 0)
62  stream << quote(meta.name) << ": ";
63 
64  if constexpr (is_puppable<T>() && sizeof(T) > 4) {
65  stream << '"' << value << '"';
66  } else {
67  stream << value;
68  }
69 
70  stack.back()++;
71  }
72 
73  private:
74  static std::string quote(const std::string& s);
75 
76  std::ostream& stream;
77  std::vector<uint16_t> stack {};
78  std::vector<pupene::Meta::Type> graph {};
79  };
80 
81  class JsonReader : public Pupper<JsonReader> {
82  public:
83  explicit JsonReader(std::istream& in)
84  : dom(json::parse(in)) {}
85  ~JsonReader() override = default;
86 
87  friend std::ostream& operator<<(std::ostream& out,
88  const JsonReader& reader);
89 
90  template <typename T>
91  PupPolicy begin(T&, const Meta& meta) {
92  using Type = Meta::Type;
93 
94  if (meta.type == Type::Value)
95  throw std::invalid_argument("must be Array or Object");
96 
97  const auto child = resolve_child(meta);
98  state.emplace_back(JsonState{child, meta, 0});
99 
100  return PupPolicy::pup_object;
101  }
102 
103  void end(const Meta& /*meta*/);
104 
105  template <typename T,
106  typename = enable_if_puppable<T>>
107  void pup(T& value, const Meta& meta) {
108  using Type = pupene::Meta::Type;
109 
110  if (!parent_is(Type::Array)) {
111  T t = state.back().dom->at(meta.name);
112  value = t;
113  } else {
114  auto& next = state.back();
115  T t = next.dom->begin()[next.idx++];;
116  value = t;
117  }
118  }
119 
120  private:
121  struct JsonState {
122  const json* dom;
123  const Meta meta;
124  uint16_t idx = 0;
125  };
126 
127  const json dom;
128  std::vector<JsonState> state;
129 
130  bool parent_is(Meta::Type type) const;
131  const json* resolve_child(const Meta& meta);
132  };
133 
134  std::ostream& operator<<(std::ostream& out,
135  const Meta& meta);
136 }
void pup(T &value, const Meta &meta)
Definition: json-puppers.h:107
JsonReader(std::istream &in)
Definition: json-puppers.h:83
pup object using its component pup functions
Definition: debug.cpp:4
PupPolicy begin(T &, const Meta &meta)
Definition: json-puppers.h:91
~JsonWriter() override=default
Holds name and type of objects.
Definition: traits.h:7
void end(const Meta &)
Definition: json-puppers.cpp:8
JsonWriter(std::ostream &stream)
Definition: json-puppers.h:17
void pup(T &value, const Meta &meta)
Definition: json-puppers.h:52
void end(const Meta &)
const Type type
Definition: traits.h:19
PupPolicy
Controls an object&#39;s pup() behavior.
Definition: pupper.h:17
PupPolicy begin(T &, const Meta &meta)
Definition: json-puppers.h:21
~JsonReader() override=default