support yyjson

This commit is contained in:
ouczbs 2024-07-24 14:42:14 +08:00
parent 51f009c05e
commit 0a5cb27b27
19 changed files with 399 additions and 135 deletions

View File

@ -0,0 +1,53 @@
#pragma once
#include "meta/result.h"
#include "json/serialize.inl"
#include "json/serde.inl"
namespace api {
using meta::result;
enum class SerializeError : char
{
EMPTY,
ERROR,
};
template<typename T>
inline bool JsonDeserialize(string_view text, T* obj) {
yyjson_alc alc = JsonAllocatorAdapter();
yyjson_doc* doc = yyjson_read_opts((char*)text.data(), text.size(), YYJSON_READ_INSITU, &alc, nullptr);
yyjson_val* root = yyjson_doc_get_root(doc);
if constexpr (has_json_specialization_v<T>) {
return JsonSerde<T>::Read(root, obj);
}
else {
return JsonArchive::Deserialize(root, obj);
}
}
template<typename T, typename... Args>
inline result<T, SerializeError> JsonDeserialize(string_view text, Args&& ...args) {
if (text.empty()) {
return SerializeError::EMPTY;
}
T* obj = new(FramePool)T(std::forward<Args>(args)...);
bool bsuccess = JsonDeserialize<T>(text, obj);
using ResultType = result<T, SerializeError>;
return bsuccess ? ResultType{ *obj } : ResultType{ SerializeError::ERROR };
}
template<has_json_specialization_v T>
inline string_view JsonSerialize(const T& t) {
yyjson_alc alc = JsonAllocatorAdapter();
yyjson_mut_doc* doc = yyjson_mut_doc_new(&alc);
yyjson_mut_val* root = JsonSerde<T>::Write(doc, Any{t});
yyjson_mut_doc_set_root(doc, root);
size_t len;
const char* json_str = yyjson_mut_write_opts(doc, 0, &alc, &len, NULL);
return json_str ? string_view(json_str, len) : string_view("");
}
inline string_view JsonSerialize(Any any) {
yyjson_alc alc = JsonAllocatorAdapter();
yyjson_mut_doc* doc = yyjson_mut_doc_new(&alc);
yyjson_mut_val* root = JsonArchive::Serialize(doc, any);
yyjson_mut_doc_set_root(doc, root);
size_t len;
const char* json_str = yyjson_mut_write_opts(doc, 0, &alc, &len, NULL);
return json_str ? string_view(json_str, len) : string_view("");
}
}

View File

@ -1,14 +1,58 @@
#pragma once #pragma once
#include "serialize.h" #include "refl/pch.h"
#include <format>
#include <string_view>
namespace api { namespace api {
struct JsonSerialize { namespace archive {
template<typename T>
concept is_string_v = requires(T t) {
{ static_cast<std::string>(t) } -> std::convertible_to<std::string>;
}; };
}
using std::string_view;
using refl::Any;
using refl::UClass;
using refl::type_name;
using refl::TypeInfo;
template<typename T> template<typename T>
struct JsonSerde { struct JsonSerde {
inline static bool read(yyjson_val* val, T& v) inline static bool Read(yyjson_val* val, Any any) {
{ if constexpr (std::is_same_v<T, bool>) {
return r.read(v); *any.CastTo<T*>() = (T)yyjson_get_bool(val);
}
else if constexpr (std::is_integral_v<T>) {
*any.CastTo<T*>() = (T)yyjson_get_uint(val);
}
else if constexpr (std::is_floating_point_v<T>) {
*any.CastTo<T*>() = (T)yyjson_get_real(val);
}
else if constexpr (archive::is_string_v<T>) {
*any.CastTo<T*>() = yyjson_get_str(val);
}
else {
throw std::runtime_error(std::format("unknown json read type {}", type_name<T>().View()));
return false;
}
return true;
}
inline static yyjson_mut_val* Write(yyjson_mut_doc* doc, Any any) {
if constexpr (std::is_same_v<T, bool>) {
return yyjson_mut_bool(doc, *any.CastTo<T*>());
}
else if constexpr (std::is_integral_v<T>) {
return yyjson_mut_uint(doc, *any.CastTo<T*>());
}
else if constexpr (std::is_floating_point_v<T>) {
return yyjson_mut_real(doc, *any.CastTo<T*>());
}
else if constexpr (archive::is_string_v<T>) {
auto c = (any.CastTo<T*>())->data();
return yyjson_mut_str(doc, "");
}
else {
throw std::runtime_error(std::format("unknown json write type {}", type_name<T>().View()));
return {};
}
} }
}; };
} }

