#ifndef UI_BASE_METADATA_PROPERTY_METADATA_H_
#define UI_BASE_METADATA_PROPERTY_METADATA_H_
#include <concepts>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#include "base/component_export.h"
#include "base/notreached.h"
#include "ui/base/class_property.h"
#include "ui/base/metadata/base_type_conversion.h"
#include "ui/base/metadata/metadata_cache.h"
#include "ui/base/metadata/metadata_types.h"
namespace ui {
namespace metadata {
namespace internal {
template <typename TKey, typename TValue>
struct ClassPropertyMetaDataTypeHelper;
template <typename TKValue_, typename TValue_>
requires(std::same_as<TKValue_, TValue_> || std::same_as<TKValue_, TValue_*>)
struct ClassPropertyMetaDataTypeHelper<const ui::ClassProperty<TKValue_>* const,
TValue_> {
using TKValue = TKValue_;
using TValue = TValue_;
static TValue DeRef(TKValue value) {
if constexpr (std::same_as<TKValue, TValue*>) {
return *value;
}
if constexpr (std::same_as<TKValue, TValue>) {
return value;
}
NOTREACHED();
}
};
template <typename TClass>
TClass* AsClass(void* obj) {
return static_cast<TClass*>(
reinterpret_cast<TClass*>(obj)->ReinterpretToBaseClass(obj));
}
}
template <typename TClass,
typename TValue,
typename TRet,
TRet (TClass::*Get)() const,
typename TConverter = ui::metadata::TypeConverter<TValue>>
class ObjectPropertyReadOnlyMetaData : public ui::metadata::MemberMetaDataBase {
public:
using MemberMetaDataBase::MemberMetaDataBase;
ObjectPropertyReadOnlyMetaData(const ObjectPropertyReadOnlyMetaData&) =
delete;
ObjectPropertyReadOnlyMetaData& operator=(
const ObjectPropertyReadOnlyMetaData&) = delete;
~ObjectPropertyReadOnlyMetaData() override = default;
std::u16string GetValueAsString(void* obj) const override {
if constexpr (kTypeIsSerializable || kTypeIsReadOnly) {
return TConverter::ToString((internal::AsClass<TClass>(obj)->*Get)());
}
return std::u16string();
}
ui::metadata::PropertyFlags GetPropertyFlags() const override {
if constexpr (kTypeIsSerializable) {
return ui::metadata::PropertyFlags::kReadOnly |
ui::metadata::PropertyFlags::kSerializable;
}
return ui::metadata::PropertyFlags::kReadOnly;
}
std::string_view GetMemberNamePrefix() const override {
return TConverter::property_name_prefix;
}
private:
static constexpr bool kTypeIsSerializable = TConverter::is_serializable;
static constexpr bool kTypeIsReadOnly = TConverter::is_read_only;
};
template <typename TClass,
typename TValue,
typename TSig,
TSig Set,
typename TRet,
TRet (TClass::*Get)() const,
typename TConverter = ui::metadata::TypeConverter<TValue>>
class ObjectPropertyMetaData
: public ObjectPropertyReadOnlyMetaData<TClass,
TValue,
TRet,
Get,
TConverter> {
public:
using ObjectPropertyReadOnlyMetaData<TClass, TValue, TRet, Get, TConverter>::
ObjectPropertyReadOnlyMetaData;
ObjectPropertyMetaData(const ObjectPropertyMetaData&) = delete;
ObjectPropertyMetaData& operator=(const ObjectPropertyMetaData&) = delete;
~ObjectPropertyMetaData() override = default;
void SetValueAsString(void* obj, const std::u16string& new_value) override {
if constexpr (kTypeIsSerializable && !kTypeIsReadOnly) {
if (std::optional<TValue> result = TConverter::FromString(new_value)) {
(internal::AsClass<TClass>(obj)->*Set)(std::move(result.value()));
}
}
}
ui::metadata::MemberMetaDataBase::ValueStrings GetValidValues()
const override {
if constexpr (kTypeIsSerializable) {
return TConverter::GetValidStrings();
}
return {};
}
ui::metadata::PropertyFlags GetPropertyFlags() const override {
ui::metadata::PropertyFlags flags = ui::metadata::PropertyFlags::kEmpty;
if constexpr (kTypeIsSerializable) {
flags = flags | ui::metadata::PropertyFlags::kSerializable;
}
if constexpr (kTypeIsReadOnly) {
flags = flags | ui::metadata::PropertyFlags::kReadOnly;
}
return flags;
}
private:
static constexpr bool kTypeIsSerializable = TConverter::is_serializable;
static constexpr bool kTypeIsReadOnly = TConverter::is_read_only;
};
template <typename TClass,
typename TKey,
typename TValue,
typename TConverter = ui::metadata::TypeConverter<TValue>>
class ClassPropertyMetaData : public ui::metadata::MemberMetaDataBase {
public:
using TypeHelper = internal::ClassPropertyMetaDataTypeHelper<TKey, TValue>;
ClassPropertyMetaData(TKey key, const std::string& property_type)
: MemberMetaDataBase(key->name, property_type), key_(key) {}
ClassPropertyMetaData(const ClassPropertyMetaData&) = delete;
ClassPropertyMetaData& operator=(const ClassPropertyMetaData&) = delete;
~ClassPropertyMetaData() override = default;
std::u16string GetValueAsString(void* obj) const override {
typename TypeHelper::TKValue value =
internal::AsClass<TClass>(obj)->GetProperty(key_);
if (std::is_pointer<typename TypeHelper::TKValue>::value && !value) {
return u"(not assigned)";
} else {
return TConverter::ToString(TypeHelper::DeRef(value));
}
}
void SetValueAsString(void* obj, const std::u16string& new_value) override {
std::optional<TValue> value = TConverter::FromString(new_value);
if (value)
internal::AsClass<TClass>(obj)->SetProperty(key_, *value);
}
ui::metadata::PropertyFlags GetPropertyFlags() const override {
ui::metadata::PropertyFlags flags = ui::metadata::PropertyFlags::kEmpty;
if constexpr (kTypeIsSerializable) {
flags = flags | ui::metadata::PropertyFlags::kSerializable;
}
if constexpr (kTypeIsReadOnly) {
flags = flags | ui::metadata::PropertyFlags::kReadOnly;
}
return flags;
}
private:
TKey key_;
static constexpr bool kTypeIsSerializable = TConverter::is_serializable;
static constexpr bool kTypeIsReadOnly = TConverter::is_read_only;
};
}
}
#endif