// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "WebAPIJsonUtilities.h" namespace UE::Json { // Numeric template constexpr typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { return InJsonValue->TryGetNumber(OutValue); } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ValueType& OutValue) { return InJsonObject->TryGetNumberField(InFieldName, OutValue); } // Enum template typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, EnumType& OutValue, const TMap& InNameToValue) { // Try int first uint8 IntValue; bool bResult = InJsonValue->TryGetNumber(IntValue); if(bResult) { OutValue = StaticCast(IntValue); } else { if(InNameToValue.IsEmpty()) { UE_LOG(LogWebAPIEditor, Error, TEXT("Tried to convert enum from string, but no lookup was provided.")); return bResult; } FString StrValue; bResult = InJsonValue->TryGetString(StrValue); if(bResult) { if(const EnumType* NameToValue = InNameToValue.Find(StrValue)) { OutValue = *NameToValue; } } } return bResult; } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, EnumType& OutValue, const TMap& InNameToValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue.Get(), InNameToValue); } return false; } // String template constexpr typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { return InJsonValue->TryGetString(OutValue); } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ValueType& OutValue) { return InJsonObject->TryGetStringField(InFieldName, OutValue); } // Bool template constexpr typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { return InJsonValue->TryGetBool(OutValue); } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ValueType& OutValue) { return InJsonObject->TryGetBoolField(InFieldName, OutValue); } // Array template typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ContainerType& OutValues) { using ValueType = typename ContainerType::ElementType; const TArray>* Values = nullptr; if(InJsonValue->TryGetArray(Values)) { bool bSuccess = true; if(Values->Num() > 0) { OutValues.Reserve(Values->Num()); for(const TSharedPtr& JsonValue : *Values) { ValueType& Value = OutValues.Emplace_GetRef(); bSuccess &= TryGet(JsonValue, Value); } } return bSuccess; } return false; } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ContainerType& OutValues) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { using ValueType = typename ContainerType::ElementType; return TryGet(JsonField, OutValues); } return false; } // Map template typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, TMap& OutValues) { const TSharedPtr* JsonObject = nullptr; if(InJsonValue->TryGetObject(JsonObject)) { OutValues.Reserve(JsonObject->Get()->Values.Num()); for(TPair>& FieldValuePair : JsonObject->Get()->Values) { ValueType& ItemValue = OutValues.Emplace(MoveTemp(FieldValuePair.Key)); TryGet(FieldValuePair.Value, ItemValue); } return true; } return false; } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TMap& OutValues) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValues); } return false; } // Optional template constexpr typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, TOptional& OutValue) { ValueType Value; if(TryGet>(InJsonValue, Value)) { OutValue = Value; return true; } return true; } template typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TOptional& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { if(!OutValue.IsSet()) { OutValue = ValueType{}; } return TryGet(JsonField, OutValue.GetValue()); } return true; } // Optional Enum template constexpr typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, TOptional& OutValue, const TMap& InNameToValue) { EnumType Value; if(TryGet>(InJsonValue, Value, InNameToValue)) { OutValue = Value; return true; } return true; } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TOptional& OutValue, const TMap& InNameToValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { if(!OutValue.IsSet()) { OutValue = EnumType{}; } return TryGet(JsonField, OutValue.GetValue(), InNameToValue); } return true; } // Object (with FromJson) template typename TEnableIf< TAnd< TNot>, TypeTraits::THasFromJson>::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { const TSharedPtr* Value; if(InJsonValue->TryGetObject(Value)) { return OutValue.FromJson(Value->ToSharedRef()); } return false; } template typename TEnableIf< TAnd< TNot>, TypeTraits::THasFromJson>::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ValueType& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return false; } // Object (without FromJson) template typename TEnableIf< TAnd< TNot>, TNot>, TNot>, TNot>>::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { static_assert(TypeTraits::THasFromJson::Value, "ValueType must implement FromJson"); return false; } // TIsTMap, template typename TEnableIf< TAnd< TNot>, TNot>, TNot>, TNot>>::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ValueType& OutValue) { static_assert(TypeTraits::THasFromJson::Value, "ValueType must implement FromJson"); return false; } // UniqueObj template bool TryGet(const TSharedPtr& InJsonValue, TUniqueObj& OutValue) { return Json::TryGet(InJsonValue, OutValue.Get()); } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TUniqueObj& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue.Get()); } return false; } // TJsonReference template bool TryGet(const TSharedPtr& InJsonValue, TJsonReference& OutValue) { const TSharedPtr* JsonObject = nullptr; if(InJsonValue->TryGetObject(JsonObject)) { FString ReferencePath; if(JsonObject->Get()->TryGetStringField(TEXT("$ref"), ReferencePath)) { OutValue.ResolveDeferred(ReferencePath); return true; } } return Json::TryGet(InJsonValue, *OutValue.Get()); } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TJsonReference& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return false; } // SharedPtr template bool TryGet(const TSharedPtr& InJsonValue, TSharedPtr& OutValue) { // Initialize if invalid if(!OutValue.IsValid()) { OutValue = MakeShared(); } return Json::TryGet(InJsonValue, *OutValue.Get()); } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TSharedPtr& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return false; } // SharedRef template bool TryGet(const TSharedPtr& InJsonValue, TSharedRef& OutValue) { return Json::TryGet(InJsonValue, OutValue.Get()); } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TSharedRef& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return false; } // Optional UniqueObj template bool TryGet(const TSharedPtr& InJsonValue, TOptional>& OutValue) { if(OutValue.IsSet()) { TUniqueObj& Value = OutValue.GetValue(); if(TryGet(InJsonValue, OutValue.GetValue())) { OutValue = Value; return true; } } else { TUniqueObj Value; if(TryGet(InJsonValue, Value)) { OutValue = Value; return true; } } return true; } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TOptional>& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return true; } // Optional SharedRef template bool TryGet(const TSharedPtr& InJsonValue, TOptional>& OutValue) { TSharedRef Value = MakeShared(); if(TryGet(InJsonValue, Value)) { OutValue = Value; return true; } return true; } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TOptional>& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return true; } // JsonObject template bool TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { const TSharedPtr* Value = nullptr; if(InJsonValue->TryGetObject(Value)) { OutValue = *Value; return true; } return false; } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TSharedPtr& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet<>(JsonField, OutValue); } return false; } // Variant template bool TryGet(const TSharedPtr& InJsonValue, TVariant& OutValue) { FVariantValueVisitor Visitor(InJsonValue); // @todo: asked Stefan Boberg about this, only ever tests a single type return Visit(Visitor, OutValue); } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TVariant& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return false; } }