View File

@ -0,0 +1,26 @@
#include "serde.h"
namespace api {
namespace detail {
// 辅助结构体,用于检查特化版本
template<typename T, typename = void>
struct has_json_specialization : std::false_type {};
// 特化辅助结构体,匹配特化版本
template <typename T>
struct has_json_specialization<T, std::void_t<decltype(&JsonSerde<T>::Read) >> : std::true_type {};
}
template<typename T>
concept has_json_specialization_v = detail::has_json_specialization<T>::value;
#ifdef API_DEBUG
template<typename T>
inline bool JsonRead(yyjson_val* node, const T& t) {
return JsonSerde<T>::Read(node, t);
}
template<typename T>
inline yyjson_mut_val* JsonWrite(yyjson_mut_doc* doc, const T& t) {
return JsonSerde<T>::Write(doc, t);
}
#else
#define JsonRead(node, t) JsonSerde<decltype(t)>::Read(node, t)
#endif
}

View File

@ -1,85 +1,24 @@
#pragma once #pragma once
#include "zlog.h"
#include "yyjson.h" #include "yyjson.h"
#include <string_view> #include "serde.h"
#include <vector>
namespace api { namespace api {
using std::string_view; struct JsonVTable {
struct JsonReader { bool(*Read)(yyjson_val*, Any) = nullptr;
struct Level { yyjson_mut_val*(*Write)(yyjson_mut_doc*, Any) = nullptr;
enum EType : uint32_t {
EObjectIndex = -1,
EArrayIndex = 0,
};
yyjson_val* val = nullptr;
uint32_t index = EObjectIndex;
constexpr Level(yyjson_val* val, EType type = EObjectIndex) noexcept
: val(val),index(type){}
constexpr bool is_object()const {
return index == EObjectIndex;
}
constexpr bool is_array()const {
return index != EObjectIndex;
}
};
yyjson_doc* doc;
std::vector<Level> stack;
~JsonReader() {
if (doc) {
yyjson_doc_free(doc);
}
}
JsonReader(string_view json) {
yyjson_read_err err = {};
doc = yyjson_read_opts((char*)json.data(), json.size(), 0, nullptr, &err);
if (doc == nullptr) {
zlog::error("Failed to parse JSON: {}, error: {}", json.data(), err.msg);
}
}
yyjson_val* find(string_view name) {
auto back = stack.back();
if (back.is_object()) {
return yyjson_obj_get(back.val, name.data());
}
return yyjson_arr_get(back.val, back.index++);
}
bool start_object(string_view name = "") {
yyjson_val* root = stack.empty() ? yyjson_doc_get_root(doc) : find(name);
stack.emplace_back(root, Level::EObjectIndex);
}
void end_object() {
stack.pop_back();
}
bool start_array(string_view name = "") {
yyjson_val* root = stack.empty() ? yyjson_doc_get_root(doc) : find(name);
stack.emplace_back(root, Level::EArrayIndex);
}
void end_array() {
stack.pop_back();
}
template<typename T> template<typename T>
bool read(T& v, const string_view& name = "") { static JsonVTable Make() {
template<typename T> return { &JsonSerde<T>::Read, &JsonSerde<T>::Write };
concept is_string_v = requires(T t) { }
{ static_cast<std::string>(t) } -> std::convertible_to<std::string>;
}; };
yyjson_val* parent = find(name); using JsonFuncTable = std::pmr::unordered_map<const UClass*, JsonVTable>;
if constexpr (std::is_same_v<T, bool>) { struct JsonArchive {
v = (T)yyjson_get_bool(parent); private:
} static JsonFuncTable BuildFuncTable();
else if constexpr (std::is_integral_v<T>) { inline static JsonFuncTable FuncTable = BuildFuncTable();
v = (T)yyjson_get_uint(parent); public:
} template<typename T>
else if constexpr (std::is_floating_point_v<T>) { static void Register();
v = (T)yyjson_get_real(parent); static yyjson_mut_val* Serialize(yyjson_mut_doc* doc, Any any);
} static bool Deserialize(yyjson_val* res, Any any);
else if constexpr (is_string_v<T>){
v = yyjson_get_str(parent);
}
else {
return false;
}
return true;
}
}; };
} }

