zengine-old/engine/3rdparty/zlib/include/yaml/serialize/text.inl
2024-07-10 22:18:04 +08:00

184 lines
4.8 KiB
C++

#pragma once
#include "text.h"
namespace YAML
{
template<typename T>
inline string TextSerialize<T>::Serialize(const Any& any)
{
if constexpr (Check_IsString<T>) {
return string(*any.CastTo<T*>());
}
else if constexpr(Check_ToString<T>){
return std::to_string(*any.CastTo<T*>());
}
else {
return string(any.cls->name.GetView());
}
}
template<typename T>
inline bool TextSerialize<T>::Unserialize(const string& val, const Any& any)
{
if constexpr (Check_IsString<T>) {
return new (any.CastTo<T*>())T(val);
}
else if constexpr (std::is_arithmetic_v<T>) {
if constexpr (std::is_integral_v<T>) {
*any.CastTo<T*>() = std::stoul(val);
return true;
}
else if constexpr (std::is_floating_point_v<T>) {
*any.CastTo<T*>() = std::stold(val);
return true;
}
}
else {
return false;
}
}
inline StringFuncMap TextArchive::BuildStringMap()
{
StringFuncMap funcMap;
#define RegisterAny(T) funcMap.emplace(&TypeInfo<T>::StaticClass, std::make_pair(&TextSerialize<T>::Serialize, &TextSerialize<T>::Unserialize))
#include "register.inl"
#undef RegisterAny
return funcMap;
}
template<typename T>
inline void TextArchive::Register()
{
FuncMap.emplace(&TypeInfo<T>::StaticClass, std::make_pair(&TextSerialize<T>::Serialize, &TextSerialize<T>::Unserialize));
}
inline Node TextArchive::Serialize(const Any& any)
{
if (!any) {
return {};
}
auto it = FuncMap.find(any.cls);
if (it != FuncMap.end()) {
return Node{ it->second.first(any)};
}
Node result;
if (any.cls == &refl::TypeInfo<Any>::StaticClass) {
Any obj = any.CastTo<Any>();
if (obj) {
result["__class__"] = string(obj.cls->name);
result["__data__"] = Serialize(obj);
}
return result;
}
if (any.IsContainer()) {
auto docker = any.ToContainer();
bool isMap = any.IsMap();
auto fieldList = any.ContainerValue()->GetFields(refl::FIND_ALL_MEMBER, FName(""));
for (auto obj : docker) {
if (isMap) {
Any first = obj.Member(*fieldList[0]);
Any second = obj.Member(*fieldList[1]);
result[Serialize(first)] = Serialize(second);
}
else {
result.push_back(Serialize(obj));
}
}
return result;
}
if (any.IsArray()) {
int n = any.ArraySize();
for (int i = 0; i < n; i++) {
result.push_back(Serialize(any.Member(i)));
}
return result;
}
if (Any p = any.Parent()) {
result["__parent__"] = Serialize(p);
}
auto fieldList = any.cls->GetFields(refl::FIND_ALL_MEMBER, FName(""));
for (auto& field : fieldList) {
Node child = Serialize(any.Member(field));
result[field.name.GetView()] = child;
}
return result;
}
inline bool TextArchive::Unserialize(const Node& res, const Any& any)
{
if (!any) {
return false;
}
if (res.IsNull()) {
const string& str = "";
return any.Construct(Any{ &str, &TypeInfo<string>::StaticClass });
}
auto it = FuncMap.find(any.cls);
if (it != FuncMap.end()) {
return it->second.second(res.as<string>(),any);
}
if (any.cls == &refl::TypeInfo<Any>::StaticClass) {
string name = res["__class__"].as<string>();
auto cls = refl::UClass::Find(Name(name));
if (cls) {
Any obj = cls->New();
*any.CastTo<Any*>() = obj;
return Unserialize(res["__data__"], obj);
}
*any.CastTo<Any*>() = {};
return false;
}
if (any.IsContainer()) {
auto docker = any.ToContainer();
docker.construct();
char memory[STACK_MEMORY_SIZE];
Any any = docker.try_malloc(&memory, STACK_MEMORY_SIZE);
bool isMap = res.IsMap() && any.IsMap();
Any first, second;
if (isMap) {
auto fieldList = any.ContainerValue()->GetFields(refl::FIND_ALL_MEMBER, FName(""));
first = any.Member(*fieldList.at(0));
second = any.Member(*fieldList.at(1));
}
for (auto it : res) {
if (isMap) {
Unserialize(it.first, first);
Unserialize(it.second, second);
}
else {
Unserialize(it, any);
}
docker.insert(any);
any.Destruct();
}
docker.try_free(any, STACK_MEMORY_SIZE);
return true;
}
if (res.IsSequence() && any.IsArray()) {
for (std::size_t i = 0; i < res.size(); i++) {
Unserialize(res[i], any.Member(i));
}
return true;
}
if (res.IsMap() && any.IsObject()) {
auto fieldList = any.cls->GetFields(refl::FIND_ALL_MEMBER, FName(""));
auto rt = res.begin();
int diff = res.size() - fieldList.size();
if (diff == 1 && any.CheckParent()) {
diff = 0;
Unserialize(rt++->second, any.Parent());
}
else if (diff != 0) {
return false;
}
auto ft = fieldList.begin();
for (; ft != fieldList.end() && rt != res.end(); ++ft,++rt) {
if (ft->name != Name(rt->first.as<string>())) {
return false;
}
Unserialize(rt->second, any.Member(*ft));
}
return true;
}
if (res.IsScalar() && any.IsObject()) {
const string& str = res.as<string>();
return any.Construct(Any{&str, &TypeInfo<string>::StaticClass});
}
return false;
}
}