(WIP) Some reflection stuff.
This commit is contained in:
247
source/serialization.cpp
Normal file
247
source/serialization.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
#include "iwa/serialization.hpp"
|
||||
|
||||
namespace iwa
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void propertyToYAML(const void* data, const iwa::Type& type, YAML::Emitter& emitter);
|
||||
void propertyFromYAML(void* data, const iwa::Type& type, const YAML::Node& node);
|
||||
|
||||
struct PropertyEmitVisitor
|
||||
{
|
||||
const void* data;
|
||||
YAML::Emitter& emitter;
|
||||
|
||||
void operator()(const VoidType&)
|
||||
{
|
||||
emitter << YAML::Null;
|
||||
}
|
||||
|
||||
void operator()(const BoolType&)
|
||||
{
|
||||
emitter << *static_cast<const bool*>(data);
|
||||
}
|
||||
|
||||
void operator()(const IntType& type)
|
||||
{
|
||||
visitIntValue([&](auto&& value)
|
||||
{
|
||||
emitter << value;
|
||||
}, data, type);
|
||||
}
|
||||
|
||||
void operator()(const FloatType& type)
|
||||
{
|
||||
visitFloatValue([&](auto&& value)
|
||||
{
|
||||
emitter << value;
|
||||
}, data, type);
|
||||
}
|
||||
|
||||
void operator()(const CharType& type)
|
||||
{
|
||||
visitCharValue([&](auto&& value)
|
||||
{
|
||||
emitter << value;
|
||||
}, data, type);
|
||||
}
|
||||
|
||||
void operator()(const ArrayType& type)
|
||||
{
|
||||
emitter << YAML::BeginSeq;
|
||||
for (std::size_t idx = 0; idx < type.arraySize; ++idx)
|
||||
{
|
||||
const std::byte* ele = static_cast<const std::byte*>(data) + (idx * type.arrayStride);
|
||||
propertyToYAML(ele, *type.baseType, emitter);
|
||||
}
|
||||
emitter << YAML::EndSeq;
|
||||
}
|
||||
|
||||
void operator()(const ClassType&)
|
||||
{
|
||||
MIJIN_ERROR("Not implemented.");
|
||||
emitter << YAML::Null;
|
||||
}
|
||||
|
||||
void operator()(const StructType& type)
|
||||
{
|
||||
structToYAML(data, *type.struct_, emitter);
|
||||
}
|
||||
|
||||
void operator()(const PointerType&)
|
||||
{
|
||||
MIJIN_ERROR("Not implemented.");
|
||||
emitter << YAML::Null;
|
||||
}
|
||||
|
||||
void operator()(const ReferenceType&)
|
||||
{
|
||||
MIJIN_ERROR("Not implemented.");
|
||||
emitter << YAML::Null;
|
||||
}
|
||||
|
||||
void operator()(const ConstType& type)
|
||||
{
|
||||
propertyToYAML(data, *type.baseType, emitter);
|
||||
}
|
||||
|
||||
void operator()(const VolatileType& type)
|
||||
{
|
||||
propertyToYAML(data, *type.baseType, emitter);
|
||||
}
|
||||
|
||||
void operator()(const STDType& type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case STDType::STRING:
|
||||
emitter << *static_cast<const std::string*>(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(const BitFlagsType&)
|
||||
{
|
||||
MIJIN_ERROR("Not implemented.");
|
||||
emitter << YAML::Null;
|
||||
}
|
||||
};
|
||||
|
||||
struct PropertyParseVisitor
|
||||
{
|
||||
void* data;
|
||||
const YAML::Node& node;
|
||||
|
||||
void operator()(const VoidType&) { /* ??? */ }
|
||||
|
||||
void operator()(const BoolType&)
|
||||
{
|
||||
*static_cast<bool*>(data) = node.as<bool>();
|
||||
}
|
||||
|
||||
void operator()(const IntType& type)
|
||||
{
|
||||
visitIntValue([&](auto& value)
|
||||
{
|
||||
using type_t = std::decay_t<decltype(value)>;
|
||||
value = node.as<type_t>();
|
||||
}, data, type);
|
||||
}
|
||||
|
||||
void operator()(const FloatType& type)
|
||||
{
|
||||
visitFloatValue([&](auto& value)
|
||||
{
|
||||
using type_t = std::decay_t<decltype(value)>;
|
||||
value = node.as<type_t>();
|
||||
}, data, type);
|
||||
}
|
||||
|
||||
void operator()(const CharType& type)
|
||||
{
|
||||
MIJIN_ERROR("Not implemented.");
|
||||
(void) type;
|
||||
// visitCharValue([&](auto& value)
|
||||
// {
|
||||
// using type_t = std::decay_t<decltype(value)>;
|
||||
// value = node.as<type_t>();
|
||||
// }, data, type);
|
||||
}
|
||||
|
||||
void operator()(const ArrayType& type)
|
||||
{
|
||||
if (!node.IsSequence() || node.size() != type.arraySize)
|
||||
{
|
||||
throw std::runtime_error("Node not an array or size doesn't fit.");
|
||||
}
|
||||
for (std::size_t idx = 0; idx < type.arraySize; ++idx)
|
||||
{
|
||||
std::byte* ele = static_cast<std::byte*>(data) + (idx * type.arrayStride);
|
||||
propertyFromYAML(ele, *type.baseType, node[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(const ClassType&)
|
||||
{
|
||||
MIJIN_ERROR("Not implemented.");
|
||||
}
|
||||
|
||||
void operator()(const StructType& type)
|
||||
{
|
||||
structFromYAML(data, *type.struct_, node);
|
||||
}
|
||||
|
||||
void operator()(const PointerType&)
|
||||
{
|
||||
MIJIN_ERROR("Not implemented.");
|
||||
}
|
||||
|
||||
void operator()(const ReferenceType&)
|
||||
{
|
||||
MIJIN_ERROR("Not implemented.");
|
||||
}
|
||||
|
||||
void operator()(const ConstType&)
|
||||
{
|
||||
MIJIN_ERROR("Can't read const values.");
|
||||
}
|
||||
|
||||
void operator()(const VolatileType& type)
|
||||
{
|
||||
propertyFromYAML(data, *type.baseType, node);
|
||||
}
|
||||
|
||||
void operator()(const STDType& type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case STDType::STRING:
|
||||
*static_cast<std::string*>(data) = node.as<std::string>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(const BitFlagsType&)
|
||||
{
|
||||
MIJIN_ERROR("Not implemented.");
|
||||
}
|
||||
};
|
||||
|
||||
void propertyToYAML(const void* data, const iwa::Type& type, YAML::Emitter& emitter)
|
||||
{
|
||||
std::visit(PropertyEmitVisitor{data, emitter}, type);
|
||||
}
|
||||
|
||||
void propertyFromYAML(void* data, const iwa::Type& type, const YAML::Node& node)
|
||||
{
|
||||
std::visit(PropertyParseVisitor{data, node}, type);
|
||||
}
|
||||
}
|
||||
|
||||
void structToYAML(const void* data, const Struct& type, YAML::Emitter& emitter)
|
||||
{
|
||||
emitter << YAML::BeginMap;
|
||||
for (const Property& property : type.getProperties())
|
||||
{
|
||||
emitter << YAML::Key << property.name;
|
||||
propertyToYAML(static_cast<const std::byte*>(data) + property.offset, property.type, emitter);
|
||||
}
|
||||
emitter << YAML::EndMap;
|
||||
}
|
||||
|
||||
void structFromYAML(void* data, const Struct& type, const YAML::Node& node)
|
||||
{
|
||||
if (!node.IsMap())
|
||||
{
|
||||
throw std::runtime_error("Expected map.");
|
||||
}
|
||||
for (const Property& property : type.getProperties())
|
||||
{
|
||||
const YAML::Node& propNode = node[property.name];
|
||||
if (propNode.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
propertyFromYAML(static_cast<std::byte*>(data) + property.offset, property.type, propNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user