iwa/source/serialization.cpp

248 lines
5.7 KiB
C++

#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);
}
}
}