View File

@ -0,0 +1,65 @@
#include "serialize.h"
#include "serde.h"
namespace api {
// 定义 yyjson_alc 适配器类
yyjson_alc JsonAllocatorAdapter(std::pmr::memory_resource* mr = &FramePool) {
// 初始化 yyjson_alc 结构体
yyjson_alc alc;
alc.malloc = [](void* ctx, size_t size) -> void* {
auto* adapter = static_cast<std::pmr::memory_resource*>(ctx);
return adapter->allocate(size);
};
alc.realloc = [](void* ctx, void* ptr, size_t old_size, size_t size) -> void* {
auto* adapter = static_cast<std::pmr::memory_resource*>(ctx);
// std::pmr::memory_resource 不支持直接重新分配
// 因此,先分配新的内存,再拷贝数据
void* new_ptr = adapter->allocate(size);
if (ptr) {
std::memcpy(new_ptr, ptr, std::min(old_size, size));
adapter->deallocate(ptr, old_size);
}
return new_ptr;
};
alc.free = [](void* ctx, void* ptr) {
auto* adapter = static_cast<std::pmr::memory_resource*>(ctx);
adapter->deallocate(ptr, 0);
};
alc.ctx = mr;
return alc;
}
inline JsonFuncTable JsonArchive::BuildFuncTable()
{
JsonFuncTable funcTable{ &MemPool };
#define RegisterAny(T) funcTable.emplace(&TypeInfo<T>::StaticClass,JsonVTable::Make<T>())
#include "../register.inl"
#undef RegisterAny
return funcTable;
}
template<typename T>
inline void JsonArchive::Register()
{
FuncTable.emplace(&TypeInfo<T>::StaticClass, JsonVTable::Make<T>());
}
inline yyjson_mut_val* JsonArchive::Serialize(yyjson_mut_doc* doc, Any any)
{
if (!any) {
return {};
}
auto it = FuncTable.find(any.cls);
if (it != FuncTable.end()) {
return it->second.Write(doc, any);
}
return {};
}
inline bool JsonArchive::Deserialize(yyjson_val* res, Any any)
{
if (!any) {
return false;
}
auto it = FuncTable.find(any.cls);
if (it != FuncTable.end()) {
return it->second.Read(res, any);
}
return false;
}
}

View File

@ -0,0 +1,11 @@
#ifdef RegisterAny
RegisterAny(string_view);
RegisterAny(int);
RegisterAny(unsigned int);
RegisterAny(short);
RegisterAny(unsigned short);
RegisterAny(char);
RegisterAny(unsigned char);
RegisterAny(float);
RegisterAny(double);
#endif // RegisterAny

View File

@ -0,0 +1,46 @@
#pragma once
#include <utility>
#include <variant>
namespace meta
{
// a struct stolen from rust
// lets us define a result, or return an error otherwise
template<typename Result, typename Error>
class result
: protected std::variant<Result, Error>
{
protected:
using Base = std::variant<Result, Error>;
private:
static constexpr auto Success = 0;
static constexpr auto Failure = 1;
static_assert(std::is_default_constructible_v<Error>, "Error must be default constructible");
public:
using value_type = Result;
using Base::Base;
using Base::operator=;
// accessors
Result& value();
template<typename U, typename = std::enable_if_t<std::is_constructible_v<Result, U>>>
Result value_or(U&& result) const;
Error& error();
const Result& value() const;
const Error& error() const;
// monadic operators
template<class Fn> auto map(Fn&& visitor) const;
template<class Fn> auto and_then(Fn&& visitor) const;
template<class Fn, class ErrFn> auto and_then(Fn&& visitor, ErrFn&& err_visitor) const;
template<class ErrFunc> auto or_else(ErrFunc&& err_visitor) const;
// operator overloads
explicit operator bool() const;
Result& operator*();
Result* operator->();
const Result& operator*() const;
const Result* operator->() const;
};
}
#include "result.inl"

View File

