Files
mirai/src/core/property.h

209 lines
5.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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); \
} \
};