VariantSerialization.hpp
1 #pragma once
3 #include <score/serialization/JSONVisitor.hpp>
4 #include <score/tools/Metadata.hpp>
5 
6 #include <ossia/detail/for_each.hpp>
7 #include <ossia/detail/nullable_variant.hpp>
8 
39 template <typename T>
41 {
43  : s{s_p}
44  , var{var_p}
45  {
46  }
47 
49  const T& var;
50 
51  bool done = false;
52 
53  template <typename TheClass>
54  void operator()();
55 };
56 
57 template <typename T>
58 template <typename TheClass>
60 {
61  // This trickery iterates over all the types in Args...
62  // A single type should be serialized, even if we cannot break.
63  if(done)
64  return;
65  if(auto res = var.template target<TheClass>())
66  {
67  s.stream() << *res;
68  done = true;
69  }
70 }
71 
72 template <typename T>
74 {
75  VariantDataStreamDeserializer(DataStream::Deserializer& s_p, quint64 which_p, T& var_p)
76  : s{s_p}
77  , which{which_p}
78  , var{var_p}
79  {
80  }
81 
83  quint64 which;
84  T& var;
85 
86  quint64 i = 1; // 0 is the monostate / npos
87  template <typename TheClass>
88  void operator()();
89 };
90 
91 template <typename T>
92 template <typename TheClass>
94 {
95  // Here we iterate until we are on the correct type, and we deserialize it.
96  if(i++ != which)
97  return;
98 
99  TheClass data;
100  s.stream() >> data;
101  var = std::move(data);
102 }
103 
104 template <typename... Args>
105 struct TSerializer<DataStream, ossia::nullable_variant<Args...>>
106 {
107  using var_t = ossia::nullable_variant<Args...>;
108  static void readFrom(DataStream::Serializer& s, const var_t& var)
109  {
110  s.stream() << (quint64)var.which().index();
111 
112  // TODO this should be an assert.
113  if(var)
114  {
115  ossia::for_each_type<Args...>(VariantDataStreamSerializer<var_t>{s, var});
116  }
117 
118  s.insertDelimiter();
119  }
120 
121  static void writeTo(DataStream::Deserializer& s, var_t& var)
122  {
123  quint64 which;
124  s.stream() >> which;
125 
126  if(which != (quint64)var.npos.index())
127  {
128  ossia::for_each_type<Args...>(VariantDataStreamDeserializer<var_t>{s, which, var});
129  }
130  s.checkDelimiter();
131  }
132 };
133 
134 // This part is required because it isn't as straightforward to save variant
135 // data
136 // in JSON as it is to save it in a DataStream.
137 // Basically, each variant member has an associated name that will be the
138 // key in the JSON parent object. This name is defined by specializing
139 // template<> class Metadata<Json_k, T>.
140 // For instance:
141 // template<> class Metadata<Json_k, score::Address>
142 // { public: static constexpr const char * get() { return "Address"; } };
143 // A JSON_METADATA macro is provided for this.
144 
145 // This allows easy store and retrieval under a familiar name
146 
147 // TODO add some ASSERT for the variant being set on debug mode. npos case
148 // should not happen since we have the std::optionalVariant.
149 
150 template <typename T>
152 {
153  VariantJSONSerializer(JSONObject::Serializer& s_p, const T& var_p)
154  : s{s_p}
155  , var{var_p}
156  {
157  }
159  const T& var;
160 
161  bool done = false;
162 
163  template <typename TheClass>
164  void operator()();
165 };
166 
167 template <typename T>
168 template <typename TheClass>
170 {
171  if(done)
172  return;
173 
174  if(auto res = var.template target<TheClass>())
175  {
176  s.obj[Metadata<Json_k, TheClass>::get()] = *res;
177  done = true;
178  }
179 }
180 
181 template <typename T>
183 {
185  : s{s_p}
186  , var{var_p}
187  {
188  }
190  T& var;
191 
192  bool done = false;
193  template <typename TheClass>
194  void operator()();
195 };
196 
197 template <typename T>
198 template <typename TheClass>
200 {
201  if(done)
202  return;
203 
204  if(auto it = s.obj.tryGet(Metadata<Json_k, TheClass>::get()))
205  {
206  JSONWriter w{*it};
207  TheClass obj;
208  obj <<= JsonValue{w.base};
209  var = std::move(obj);
210  done = true;
211  }
212 }
213 
214 template <typename... Args>
215 struct TSerializer<JSONObject, ossia::nullable_variant<Args...>>
216 {
217  using var_t = ossia::nullable_variant<Args...>;
218  static void readFrom(JSONObject::Serializer& s, const var_t& var)
219  {
220  s.stream.StartObject();
221  if(var)
222  {
223  ossia::for_each_type<Args...>(VariantJSONSerializer<var_t>{s, var});
224  }
225  s.stream.EndObject();
226  }
227 
228  static void writeTo(JSONObject::Deserializer& s, var_t& var)
229  {
230  if(s.base.MemberCount() == 0)
231  return;
232  ossia::for_each_type<Args...>(VariantJSONDeserializer<var_t>{s, var});
233  }
234 };
Definition: VisitorInterface.hpp:53
Definition: DataStreamVisitor.hpp:27
Definition: DataStreamVisitor.hpp:202
Definition: VisitorInterface.hpp:61
Definition: JSONVisitor.hpp:52
Definition: JSONVisitor.hpp:423
Definition: JSONVisitor.hpp:372
Static metadata implementation.
Definition: lib/score/tools/Metadata.hpp:36
Definition: VisitorInterface.hpp:13
Definition: VariantSerialization.hpp:74
Definition: VariantSerialization.hpp:41
Definition: VariantSerialization.hpp:183
Definition: VariantSerialization.hpp:152