@ -0,0 +1,54 @@
namespace meta
{
template<typename Result, typename Error>
inline Result& result<Result, Error>::value()
{
return std::get<Success>(*this);
}
template<typename Result, typename Error>
template<typename U, typename>
Result result<Result, Error>::value_or(U&& result) const
{
return bool(*this) ? **this : static_cast<Result>(std::forward<U>(result));
}
template<typename Result, typename Error>
inline Error& result<Result, Error>::error()
{
return std::get<Failure>(*this);
}
template<typename Result, typename Error>
inline const Result& result<Result, Error>::value() const
{
return std::get<Success>(*this);
}
template<typename Result, typename Error>
inline const Error& result<Result, Error>::error() const
{
return std::get<Failure>(*this);
}
template<typename Result, typename Error>
inline result<Result, Error>::operator bool() const
{
return Base::index() == Success;
}
template<typename Result, typename Error>
inline Result& result<Result, Error>::operator*()
{
return value();
}
template<typename Result, typename Error>
inline Result* result<Result, Error>::operator->()
{
return &operator*();
}
template<typename Result, typename Error>
const Result& result<Result, Error>::operator*() const
{
return value();
}
template<typename Result, typename Error>
const Result* result<Result, Error>::operator->() const
{
return &operator*();
}
}

View File

@ -45,3 +45,5 @@ inline void* operator new(size_t size, pmr::FrameAllocatorPool& pool, size_t ali
return pool.allocate(size, alignment); return pool.allocate(size, alignment);
} }
#include "frame_allocator.inl" #include "frame_allocator.inl"
inline static pmr::FrameAllocatorPool MemPool{};
inline static pmr::FrameAllocatorPool FramePool{};

View File

