OpenShot Audio Library | OpenShotAudio 0.4.0
Loading...
Searching...
No Matches
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
23namespace juce
24{
25
34{
35public:
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
56private:
57 std::optional<std::optional<int>> explicitVersion;
58 bool versionIncluded = true;
59};
60
76class ToVar
77{
78public:
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
92private:
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//==============================================================================
260{
261public:
266 template <typename T>
267 static std::optional<T> convert (const var& v)
268 {
269 return Visitor::convert<T> (v);
270 }
271
272private:
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//==============================================================================
476template <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
492template <>
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
514template <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={})
Array< var > * getArray() const noexcept