209 lines
5.0 KiB
C++
209 lines
5.0 KiB
C++
#pragma once
|
||
#include <any>
|
||
#include <functional>
|
||
#include <optional>
|
||
#include <string>
|
||
#include <string_view>
|
||
|
||
#include "flag_enum.h"
|
||
#include "types/types.h"
|
||
|
||
namespace mirai {
|
||
class object;
|
||
}
|
||
|
||
enum class property_flags : u32 {
|
||
none = 0,
|
||
read_only = 1 << 0,
|
||
serializable = 1 << 1,
|
||
editable = 1 << 2,
|
||
hidden = 1 << 3,
|
||
notify = 1 << 4,
|
||
required = 1 << 5,
|
||
deprecated = 1 << 6,
|
||
};
|
||
MIRAI_FLAG_ENUM(property_flags)
|
||
|
||
struct property_change_event {
|
||
std::string_view property_name;
|
||
std::any old_value;
|
||
std::any new_value;
|
||
|
||
void* owner = nullptr;
|
||
};
|
||
|
||
using property_change_listener = std::function<void(const property_change_event&)>;
|
||
using property_getter = std::function<std::any(const void*)>;
|
||
using property_setter = std::function<bool(void*, const std::any&)>;
|
||
|
||
struct property_info {
|
||
// 属性名称
|
||
std::string name;
|
||
// 属性显示名称
|
||
std::string display_name;
|
||
// 属性描述
|
||
std::string description;
|
||
// 属性类别(用于分组)
|
||
std::string category;
|
||
// 属性类型名称
|
||
std::string type_name;
|
||
// 属性标志
|
||
property_flags flags{property_flags::none};
|
||
// getter 函数(返回 std::any)
|
||
property_getter getter;
|
||
// setter 函数(接受 std::any)
|
||
property_setter setter;
|
||
// 默认值
|
||
std::any default_value;
|
||
// 最小值(用于数值类型)
|
||
std::optional<std::any> min_value;
|
||
// 最大值(用于数值类型)
|
||
std::optional<std::any> max_value;
|
||
mirai::object* owner{nullptr};
|
||
|
||
property_info(mirai::object* owner_ptr);
|
||
|
||
// 检查属性是否只读
|
||
[[nodiscard]] bool is_read_only() const noexcept {
|
||
return has_flag(flags, property_flags::read_only) || !setter;
|
||
}
|
||
|
||
// 检查属性是否可序列化
|
||
[[nodiscard]] bool is_serializable() const noexcept {
|
||
return has_flag(flags, property_flags::serializable);
|
||
}
|
||
|
||
// 检查属性是否可编辑
|
||
[[nodiscard]] bool is_editable() const noexcept {
|
||
return has_flag(flags, property_flags::editable) && !is_read_only();
|
||
}
|
||
|
||
// 检查属性是否隐藏
|
||
[[nodiscard]] bool is_hidden() const noexcept {
|
||
return has_flag(flags, property_flags::hidden);
|
||
}
|
||
|
||
// 检查属性是否启用通知
|
||
[[nodiscard]] bool has_notify() const noexcept {
|
||
return has_flag(flags, property_flags::notify);
|
||
}
|
||
|
||
// 获取属性值
|
||
[[nodiscard]] std::any get_value(const void* obj) const {
|
||
if (getter) {
|
||
return getter(obj);
|
||
}
|
||
return {};
|
||
}
|
||
|
||
// 设置属性值
|
||
bool set_value(void* obj, const std::any& value) const {
|
||
if (is_read_only()) {
|
||
return false;
|
||
}
|
||
if (setter) {
|
||
return setter(obj, value);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// 获取类型化的属性值
|
||
[[nodiscard]] std::optional<std::any> get_value_as(const void* obj) const {
|
||
try {
|
||
auto value = get_value(obj);
|
||
if (value.has_value()) {
|
||
return std::any_cast<std::any>(value);
|
||
}
|
||
}
|
||
catch (const std::bad_any_cast&) {
|
||
// 类型不匹配
|
||
}
|
||
return std::nullopt;
|
||
}
|
||
|
||
template <typename T>
|
||
bool set_value_as(void* obj, const T& value) const {
|
||
return set_value(obj, std::any(value));
|
||
}
|
||
};
|
||
|
||
template <typename T>
|
||
class property_wrapper {
|
||
public:
|
||
property_info info_;
|
||
|
||
// 构造函数:在初始化列表中被调用
|
||
property_wrapper(
|
||
mirai::object* owner_ptr,
|
||
std::string_view name,
|
||
std::string_view description,
|
||
std::string_view type_name,
|
||
property_flags flags,
|
||
const T& default_val,
|
||
std::function<T(const void*)> internal_getter,
|
||
std::function<void(void*, const T&)> internal_setter
|
||
) : info_(owner_ptr) {
|
||
info_.name = name;
|
||
info_.display_name = name; // 默认显示名称等于代码名称
|
||
info_.description = description; // 设置注释/描述
|
||
info_.type_name = type_name;
|
||
info_.flags = flags;
|
||
info_.default_value = default_val;
|
||
|
||
// 适配 lambda 转换为通用的 any 接口
|
||
info_.getter = [internal_getter](const void* obj) -> std::any {
|
||
return internal_getter(obj);
|
||
};
|
||
|
||
info_.setter = [internal_setter](void* obj, const std::any& val) -> bool {
|
||
try {
|
||
internal_setter(obj, std::any_cast<T>(val));
|
||
return true;
|
||
} catch (...) {
|
||
return false;
|
||
}
|
||
};
|
||
// 获取基类的指针
|
||
}
|
||
|
||
// 类型化访问
|
||
T get(const void* obj) const {
|
||
return std::any_cast<T>(info_.get_value(obj));
|
||
}
|
||
|
||
void set(void* obj, const T& val) {
|
||
info_.set_value(obj, val);
|
||
}
|
||
};
|
||
|
||
#define PROPERTY(Type, Name, Description, Flags, DefaultVal) \
|
||
private: \
|
||
Type m_##Name = DefaultVal; \
|
||
public: \
|
||
/* 1. Getter */ \
|
||
[[nodiscard]] Type get_##Name() const { return m_##Name; } \
|
||
/* 2. Setter */ \
|
||
void set_##Name(const Type& value) { \
|
||
if (m_##Name != value) { \
|
||
m_##Name = value; \
|
||
/* 这里可以触发 on_property_changed 通知 */ \
|
||
} \
|
||
} \
|
||
/* 3. 反射包装器 (public 以便外部访问元数据) */ \
|
||
property_wrapper<Type> prop_##Name { \
|
||
this, \
|
||
#Name, \
|
||
Description, \
|
||
#Type, \
|
||
Flags, \
|
||
DefaultVal, \
|
||
/* Getter Lambda */ \
|
||
[](const void* obj) -> Type { \
|
||
return static_cast<const std::decay_t<decltype(*this)>*>(obj)->get_##Name(); \
|
||
}, \
|
||
/* Setter Lambda */ \
|
||
[](void* obj, const Type& val) { \
|
||
static_cast<std::decay_t<decltype(*this)>*>(obj)->set_##Name(val); \
|
||
} \
|
||
};
|