template concept C_IsIntType = C_IsAnyOf; template concept C_IsFloatType = std::is_same_v; template concept C_IsSerializable = C_IsIntType || C_IsFloatType; struct FxSerializerValue { public: enum Type { eInt, eFloat, }; public: FxSerializerValue() = delete; template requires C_IsIntType explicit FxSerializerValue(T value) : Type(eInt), IntValue(value) { } template requires C_IsFloatType explicit FxSerializerValue(T value) : Type(eFloat), FloatValue(value) { } public: Type Type; union { int64 IntValue; float32 FloatValue; }; }; class FxSerializer { public: FxSerializer() { Values.Create(16); } FxSerializer(const FxSerializer& other) = delete; template requires C_IsSerializable FxSerializer& operator<<(T value) { Values.Insert(FxSerializerValue { value }); return *this; } template requires C_IsSerializable FxSerializer& Add(T& member) { if (bInWriteMode) { (*this) << member; } else { (*this) >> member; } return *this; } void SetWriteMode() { bInWriteMode = true; } void SetReadMode() { bInWriteMode = false; } template requires C_IsSerializable FxSerializer& operator>>(T& value) { if (WriteIndex > Values.Size()) { return *this; } FxSerializerValue& stored_value = Values[WriteIndex++]; if constexpr (C_IsIntType) { value = stored_value.IntValue; } else if constexpr (C_IsFloatType) { value = stored_value.FloatValue; } return *this; } void Rewind() { WriteIndex = 0; } public: int WriteIndex = 0; FxPagedArray Values; bool bInWriteMode = true; }; #define FX_SERIALIZABLE_MEMBERS(...) \ template \ void SerializerDefineRecursive(FxSerializer& s, TMemberTypes&... types) \ { \ (s.Add(types), ...); \ } \ void SerializeNow(FxSerializer& s) { SerializerDefineRecursive(s, __VA_ARGS__); } \ void Serialize(FxSerializer& s) \ { \ s.SetWriteMode(); \ SerializeNow(s); \ } \ void Deserialize(FxSerializer& s) \ { \ s.SetReadMode(); \ SerializeNow(s); \ } struct SerializeTest { FX_SERIALIZABLE_MEMBERS(X, Y); void Print() { FxLogInfo("Object: [{}, {}]", X, Y); } float X = 0; int Y = 0; };