OpenShot Audio Library | OpenShotAudio  0.6.0
juce_JSONSerialisation.h
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2022 - Raw Material Software Limited
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
34 {
35 public:
40  [[nodiscard]] ToVarOptions withExplicitVersion (std::optional<int> x) const { return withMember (*this, &ToVarOptions::explicitVersion, x); }
41 
48  [[nodiscard]] ToVarOptions withVersionIncluded (bool x) const { return withMember (*this, &ToVarOptions::versionIncluded, x); }
49 
51  [[nodiscard]] auto getExplicitVersion() const { return explicitVersion; }
52 
54  [[nodiscard]] auto getVersionIncluded() const { return versionIncluded; }
55 
56 private:
57  std::optional<std::optional<int>> explicitVersion;
58  bool versionIncluded = true;
59 };
60 
76 class ToVar
77 {
78 public:
79  using Options = ToVarOptions;
80 
86  template <typename T>
87  static std::optional<var> convert (const T& t, const Options& options = {})
88  {
89  return Visitor::convert (t, options);
90  }
91 
92 private:
93  class Visitor
94  {
95  public:
96  template <typename T>
97  static std::optional<var> convert (const T& t, const Options& options)
98  {
99  constexpr auto fallbackVersion = detail::ForwardingSerialisationTraits<T>::marshallingVersion;
100  const auto versionToUse = options.getExplicitVersion()
101  .value_or (fallbackVersion);
102 
103  if (versionToUse > fallbackVersion)
104  {
105  // The requested explicit version is higher than the declared version of the type.
106  return std::nullopt;
107  }
108 
109  Visitor visitor { versionToUse, options.getVersionIncluded() };
110  detail::doSave (visitor, t);
111  return visitor.value;
112  }
113 
114  std::optional<int> getVersion() const { return version; }
115 
116  template <typename... Ts>
117  void operator() (Ts&&... ts)
118  {
119  (visit (std::forward<Ts> (ts)), ...);
120  }
121 
122  private:
123  Visitor (const std::optional<int>& explicitVersion, bool includeVersion)
124  : version (explicitVersion),
125  value ([&]() -> var
126  {
127  if (! (version.has_value() && includeVersion))
128  return var();
129 
130  auto obj = std::make_unique<DynamicObject>();
131  obj->setProperty ("__version__", *version);
132  return obj.release();
133  }()),
134  versionIncluded (includeVersion) {}
135 
136  template <typename T>
137  void visit (const T& t)
138  {
139  if constexpr (std::is_integral_v<T>)
140  {
141  push ((int64) t);
142  }
143  else if constexpr (std::is_floating_point_v<T>)
144  {
145  push ((double) t);
146  }
147  else if (auto converted = convert (t))
148  {
149  push (*converted);
150  }
151  else
152  {
153  value.reset();
154  }
155  }
156 
157  template <typename T>
158  void visit (const Named<T>& named)
159  {
160  if (! value.has_value())
161  return;
162 
163  if (value == var())
164  value = new DynamicObject;
165 
166  auto* obj = value->getDynamicObject();
167 
168  if (obj == nullptr)
169  {
170  // Serialisation failure! This may be caused by archiving a primitive or
171  // SerialisationSize, and then attempting to archive a named pair to the same
172  // archive instance.
173  // When using named pairs, *all* items serialised with a particular archiver must be
174  // named pairs.
175  jassertfalse;
176 
177  value.reset();
178  return;
179  }
180 
181  if (! trySetProperty (*obj, named))
182  value.reset();
183  }
184 
185  template <typename T>
186  void visit (const SerialisationSize<T>&)
187  {
188  push (Array<var>{});
189  }
190 
191  void visit (const bool& t)
192  {
193  push (t);
194  }
195 
196  void visit (const String& t)
197  {
198  push (t);
199  }
200 
201  void visit (const var& t)
202  {
203  push (t);
204  }
205 
206  template <typename T>
207  std::optional<var> convert (const T& t)
208  {
209  return convert (t, Options{}.withVersionIncluded (versionIncluded));
210  }
211 
212  void push (var v)
213  {
214  if (! value.has_value())
215  return;
216 
217  if (*value == var())
218  *value = v;
219  else if (auto* array = value->getArray())
220  array->add (v);
221  else
222  value.reset();
223  }
224 
225  template <typename T>
226  bool trySetProperty (DynamicObject& obj, const Named<T>& n)
227  {
228  if (const auto converted = convert (n.value))
229  {
230  obj.setProperty (Identifier (std::string (n.name)), *converted);
231  return true;
232  }
233 
234  return false;
235  }
236 
237  std::optional<int> version;
238  std::optional<var> value;
239  bool versionIncluded = true;
240  };
241 };
242 
243 //==============================================================================
259 class FromVar
260 {
261 public:
266  template <typename T>
267  static std::optional<T> convert (const var& v)
268  {
269  return Visitor::convert<T> (v);
270  }
271 
272 private:
273  class Visitor
274  {
275  public:
276  template <typename T>
277  static std::optional<T> convert (const var& v)
278  {
279  const auto version = [&]() -> std::optional<int>
280  {
281  if (auto* obj = v.getDynamicObject())
282  if (obj->hasProperty ("__version__"))
283  return (int) obj->getProperty ("__version__");
284 
285  return std::nullopt;
286  }();
287 
288  Visitor visitor { version, v };
289  T t{};
290  detail::doLoad (visitor, t);
291  return ! visitor.failed ? std::optional<T> (std::move (t))
292  : std::nullopt;
293  }
294 
295  std::optional<int> getVersion() const { return version; }
296 
297  template <typename... Ts>
298  void operator() (Ts&&... ts)
299  {
300  (visit (std::forward<Ts> (ts)), ...);
301  }
302 
303  private:
304  Visitor (std::optional<int> vn, const var& i)
305  : version (vn), input (i) {}
306 
307  template <typename T>
308  void visit (T& t)
309  {
310  if constexpr (std::is_integral_v<T>)
311  {
312  readPrimitive (std::in_place_type<int64>, t);
313  }
314  else if constexpr (std::is_floating_point_v<T>)
315  {
316  readPrimitive (std::in_place_type<double>, t);
317  }
318  else
319  {
320  auto node = getNodeToRead();
321 
322  if (! node.has_value())
323  return;
324 
325  auto converted = convert<T> (*node);
326 
327  if (converted.has_value())
328  t = *converted;
329  else
330  failed = true;
331  }
332  }
333 
334  template <typename T>
335  void visit (const Named<T>& named)
336  {
337  auto node = getNodeToRead();
338 
339  if (! node.has_value())
340  return;
341 
342  auto* obj = node->getDynamicObject();
343 
344  failed = obj == nullptr || ! tryGetProperty (*obj, named);
345  }
346 
347  template <typename T>
348  void visit (const SerialisationSize<T>& t)
349  {
350  if (failed)
351  return;
352 
353  if (auto* array = input.getArray())
354  {
355  t.size = static_cast<T> (array->size());
356  currentArrayIndex = 0;
357  }
358  else
359  {
360  failed = true;
361  }
362  }
363 
364  void visit (bool& t)
365  {
366  readPrimitive (std::in_place_type<bool>, t);
367  }
368 
369  void visit (String& t)
370  {
371  readPrimitive (std::in_place_type<String>, t);
372  }
373 
374  void visit (var& t)
375  {
376  t = input;
377  }
378 
379  static std::optional<double> pullTyped (std::in_place_type_t<double>, const var& source)
380  {
381  return source.isDouble() ? std::optional<double> ((double) source) : std::nullopt;
382  }
383 
384  static std::optional<int64> pullTyped (std::in_place_type_t<int64>, const var& source)
385  {
386  return source.isInt() || source.isInt64() ? std::optional<int64> ((int64) source) : std::nullopt;
387  }
388 
389  static std::optional<bool> pullTyped (std::in_place_type_t<bool>, const var& source)
390  {
391  return std::optional<bool> ((bool) source);
392  }
393 
394  static std::optional<String> pullTyped (std::in_place_type_t<String>, const var& source)
395  {
396  return source.isString() ? std::optional<String> (source.toString()) : std::nullopt;
397  }
398 
399  std::optional<var> getNodeToRead()
400  {
401  if (failed)
402  return std::nullopt;
403 
404  if (currentArrayIndex == std::numeric_limits<size_t>::max())
405  return input;
406 
407  const auto* array = input.getArray();
408 
409  if (array == nullptr)
410  return input;
411 
412  if ((int) currentArrayIndex < array->size())
413  return array->getReference ((int) currentArrayIndex++);
414 
415  failed = true;
416  return std::nullopt;
417  }
418 
419  template <typename TypeToRead, typename T>
420  void readPrimitive (std::in_place_type_t<TypeToRead> tag, T& t)
421  {
422  auto node = getNodeToRead();
423 
424  if (! node.has_value())
425  return;
426 
427  auto typed = pullTyped (tag, *node);
428 
429  if (typed.has_value())
430  t = static_cast<T> (*typed);
431  else
432  failed = true;
433  }
434 
435  template <typename T>
436  static bool tryGetProperty (const DynamicObject& obj, const Named<T>& n)
437  {
438  const Identifier identifier (String (n.name.data(), n.name.size()));
439 
440  if (! obj.hasProperty (identifier))
441  return false;
442 
443  const auto converted = convert<T> (obj.getProperty (identifier));
444 
445  if (! converted.has_value())
446  return false;
447 
448  n.value = *converted;
449  return true;
450  }
451 
452  std::optional<int> version;
453  var input;
454  size_t currentArrayIndex = std::numeric_limits<size_t>::max();
455  bool failed = false;
456  };
457 };
458 
459 //==============================================================================
476 template <typename Type>
478 {
479  static Type fromVar (const var& v)
480  {
481  return static_cast<Type> (v);
482  }
483 
484  static var toVar (const Type& t)
485  {
486  return t;
487  }
488 };
489 
490 #ifndef DOXYGEN
491 
492 template <>
493 struct VariantConverter<String>
494 {
495  static String fromVar (const var& v) { return v.toString(); }
496  static var toVar (const String& s) { return s; }
497 };
498 
499 #endif
500 
514 template <typename Type>
516 {
517  static_assert (detail::serialisationKind<Type> != detail::SerialisationKind::none);
518 
519  static Type fromVar (const var& v)
520  {
521  auto converted = FromVar::convert<Type> (v);
522  jassert (converted.has_value());
523  return std::move (converted).value_or (Type{});
524  }
525 
526  static var toVar (const Type& t)
527  {
528  auto converted = ToVar::convert<> (t);
529  jassert (converted.has_value());
530  return std::move (converted).value_or (var{});
531  }
532 };
533 
534 } // namespace juce
static std::optional< T > convert(const var &v)
ToVarOptions withVersionIncluded(bool x) const
ToVarOptions withExplicitVersion(std::optional< int > x) const
static std::optional< var > convert(const T &t, const Options &options={})