DataConfig Data Model
Conceptually the DataConfig data model is defined by 3 C++ types:
EDcDataEntry- enum covers every possible data type.FDcReader- methods to read from the data model.FDcWriter- methods to write into the data model.
And that's it. The obvious missing thing is a DOM like object that you can random access and serialize into - we choose to not implement that and it's crucial to understand this to get to know how DataConfig works.
EDcDataEntry
The enum covers all possible types:
// DataConfigCore/Public/DataConfig/DcTypes.h
UENUM()
enum class EDcDataEntry : uint16
{
None,
Bool,
Name,
String,
Text,
Enum,
Float,
Double,
Int8,
Int16,
Int32,
Int64,
UInt8,
UInt16,
UInt32,
UInt64,
// Struct
StructRoot,
StructEnd,
// Class
ClassRoot,
ClassEnd,
// Map
MapRoot,
MapEnd,
// Array
ArrayRoot,
ArrayEnd,
// Set,
SetRoot,
SetEnd,
// Optional
OptionalRoot,
OptionalEnd,
// Reference
ObjectReference,
ClassReference,
WeakObjectReference,
LazyObjectReference,
SoftObjectReference,
SoftClassReference,
InterfaceReference,
// Delegates
Delegate,
MulticastInlineDelegate,
MulticastSparseDelegate,
// Field
FieldPath,
// Extra
Blob,
// Extension
Extension,
// End
Ended,
};
Most enumerators directly maps to a FProperty type:
EDcDataEntry::Bool-FBoolPropertyEDcDataEntry::Name-FNamePropertyEDcDataEntry::String-FStrPropertyEDcDataEntry::ArrayRoot/ArrayEnd-FArrayProperty
It should've covered all possible FProperty types. There're some additions that has no direct FProperty mapping:
EDcDataEntry::None- It's mapsnullin JSON, and it's also used to explicitly represent null object reference.EDcDataEntry::Ended- It's a phony type that is returned when there's no more data or reader/writer is in a invalid state.EDcDataEntry::Blob- It's an extension to allow direct memory read/write from given fields.EDcDataEntry::Extension- It's an extension that allows additional data formats. MsgPack reader/writer uses this to support itsextensiondata types.
FDcReader
FDcReader is the one and only way to read from DataConfig data model. For every enumerator in EDcDataEntry there's a member method on FDcReader to from it.
Here we set up a simple struct trying out the reader methods:
// DataConfigTests/Private/DcTestBlurb.h
USTRUCT()
struct FDcTestExampleSimple
{
GENERATED_BODY()
UPROPERTY() FString StrField;
UPROPERTY() int IntField;
};
// DataConfigTests/Private/DcTestBlurb.cpp
FDcTestExampleSimple SimpleStruct;
SimpleStruct.StrField = TEXT("Foo Str");
SimpleStruct.IntField = 253;
Since we know exactly how the FDcTestExampleSimple looks like we can manually arrange the read calls:
// DataConfigTests/Private/DcTestBlurb.cpp
FDcPropertyReader Reader{FDcPropertyDatum(&SimpleStruct)};
DC_TRY(Reader.ReadStructRoot(&Struct)); // `FDcTestExampleSimple` Struct Root
DC_TRY(Reader.ReadName(&FieldName)); // 'StrField' as FName
DC_TRY(Reader.ReadString(&StrValue)); // "Foo Str"
DC_TRY(Reader.ReadName(&FieldName)); // 'IntField' as FName
DC_TRY(Reader.ReadInt32(&IntValue)); // 253
DC_TRY(Reader.ReadStructEnd(&Struct)); // `FDcTestExampleSimple` Struct Root
In the example above FDcReader behave like a iterator as each ReadXXX() call emits value and move the internal cursor into the next slot. In case we're reading a unknown structure, we can use FReader::PeekRead() to peek what's coming next.
FDcWriter
FDcWriter is the counter part of writing into the data config model. To write into the example instance above:
DC_TRY(Writer.WriteStructRoot(FDcStructStat{})); // `FDcTestExampleSimple` Struct Root
DC_TRY(Writer.WriteName(TEXT("StrField"))); // 'StrField' as FName
DC_TRY(Writer.WriteString(TEXT("Alt Str"))); // "Foo STr"
DC_TRY(Writer.WriteName(TEXT("IntField"))); // 'IntField' as FName
DC_TRY(Writer.WriteInt32(233)); // 233
DC_TRY(Writer.WriteStructEnd(FDcStructStat{})); // `FDcTestExampleSimple` Struct Root
There's also FDcWriter::PeekRead() to query whether it's possible to write given data type.
Sum Up
DataConfig provide FDcReader and FDcWriter to access the property system. It can be considered as a friendly alternative to the property system API. This is also how we support JSON and MsgPack in an uniform API.