@ -31,9 +31,9 @@ namespace pmr
}; };
struct Name { struct Name {
size_t hash; size_t hash;
#ifdef Z_DEBUG #ifdef API_DEBUG
std::string_view value; std::string_view value;
#endif // Z_DEBUG #endif // API_DEBUG
public: public:
Name():hash(NameID::InvalidValue()) {}; Name():hash(NameID::InvalidValue()) {};
Name(const char* str)noexcept; Name(const char* str)noexcept;

View File

@ -40,7 +40,7 @@ namespace pmr {
{ {
return NameTable::Find(hash); return NameTable::Find(hash);
} }
#ifdef Z_DEBUG #ifdef API_DEBUG
#define MAKE_NAME_PAIR(hash, str) value = NameTable::MakePair(hash, str) #define MAKE_NAME_PAIR(hash, str) value = NameTable::MakePair(hash, str)
#define NAME_TO_STRING value #define NAME_TO_STRING value
#else #else

View File

@ -2,27 +2,20 @@
#include "type.h" #include "type.h"
namespace refl { namespace refl {
class UClass; class UClass;
struct Any;
template<typename T>
concept is_not_any_v = !std::is_same_v<args_type_t<T>, Any>;
struct Any { struct Any {
public: public:
const void* ptr; const void* ptr;
const UClass* cls; const UClass* cls;
public: public:
constexpr Any() : ptr(nullptr), cls(nullptr) {} constexpr Any() noexcept: ptr(nullptr), cls(nullptr) {}
constexpr Any(const void* ptr, const UClass* cls) : ptr(ptr), cls(cls) {} constexpr Any(const void* ptr, const UClass* cls) noexcept : ptr(ptr), cls(cls) {}
template<typename T> template<is_not_any_v T>
constexpr Any(T&& v) : ptr(&v), cls(TypeInfo<args_type_t<T>>::StaticClass) { constexpr Any(T&& v) noexcept : ptr(&v), cls(&TypeInfo<args_type_t<T>>::StaticClass) {}
if constexpr (std::is_same_v<args_type_t<T>, Any>) { template<is_not_any_v T>
ptr = v.ptr; constexpr Any(T* v) noexcept : ptr(v), cls(&TypeInfo<args_type_t<T>>::StaticClass) {}
cls = v.cls;
}
}
template<typename T>
constexpr Any(T* v) : ptr(v), cls(&TypeInfo<args_type_t<T>>::StaticClass) {
if constexpr (std::is_same_v<args_type_t<T>, Any>) {
ptr = v->ptr;
cls = v->cls;
}
}
template<typename T>//参数 T* => T* template<typename T>//参数 T* => T*
constexpr inline T CastTo() const { constexpr inline T CastTo() const {
if constexpr (std::is_pointer_v<T>) { if constexpr (std::is_pointer_v<T>) {
@ -37,6 +30,7 @@ namespace refl {
} }
} }
public: public:
operator bool()const { return cls && ptr; }
bool Check(const UClass* parent) const; bool Check(const UClass* parent) const;
}; };
} }

View File

@ -1,4 +1,6 @@
#pragma once #pragma once
#include <array>
#include <string_view>
namespace refl { namespace refl {
template<size_t N> template<size_t N>
struct TStr { struct TStr {

View File

@ -79,13 +79,17 @@ namespace refl {
} }
template<typename T> template<typename T>
constexpr auto type_name() noexcept { constexpr auto type_name() noexcept {
if constexpr (std::is_arithmetic_v<T>) { if constexpr (std::is_same_v<T, void>) {
return TStr{ "void" };
}
else if constexpr (std::is_arithmetic_v<T>) {
constexpr auto prefix = detail::num_prefix_name<T>(); constexpr auto prefix = detail::num_prefix_name<T>();
constexpr auto bit = detail::num_name<8 * sizeof(T)>(); constexpr auto bit = detail::num_name<8 * sizeof(T)>();
return detail::concat(prefix, bit); return detail::concat(prefix, bit);
} }
else { else {
static_assert("not support"); //static_assert("not support");
return TStr{ "unknown" };
} }
} }
} }

View File

@ -44,6 +44,8 @@ namespace refl {
uint32_t flag{0}; uint32_t flag{0};
const UClass* parent; const UClass* parent;
vtable_uclass* vtable{nullptr}; vtable_uclass* vtable{nullptr};
UClass(const UClass*) = delete;
UClass& operator=(const UClass*) = delete;
public: public:
UClass(std::string_view name, uint32_t size, const UClass* parent = nullptr) UClass(std::string_view name, uint32_t size, const UClass* parent = nullptr)
:name(name), size(size), parent(parent) {} :name(name), size(size), parent(parent) {}
@ -59,7 +61,7 @@ namespace refl {
} }
template<typename T> template<typename T>
bool IsChildOf(bool bthis = false) const { bool IsChildOf(bool bthis = false) const {
return IsChildOf(TypeInfo<T>::StaticClass, bthis); return IsChildOf(&TypeInfo<T>::StaticClass, bthis);
} }
public: public:
template<typename T> template<typename T>

View File

@ -1,44 +1,41 @@
#include "uclass.h" #include "uclass.h"
#include "name.h" #include "name.h"
namespace refl{ namespace refl{
namespace detail {
inline static pmr::FrameAllocatorPool MemPool{};
}
template <class T> template <class T>
concept is_metas_v = false;//requires(const Name & name) { MetaImpl<T>::MyMetas::GetMeta(name); }; concept is_metas_v = false;//requires(const Name & name) { MetaImpl<T>::MyMetas::GetMeta(name); };
template<typename T> template<typename T>
class UClass_Auto : public UClass { class UClass_Auto : public UClass {
using UClass::UClass;
using MyUClass = UClass_Auto<T>;
public: public:
static MyUClass* BuildClass() { UClass_Auto() : UClass(type_name<T>().View(), sizeof(T)) {
MyUClass* cls = new(detail::MemPool)MyUClass(type_name<T>().View(), sizeof(T));
if constexpr (std::is_pointer_v<T>) { if constexpr (std::is_pointer_v<T>) {
using RT = std::remove_pointer_t<T>; using RT = std::remove_pointer_t<T>;
cls->flag |= CLASS_POINTER_FLAG; flag |= CLASS_POINTER_FLAG;
if constexpr (!std::is_same_v<RT, void>) { if constexpr (!std::is_same_v<RT, void>) {
cls->parent = TypeInfo<RT>::StaticClass; parent = &TypeInfo<RT>::StaticClass;
} }
} }
else if constexpr (is_array_v<T>) { else if constexpr (is_array_v<T>) {
using RT = is_array_t<T>; using RT = is_array_t<T>;
cls->flag = CLASS_ARRAY_FLAG; flag = CLASS_ARRAY_FLAG;
if constexpr (std::is_pointer_v<RT>) { if constexpr (std::is_pointer_v<RT>) {
cls->flag |= CLASS_POINTER_FLAG; flag |= CLASS_POINTER_FLAG;
} }
cls->parent = TypeInfo<RT>::StaticClass; parent = &TypeInfo<RT>::StaticClass;
} }
else { else {
cls->vtable = new(detail::MemPool)vtable_uclass(); vtable = new(MemPool)vtable_uclass();
cls->vtable->Construct = &UClass::Construct<T>; vtable->Construct = &UClass::Construct<T>;
cls->vtable->Destruct = &UClass::Destruct<T>; vtable->Destruct = &UClass::Destruct<T>;
} }
return cls;
} }
}; };
template<>
struct TypeInfoImpl<void> {
inline static UClass StaticClass{ type_name<void>().View(), 0 };
};
template<typename T> template<typename T>
struct TypeInfoImpl { struct TypeInfoImpl {
using MyUClass = UClass_Auto<T>; using MyUClass = UClass_Auto<T>;
inline static MyUClass* StaticClass = MyUClass::BuildClass(); inline static MyUClass StaticClass{};
}; };
} }

View File

@ -2,6 +2,6 @@ header_component("zlib","engine")
set_basename("myzlib") set_basename("myzlib")
add_headerfiles("include/**.h", "include/**.inl") add_headerfiles("include/**.h", "include/**.inl")
if is_mode("debug") then if is_mode("debug") then
add_defines("Z_DEBUG", {public = true}) add_defines("API_DEBUG", {public = true})
end end
set_pcheader("include/refl/pch.h") set_pcheader("include/refl/pch.h")

View File

@ -6,7 +6,7 @@
#include <stack> #include <stack>
#include <optional> #include <optional>
#include <sstream> #include <sstream>
#include "yyjson.h" #include "archive/json.h"
namespace pmr { namespace pmr {
using std::pmr::monotonic_buffer_resource; using std::pmr::monotonic_buffer_resource;
using std::pmr::vector; using std::pmr::vector;
@ -134,13 +134,38 @@ void genLua(const char* file_path, const pmr::vector<MacroData>& mdList) {
oss << '}'; oss << '}';
writeFile(file_path, oss.str()); writeFile(file_path, oss.str());
} }
namespace api {
struct Guid {
int a;
float b;
};
template<>
struct JsonSerde<Guid> {
inline static bool Read(yyjson_val* node, Any any) {
Guid& v = *any.CastTo<Guid*>();
JsonRead(yyjson_obj_get(node, "a"), v.a);
JsonRead(yyjson_obj_get(node, "b"), v.b);
return true;
}
inline static yyjson_mut_val* Write(yyjson_mut_doc* doc, Any any) {
Guid& v = *any.CastTo<Guid*>();
auto obj = yyjson_mut_obj(doc);
yyjson_mut_obj_add_val(doc, obj, "a", JsonWrite(doc, v.a));
yyjson_mut_obj_add_val(doc, obj, "b", JsonWrite(doc, v.b));
return obj;
}
};
}
void genPlugin(const char* file_path, const pmr::vector<MacroData>& mdList) { void genPlugin(const char* file_path, const pmr::vector<MacroData>& mdList) {
yyjson_read_err err = {}; api::Guid guid;
std::pmr::string json{"{a=1}"}; guid.a = 1243;
yyjson_doc* _document = yyjson_read_opts( std::string_view data = api::JsonSerialize(guid);
(char*)json.data(), json.size(), auto res = api::JsonDeserialize<api::Guid>(data);
0, nullptr, &err); if (res) {
auto obj = yyjson_doc_get_root((yyjson_doc*)_document); api::Guid g2 = res.value();
int a = g2.a;
int b = g2.b;
}
} }
int main() { int main() {
const char* file_path = R"(F:\engine\zengine\engine\modules\render\vulkan\include\vulkan\module.h)"; const char* file_path = R"(F:\engine\zengine\engine\modules\render\vulkan\include\vulkan\module.h)";

View File

@ -17,7 +17,7 @@ int main() {
constexpr TStr str3 = detail::concat(str1, str2); constexpr TStr str3 = detail::concat(str1, str2);
constexpr auto r1 = value_name<8 * sizeof(int)>(); constexpr auto r1 = value_name<8 * sizeof(int)>();
constexpr int v = 12; constexpr int v = 12;
auto cls = refl::TypeInfo<int>::StaticClass; auto cls = &refl::TypeInfo<int>::StaticClass;
//auto str4 = concat(r1, str2); //auto str4 = concat(r1, str2);
auto t1 = refl::type_name<int>(); auto t1 = refl::type_name<int>();
auto v1 = refl::type_name<int>().View(); auto v1 = refl::type_name<int>().View();