| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2022 - Raw Material Software Limited
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    The code included in this file is provided under the terms of the ISC license
 -    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 -    To use, copy, modify, and/or distribute this software for any purpose with or
 -    without fee is hereby granted provided that the above copyright notice and
 -    this permission notice appear in all copies.
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace juce
 - {
 - 
 - /**
 -     Options that control conversion from arbitrary types to juce::var.
 - 
 -     @see ToVar
 - 
 -     @tags{Core}
 - */
 - class ToVarOptions
 - {
 - public:
 -     /** By default, conversion will serialise the type using the marshallingVersion defined for
 -         that type. Setting an explicit version allows the type to be serialised as an earlier
 -         version.
 -     */
 -     [[nodiscard]] ToVarOptions withExplicitVersion (std::optional<int> x) const { return withMember (*this, &ToVarOptions::explicitVersion, x); }
 - 
 -     /** By default, conversion will include version information for any type with a non-null
 -         marshallingVersion. Setting versionIncluded to false will cause the version info to be
 -         omitted, which is useful in situations where the version information is not needed
 -         (e.g. when presenting transient information to the user, rather than writing data to
 -         disk that must be deserialised in the future).
 -     */
 -     [[nodiscard]] ToVarOptions withVersionIncluded (bool x)               const { return withMember (*this, &ToVarOptions::versionIncluded, x); }
 - 
 -     /** @see withExplicitVersion() */
 -     [[nodiscard]] auto getExplicitVersion() const { return explicitVersion; }
 - 
 -     /** @see withVersionIncluded(). */
 -     [[nodiscard]] auto getVersionIncluded() const { return versionIncluded; }
 - 
 - private:
 -     std::optional<std::optional<int>> explicitVersion;
 -     bool versionIncluded = true;
 - };
 - 
 - /**
 -     Allows converting an object of arbitrary type to var.
 - 
 -     To use this, you must first ensure that the type passed to convert is set up for serialisation.
 -     For details of what this entails, see the docs for SerialisationTraits.
 - 
 -     In short, the constant 'marshallingVersion', and either the single function 'serialise()', or
 -     the function pair 'load()' and 'save()' must be defined for the type. These may be defined
 -     as public members of the type T itself, or as public members of juce::SerialisationTraits<T>,
 -     which is a specialisation of the SerialisationTraits template struct for the type T.
 - 
 -     @see FromVar
 - 
 -     @tags{Core}
 - */
 - class ToVar
 - {
 - public:
 -     using Options = ToVarOptions;
 - 
 -     /** Attempts to convert the argument to a var using the serialisation utilities specified for
 -         that type.
 - 
 -         This will return a non-null optional if conversion succeeds, or nullopt if conversion fails.
 -     */
 -     template <typename T>
 -     static std::optional<var> convert (const T& t, const Options& options = {})
 -     {
 -         return Visitor::convert (t, options);
 -     }
 - 
 - private:
 -     class Visitor
 -     {
 -     public:
 -         template <typename T>
 -         static std::optional<var> convert (const T& t, const Options& options)
 -         {
 -             constexpr auto fallbackVersion = detail::ForwardingSerialisationTraits<T>::marshallingVersion;
 -             const auto versionToUse = options.getExplicitVersion()
 -                                              .value_or (fallbackVersion);
 - 
 -             if (versionToUse > fallbackVersion)
 -             {
 -                 // The requested explicit version is higher than the declared version of the type.
 -                 return std::nullopt;
 -             }
 - 
 -             Visitor visitor { versionToUse, options.getVersionIncluded() };
 -             detail::doSave (visitor, t);
 -             return visitor.value;
 -         }
 - 
 -         std::optional<int> getVersion() const { return version; }
 - 
 -         template <typename... Ts>
 -         void operator() (Ts&&... ts)
 -         {
 -             (visit (std::forward<Ts> (ts)), ...);
 -         }
 - 
 -     private:
 -         Visitor (const std::optional<int>& explicitVersion, bool includeVersion)
 -             : version (explicitVersion),
 -               value ([&]() -> var
 -               {
 -                   if (! (version.has_value() && includeVersion))
 -                       return var();
 - 
 -                   auto obj = std::make_unique<DynamicObject>();
 -                   obj->setProperty ("__version__", *version);
 -                   return obj.release();
 -               }()),
 -               versionIncluded (includeVersion) {}
 - 
 -         template <typename T>
 -         void visit (const T& t)
 -         {
 -             if constexpr (std::is_integral_v<T>)
 -             {
 -                 push ((int64) t);
 -             }
 -             else if constexpr (std::is_floating_point_v<T>)
 -             {
 -                 push ((double) t);
 -             }
 -             else if (auto converted = convert (t))
 -             {
 -                 push (*converted);
 -             }
 -             else
 -             {
 -                 value.reset();
 -             }
 -         }
 - 
 -         template <typename T>
 -         void visit (const Named<T>& named)
 -         {
 -             if (! value.has_value())
 -                 return;
 - 
 -             if (value == var())
 -                 value = new DynamicObject;
 - 
 -             auto* obj = value->getDynamicObject();
 - 
 -             if (obj == nullptr)
 -             {
 -                 // Serialisation failure! This may be caused by archiving a primitive or
 -                 // SerialisationSize, and then attempting to archive a named pair to the same
 -                 // archive instance.
 -                 // When using named pairs, *all* items serialised with a particular archiver must be
 -                 // named pairs.
 -                 jassertfalse;
 - 
 -                 value.reset();
 -                 return;
 -             }
 - 
 -             if (! trySetProperty (*obj, named))
 -                 value.reset();
 -         }
 - 
 -         template <typename T>
 -         void visit (const SerialisationSize<T>&)
 -         {
 -             push (Array<var>{});
 -         }
 - 
 -         void visit (const bool& t)
 -         {
 -             push (t);
 -         }
 - 
 -         void visit (const String& t)
 -         {
 -             push (t);
 -         }
 - 
 -         void visit (const var& t)
 -         {
 -             push (t);
 -         }
 - 
 -         template <typename T>
 -         std::optional<var> convert (const T& t)
 -         {
 -             return convert (t, Options{}.withVersionIncluded (versionIncluded));
 -         }
 - 
 -         void push (var v)
 -         {
 -             if (! value.has_value())
 -                 return;
 - 
 -             if (*value == var())
 -                 *value = v;
 -             else if (auto* array = value->getArray())
 -                 array->add (v);
 -             else
 -                 value.reset();
 -         }
 - 
 -         template <typename T>
 -         bool trySetProperty (DynamicObject& obj, const Named<T>& n)
 -         {
 -             if (const auto converted = convert (n.value))
 -             {
 -                 obj.setProperty (Identifier (std::string (n.name)), *converted);
 -                 return true;
 -             }
 - 
 -             return false;
 -         }
 - 
 -         std::optional<int> version;
 -         std::optional<var> value;
 -         bool versionIncluded = true;
 -     };
 - };
 - 
 - //==============================================================================
 - /**
 -     Allows converting a var to an object of arbitrary type.
 - 
 -     To use this, you must first ensure that the type passed to convert is set up for serialisation.
 -     For details of what this entails, see the docs for SerialisationTraits.
 - 
 -     In short, the constant 'marshallingVersion', and either the single function 'serialise()', or
 -     the function pair 'load()' and 'save()' must be defined for the type. These may be defined
 -     as public members of the type T itself, or as public members of juce::SerialisationTraits<T>,
 -     which is a specialisation of the SerialisationTraits template struct for the type T.
 - 
 -     @see ToVar
 - 
 -     @tags{Core}
 - */
 - class FromVar
 - {
 - public:
 -     /** Attempts to convert a var to an instance of type T.
 - 
 -         This will return a non-null optional if conversion succeeds, or nullopt if conversion fails.
 -     */
 -     template <typename T>
 -     static std::optional<T> convert (const var& v)
 -     {
 -         return Visitor::convert<T> (v);
 -     }
 - 
 - private:
 -     class Visitor
 -     {
 -     public:
 -         template <typename T>
 -         static std::optional<T> convert (const var& v)
 -         {
 -             const auto version = [&]() -> std::optional<int>
 -             {
 -                 if (auto* obj = v.getDynamicObject())
 -                     if (obj->hasProperty ("__version__"))
 -                         return (int) obj->getProperty ("__version__");
 - 
 -                 return std::nullopt;
 -             }();
 - 
 -             Visitor visitor { version, v };
 -             T t{};
 -             detail::doLoad (visitor, t);
 -             return ! visitor.failed ? std::optional<T> (std::move (t))
 -                                     : std::nullopt;
 -         }
 - 
 -         std::optional<int> getVersion() const { return version; }
 - 
 -         template <typename... Ts>
 -         void operator() (Ts&&... ts)
 -         {
 -             (visit (std::forward<Ts> (ts)), ...);
 -         }
 - 
 -     private:
 -         Visitor (std::optional<int> vn, const var& i)
 -             : version (vn), input (i) {}
 - 
 -         template <typename T>
 -         void visit (T& t)
 -         {
 -             if constexpr (std::is_integral_v<T>)
 -             {
 -                 readPrimitive (std::in_place_type<int64>, t);
 -             }
 -             else if constexpr (std::is_floating_point_v<T>)
 -             {
 -                 readPrimitive (std::in_place_type<double>, t);
 -             }
 -             else
 -             {
 -                 auto node = getNodeToRead();
 - 
 -                 if (! node.has_value())
 -                     return;
 - 
 -                 auto converted = convert<T> (*node);
 - 
 -                 if (converted.has_value())
 -                     t = *converted;
 -                 else
 -                     failed = true;
 -             }
 -         }
 - 
 -         template <typename T>
 -         void visit (const Named<T>& named)
 -         {
 -             auto node = getNodeToRead();
 - 
 -             if (! node.has_value())
 -                 return;
 - 
 -             auto* obj = node->getDynamicObject();
 - 
 -             failed = obj == nullptr || ! tryGetProperty (*obj, named);
 -         }
 - 
 -         template <typename T>
 -         void visit (const SerialisationSize<T>& t)
 -         {
 -             if (failed)
 -                 return;
 - 
 -             if (auto* array = input.getArray())
 -             {
 -                 t.size = static_cast<T> (array->size());
 -                 currentArrayIndex = 0;
 -             }
 -             else
 -             {
 -                 failed = true;
 -             }
 -         }
 - 
 -         void visit (bool& t)
 -         {
 -             readPrimitive (std::in_place_type<bool>, t);
 -         }
 - 
 -         void visit (String& t)
 -         {
 -             readPrimitive (std::in_place_type<String>, t);
 -         }
 - 
 -         void visit (var& t)
 -         {
 -             t = input;
 -         }
 - 
 -         static std::optional<double> pullTyped (std::in_place_type_t<double>, const var& source)
 -         {
 -             return source.isDouble() ? std::optional<double> ((double) source) : std::nullopt;
 -         }
 - 
 -         static std::optional<int64> pullTyped (std::in_place_type_t<int64>, const var& source)
 -         {
 -             return source.isInt() || source.isInt64() ? std::optional<int64> ((int64) source) : std::nullopt;
 -         }
 - 
 -         static std::optional<bool> pullTyped (std::in_place_type_t<bool>, const var& source)
 -         {
 -             return std::optional<bool> ((bool) source);
 -         }
 - 
 -         static std::optional<String> pullTyped (std::in_place_type_t<String>, const var& source)
 -         {
 -             return source.isString() ? std::optional<String> (source.toString()) : std::nullopt;
 -         }
 - 
 -         std::optional<var> getNodeToRead()
 -         {
 -             if (failed)
 -                 return std::nullopt;
 - 
 -             if (currentArrayIndex == std::numeric_limits<size_t>::max())
 -                 return input;
 - 
 -             const auto* array = input.getArray();
 - 
 -             if (array == nullptr)
 -                 return input;
 - 
 -             if ((int) currentArrayIndex < array->size())
 -                 return array->getReference ((int) currentArrayIndex++);
 - 
 -             failed = true;
 -             return std::nullopt;
 -         }
 - 
 -         template <typename TypeToRead, typename T>
 -         void readPrimitive (std::in_place_type_t<TypeToRead> tag, T& t)
 -         {
 -             auto node = getNodeToRead();
 - 
 -             if (! node.has_value())
 -                 return;
 - 
 -             auto typed = pullTyped (tag, *node);
 - 
 -             if (typed.has_value())
 -                 t = static_cast<T> (*typed);
 -             else
 -                 failed = true;
 -         }
 - 
 -         template <typename T>
 -         static bool tryGetProperty (const DynamicObject& obj, const Named<T>& n)
 -         {
 -             const Identifier identifier (String (n.name.data(), n.name.size()));
 - 
 -             if (! obj.hasProperty (identifier))
 -                 return false;
 - 
 -             const auto converted = convert<T> (obj.getProperty (identifier));
 - 
 -             if (! converted.has_value())
 -                 return false;
 - 
 -             n.value = *converted;
 -             return true;
 -         }
 - 
 -         std::optional<int> version;
 -         var input;
 -         size_t currentArrayIndex = std::numeric_limits<size_t>::max();
 -         bool failed = false;
 -     };
 - };
 - 
 - //==============================================================================
 - /**
 -     This template-overloaded class can be used to convert between var and custom types.
 - 
 -     If not specialised, the variant converter will attempt to use serialisation functions
 -     if they are detected for the given type.
 -     For details of what this entails, see the docs for SerialisationTraits.
 - 
 -     In short, the constant 'marshallingVersion', and either the single function 'serialise()', or
 -     the function pair 'load()' and 'save()' must be defined for the type. These may be defined
 -     as public members of the type T itself, or as public members of juce::SerialisationTraits<T>,
 -     which is a specialisation of the SerialisationTraits template struct for the type T.
 - 
 -     @see ToVar, FromVar
 - 
 -     @tags{Core}
 - */
 - template <typename Type>
 - struct VariantConverter
 - {
 -     static Type fromVar (const var& v)
 -     {
 -         return static_cast<Type> (v);
 -     }
 - 
 -     static var toVar (const Type& t)
 -     {
 -         return t;
 -     }
 - };
 - 
 - #ifndef DOXYGEN
 - 
 - template <>
 - struct VariantConverter<String>
 - {
 -     static String fromVar (const var& v)           { return v.toString(); }
 -     static var toVar (const String& s)             { return s; }
 - };
 - 
 - #endif
 - 
 - /**
 -     A helper type that can be used to implement specialisations of VariantConverter that use
 -     FromVar::convert and ToVar::convert internally.
 - 
 -     If you've already implemented SerialisationTraits for a specific type, and don't want to write
 -     a custom VariantConverter that duplicates that implementation, you can instead write:
 -     @code
 -     template <>
 -     struct juce::VariantConverter<MyType> : public juce::StrictVariantConverter<MyType> {};
 -     @endcode
 - 
 -     @tags{Core}
 - */
 - template <typename Type>
 - struct StrictVariantConverter
 - {
 -     static_assert (detail::serialisationKind<Type> != detail::SerialisationKind::none);
 - 
 -     static Type fromVar (const var& v)
 -     {
 -         auto converted = FromVar::convert<Type> (v);
 -         jassert (converted.has_value());
 -         return std::move (converted).value_or (Type{});
 -     }
 - 
 -     static var toVar (const Type& t)
 -     {
 -         auto converted = ToVar::convert<> (t);
 -         jassert (converted.has_value());
 -         return std::move (converted).value_or (var{});
 -     }
 - };
 - 
 - } // namespace juce
 
 
  |