AnyStruct
This is an intermediate example that takes advantage of the flexibility provided by the property system. FDcAnyStruct
is a struct that stores a heap allocated USTRUCT
of any type while maintaining value semantic on itself. If you're familiar with the concept of variant type, just think of it as a variant type that supports all USTRUCT
:
// DataConfigExtra/Private/DataConfig/Extra/SerDe/DcSerDeAnyStruct.cpp
// instantiate from heap allocated structs
FDcAnyStruct Any1 = new FDcExtraTestSimpleStruct1();
Any1.GetChecked<FDcExtraTestSimpleStruct1>()->NameField = TEXT("Foo");
// supports moving
FDcAnyStruct Any2 = MoveTemp(Any1);
check(!Any1.IsValid());
check(Any2.GetChecked<FDcExtraTestSimpleStruct1>()->NameField == TEXT("Foo"));
Any2.Reset();
// supports shared referencing
Any2 = new FDcExtraTestSimpleStruct2();
Any2.GetChecked<FDcExtraTestSimpleStruct2>()->StrField = TEXT("Bar");
Any1 = Any2;
check(Any1.DataPtr == Any2.DataPtr);
check(Any1.StructClass == Any2.StructClass);
We then implemented conversion logic between FDcAnyStruct
and JSON:
// DataConfigExtra/Public/DataConfig/Extra/SerDe/DcSerDeAnyStruct.h
USTRUCT()
struct FDcExtraTestWithAnyStruct1
{
GENERATED_BODY()
UPROPERTY() FDcAnyStruct AnyStructField1;
UPROPERTY() FDcAnyStruct AnyStructField2;
UPROPERTY() FDcAnyStruct AnyStructField3;
};
// DataConfigExtra/Private/DataConfig/Extra/SerDe/DcSerDeAnyStruct.cpp
FString Str = TEXT(R"(
{
"AnyStructField1" : {
"$type" : "DcExtraTestSimpleStruct1",
"NameField" : "Foo"
},
"AnyStructField2" : {
"$type" : "DcExtraTestStructWithColor1",
"ColorField1" : "#0000FFFF",
"ColorField2" : "#FF0000FF"
},
"AnyStructField3" : null
}
)");
Note how the custom FColor <-> "#RRGGBBAA"
conversion recursively works within FDcAnyStruct
. This should be a good starting point for you to implement your own nested variant types and containers. For more details refer to the implementation of HandlerDcAnyStruct[Serialize/Deserialize]
.