更新接口
This commit is contained in:
@@ -12,11 +12,6 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
namespace adminive {
|
||||
enum class Field_Lock_Mode {
|
||||
automatic,
|
||||
enabled,
|
||||
disabled
|
||||
};
|
||||
template <class T>
|
||||
struct Type_Descriptor;
|
||||
template <class T>
|
||||
@@ -39,6 +34,7 @@ template <auto Member>
|
||||
struct Member_Field_Accessor {
|
||||
using owner_type = typename Member_Pointer_Traits<Member>::owner_type;
|
||||
using member_type = typename Member_Pointer_Traits<Member>::member_type;
|
||||
static constexpr auto member = Member;
|
||||
template <class Object>
|
||||
static decltype(auto) get(Object& object) noexcept {
|
||||
return object.*Member;
|
||||
@@ -54,6 +50,7 @@ struct Reflected_Field_Accessor {
|
||||
using reference_type = decltype(Reflection_Adapter<T>::template get<Index>(std::declval<T&>()));
|
||||
using const_reference_type = decltype(Reflection_Adapter<T>::template get<Index>(std::declval<const T&>()));
|
||||
using member_type = std::remove_cvref_t<reference_type>;
|
||||
static constexpr std::size_t index = Index;
|
||||
static_assert(std::is_lvalue_reference_v<reference_type>);
|
||||
static_assert(std::is_lvalue_reference_v<const_reference_type>);
|
||||
static decltype(auto) get(T& object) noexcept(noexcept(Reflection_Adapter<T>::template get<Index>(object))) {
|
||||
@@ -83,8 +80,8 @@ inline std::string make_label(std::string_view name) {
|
||||
std::string result;
|
||||
result.reserve(name.size());
|
||||
bool uppercase = true;
|
||||
for (const char value : name) {
|
||||
if (value == '_') {
|
||||
for(const char value : name) {
|
||||
if(value == '_') {
|
||||
result.push_back(' ');
|
||||
uppercase = true;
|
||||
continue;
|
||||
@@ -94,111 +91,142 @@ inline std::string make_label(std::string_view name) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
template <class Derived, class Accessor>
|
||||
class Field_Descriptor_Base {
|
||||
struct Field_Metadata {
|
||||
std::string name;
|
||||
std::string label;
|
||||
std::string list_label;
|
||||
std::string description;
|
||||
std::string widget;
|
||||
std::string visible_on;
|
||||
std::map<std::string, std::string> enum_labels;
|
||||
bool editable{};
|
||||
bool creatable{};
|
||||
bool readable{true};
|
||||
bool sensitive{};
|
||||
bool include_default{true};
|
||||
bool visible{true};
|
||||
bool required{};
|
||||
bool list_visible{true};
|
||||
int order{-1};
|
||||
bool sortable{};
|
||||
};
|
||||
template <class Accessor, bool Managed_Writable = false, bool Synchronized = true>
|
||||
class Field_Descriptor {
|
||||
public:
|
||||
using field_descriptor_tag = void;
|
||||
using accessor_type = Accessor;
|
||||
using owner_type = typename Accessor::owner_type;
|
||||
using member_type = typename Accessor::member_type;
|
||||
explicit Field_Descriptor_Base(std::string name) : name_(std::move(name)), label_(make_label(name_)) {}
|
||||
Field_Descriptor_Base(std::string name, std::string label) : name_(std::move(name)), label_(std::move(label)) {}
|
||||
Derived editable(bool value = true) const {
|
||||
auto result = derived();
|
||||
result.editable_ = value;
|
||||
static constexpr bool managed_writable = Managed_Writable;
|
||||
static constexpr bool synchronized = Synchronized;
|
||||
explicit Field_Descriptor(std::string name) {
|
||||
metadata_.name = std::move(name);
|
||||
metadata_.label = make_label(metadata_.name);
|
||||
}
|
||||
Field_Descriptor(std::string name, std::string label) {
|
||||
metadata_.name = std::move(name);
|
||||
metadata_.label = std::move(label);
|
||||
}
|
||||
explicit Field_Descriptor(Field_Metadata metadata) : metadata_(std::move(metadata)) {}
|
||||
auto editable() const {
|
||||
auto result = rebind<true, Synchronized>();
|
||||
result.metadata_.editable = true;
|
||||
return result;
|
||||
}
|
||||
Derived locked(bool value = true) const {
|
||||
auto result = derived();
|
||||
result.lock_mode_ = value ? Field_Lock_Mode::enabled : Field_Lock_Mode::disabled;
|
||||
auto creatable() const {
|
||||
auto result = rebind<true, Synchronized>();
|
||||
result.metadata_.creatable = true;
|
||||
return result;
|
||||
}
|
||||
Derived creatable(bool value = true) const {
|
||||
auto result = derived();
|
||||
result.creatable_ = value;
|
||||
auto read_write() const {
|
||||
return rebind<true, Synchronized>();
|
||||
}
|
||||
auto unsynchronized() const {
|
||||
return rebind<Managed_Writable, false>();
|
||||
}
|
||||
Field_Descriptor readable(bool value = true) const {
|
||||
auto result = *this;
|
||||
result.metadata_.readable = value;
|
||||
return result;
|
||||
}
|
||||
Derived readable(bool value = true) const {
|
||||
auto result = derived();
|
||||
result.readable_ = value;
|
||||
return result;
|
||||
}
|
||||
Derived sensitive(bool value = true) const {
|
||||
auto result = derived();
|
||||
result.sensitive_ = value;
|
||||
Field_Descriptor sensitive(bool value = true) const {
|
||||
auto result = *this;
|
||||
result.metadata_.sensitive = value;
|
||||
if(value) {
|
||||
result.readable_ = false;
|
||||
result.include_default_ = false;
|
||||
result.metadata_.readable = false;
|
||||
result.metadata_.include_default = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Derived include_default(bool value = true) const {
|
||||
auto result = derived();
|
||||
result.include_default_ = value;
|
||||
Field_Descriptor include_default(bool value = true) const {
|
||||
auto result = *this;
|
||||
result.metadata_.include_default = value;
|
||||
return result;
|
||||
}
|
||||
Derived visible(bool value = true) const {
|
||||
auto result = derived();
|
||||
result.visible_ = value;
|
||||
Field_Descriptor visible(bool value = true) const {
|
||||
auto result = *this;
|
||||
result.metadata_.visible = value;
|
||||
return result;
|
||||
}
|
||||
Derived required(bool value = true) const {
|
||||
auto result = derived();
|
||||
result.required_ = value;
|
||||
Field_Descriptor required(bool value = true) const {
|
||||
auto result = *this;
|
||||
result.metadata_.required = value;
|
||||
return result;
|
||||
}
|
||||
Derived list_visible(bool value = true) const {
|
||||
auto result = derived();
|
||||
result.list_visible_ = value;
|
||||
Field_Descriptor list_visible(bool value = true) const {
|
||||
auto result = *this;
|
||||
result.metadata_.list_visible = value;
|
||||
return result;
|
||||
}
|
||||
Derived label(std::string value) const {
|
||||
auto result = derived();
|
||||
result.label_ = std::move(value);
|
||||
Field_Descriptor label(std::string value) const {
|
||||
auto result = *this;
|
||||
result.metadata_.label = std::move(value);
|
||||
return result;
|
||||
}
|
||||
Derived description(std::string value) const {
|
||||
auto result = derived();
|
||||
result.description_ = std::move(value);
|
||||
Field_Descriptor description(std::string value) const {
|
||||
auto result = *this;
|
||||
result.metadata_.description = std::move(value);
|
||||
return result;
|
||||
}
|
||||
Derived widget(std::string value) const {
|
||||
auto result = derived();
|
||||
result.widget_ = std::move(value);
|
||||
Field_Descriptor widget(std::string value) const {
|
||||
auto result = *this;
|
||||
result.metadata_.widget = std::move(value);
|
||||
return result;
|
||||
}
|
||||
Derived visible_on(std::string value) const {
|
||||
auto result = derived();
|
||||
result.visible_on_ = std::move(value);
|
||||
Field_Descriptor visible_on(std::string value) const {
|
||||
auto result = *this;
|
||||
result.metadata_.visible_on = std::move(value);
|
||||
return result;
|
||||
}
|
||||
Derived list_label(std::string value) const {
|
||||
auto result = derived();
|
||||
result.list_label_ = std::move(value);
|
||||
Field_Descriptor list_label(std::string value) const {
|
||||
auto result = *this;
|
||||
result.metadata_.list_label = std::move(value);
|
||||
return result;
|
||||
}
|
||||
Derived order(int value) const {
|
||||
auto result = derived();
|
||||
result.order_ = value;
|
||||
Field_Descriptor order(int value) const {
|
||||
auto result = *this;
|
||||
result.metadata_.order = value;
|
||||
return result;
|
||||
}
|
||||
Derived sortable(bool value = true) const {
|
||||
auto result = derived();
|
||||
result.sortable_ = value;
|
||||
Field_Descriptor sortable(bool value = true) const {
|
||||
auto result = *this;
|
||||
result.metadata_.sortable = value;
|
||||
return result;
|
||||
}
|
||||
template <auto Value>
|
||||
requires Enum_Type<std::remove_cv_t<decltype(Value)>>
|
||||
Derived enum_label(std::string label) const {
|
||||
Field_Descriptor enum_label(std::string label) const {
|
||||
const auto name = enum_name(Value);
|
||||
if (name.empty()) {
|
||||
if(name.empty()) {
|
||||
throw std::invalid_argument("enum adapter returned an empty value name");
|
||||
}
|
||||
auto result = derived();
|
||||
result.enum_labels_.insert_or_assign(std::string(name), std::move(label));
|
||||
auto result = *this;
|
||||
result.metadata_.enum_labels.insert_or_assign(std::string(name), std::move(label));
|
||||
return result;
|
||||
}
|
||||
Derived enum_label(std::string value_name, std::string label) const {
|
||||
auto result = derived();
|
||||
result.enum_labels_.insert_or_assign(std::move(value_name), std::move(label));
|
||||
Field_Descriptor enum_label(std::string value_name, std::string label) const {
|
||||
auto result = *this;
|
||||
result.metadata_.enum_labels.insert_or_assign(std::move(value_name), std::move(label));
|
||||
return result;
|
||||
}
|
||||
template <class Object>
|
||||
@@ -212,112 +240,81 @@ public:
|
||||
return Accessor::get(object);
|
||||
}
|
||||
const std::string& name() const noexcept {
|
||||
return name_;
|
||||
return metadata_.name;
|
||||
}
|
||||
const std::string& label() const noexcept {
|
||||
return label_;
|
||||
return metadata_.label;
|
||||
}
|
||||
const std::string& list_label() const noexcept {
|
||||
return list_label_.empty() ? label_ : list_label_;
|
||||
return metadata_.list_label.empty() ? metadata_.label : metadata_.list_label;
|
||||
}
|
||||
const std::string& description() const noexcept {
|
||||
return description_;
|
||||
return metadata_.description;
|
||||
}
|
||||
const std::string& widget() const noexcept {
|
||||
return widget_;
|
||||
return metadata_.widget;
|
||||
}
|
||||
const std::string& visible_on() const noexcept {
|
||||
return visible_on_;
|
||||
return metadata_.visible_on;
|
||||
}
|
||||
const std::map<std::string, std::string>& enum_labels() const noexcept {
|
||||
return enum_labels_;
|
||||
return metadata_.enum_labels;
|
||||
}
|
||||
bool is_editable() const noexcept {
|
||||
return editable_;
|
||||
}
|
||||
Field_Lock_Mode lock_mode() const noexcept {
|
||||
return lock_mode_;
|
||||
return metadata_.editable;
|
||||
}
|
||||
bool is_creatable() const noexcept {
|
||||
return creatable_;
|
||||
return metadata_.creatable;
|
||||
}
|
||||
bool is_readable() const noexcept {
|
||||
return readable_;
|
||||
return metadata_.readable;
|
||||
}
|
||||
bool is_sensitive() const noexcept {
|
||||
return sensitive_;
|
||||
return metadata_.sensitive;
|
||||
}
|
||||
bool includes_default() const noexcept {
|
||||
return include_default_;
|
||||
return metadata_.include_default;
|
||||
}
|
||||
bool is_visible() const noexcept {
|
||||
return visible_;
|
||||
return metadata_.visible;
|
||||
}
|
||||
bool is_required() const noexcept {
|
||||
return required_;
|
||||
return metadata_.required;
|
||||
}
|
||||
int order() const noexcept {
|
||||
return order_;
|
||||
return metadata_.order;
|
||||
}
|
||||
bool is_sortable() const noexcept {
|
||||
return sortable_;
|
||||
return metadata_.sortable;
|
||||
}
|
||||
bool is_list_visible() const noexcept {
|
||||
return list_visible_;
|
||||
}
|
||||
protected:
|
||||
const Derived& derived() const noexcept {
|
||||
return static_cast<const Derived&>(*this);
|
||||
return metadata_.list_visible;
|
||||
}
|
||||
private:
|
||||
std::string name_;
|
||||
std::string label_;
|
||||
std::string list_label_;
|
||||
std::string description_;
|
||||
std::string widget_;
|
||||
std::string visible_on_;
|
||||
std::map<std::string, std::string> enum_labels_;
|
||||
bool editable_{};
|
||||
Field_Lock_Mode lock_mode_{Field_Lock_Mode::automatic};
|
||||
bool creatable_{};
|
||||
bool readable_{true};
|
||||
bool sensitive_{};
|
||||
bool include_default_{true};
|
||||
bool visible_{true};
|
||||
bool required_{};
|
||||
bool list_visible_{true};
|
||||
int order_{-1};
|
||||
bool sortable_{};
|
||||
};
|
||||
template <auto Member>
|
||||
class Field_Descriptor : public Field_Descriptor_Base<Field_Descriptor<Member>, Member_Field_Accessor<Member>> {
|
||||
public:
|
||||
using Base = Field_Descriptor_Base<Field_Descriptor<Member>, Member_Field_Accessor<Member>>;
|
||||
using Base::Base;
|
||||
static constexpr auto member = Member;
|
||||
};
|
||||
template <class T, std::size_t Index>
|
||||
class Reflected_Field_Descriptor : public Field_Descriptor_Base<Reflected_Field_Descriptor<T, Index>, Reflected_Field_Accessor<T, Index>> {
|
||||
public:
|
||||
using Base = Field_Descriptor_Base<Reflected_Field_Descriptor<T, Index>, Reflected_Field_Accessor<T, Index>>;
|
||||
using Base::Base;
|
||||
static constexpr std::size_t index = Index;
|
||||
template <bool New_Writable, bool New_Synchronized>
|
||||
auto rebind() const {
|
||||
return Field_Descriptor<Accessor, New_Writable, New_Synchronized>(metadata_);
|
||||
}
|
||||
template <class, bool, bool>
|
||||
friend class Field_Descriptor;
|
||||
Field_Metadata metadata_;
|
||||
};
|
||||
template <class T>
|
||||
struct Is_Field_Descriptor : std::false_type {};
|
||||
template <auto Member>
|
||||
struct Is_Field_Descriptor<Field_Descriptor<Member>> : std::true_type {};
|
||||
template <class T, std::size_t Index>
|
||||
struct Is_Field_Descriptor<Reflected_Field_Descriptor<T, Index>> : std::true_type {};
|
||||
template <class T>
|
||||
concept Field_Descriptor_Type = Is_Field_Descriptor<std::remove_cvref_t<T>>::value;
|
||||
concept Field_Descriptor_Type = requires {
|
||||
typename std::remove_cvref_t<T>::field_descriptor_tag;
|
||||
typename std::remove_cvref_t<T>::owner_type;
|
||||
typename std::remove_cvref_t<T>::member_type;
|
||||
typename std::remove_cvref_t<T>::accessor_type;
|
||||
{ std::remove_cvref_t<T>::managed_writable } -> std::convertible_to<bool>;
|
||||
{ std::remove_cvref_t<T>::synchronized } -> std::convertible_to<bool>;
|
||||
};
|
||||
template <auto Member>
|
||||
auto field(std::string name) {
|
||||
return Field_Descriptor<Member>(std::move(name));
|
||||
return Field_Descriptor<Member_Field_Accessor<Member>>(std::move(name));
|
||||
}
|
||||
template <auto Member>
|
||||
auto field(std::string name, std::string label) {
|
||||
return Field_Descriptor<Member>(std::move(name), std::move(label));
|
||||
return Field_Descriptor<Member_Field_Accessor<Member>>(std::move(name), std::move(label));
|
||||
}
|
||||
template <Reflected_Type T, std::size_t Index>
|
||||
auto reflected_field() {
|
||||
@@ -326,7 +323,7 @@ auto reflected_field() {
|
||||
if(name.empty()) {
|
||||
throw std::invalid_argument("reflected field name must not be empty");
|
||||
}
|
||||
return Reflected_Field_Descriptor<T, Index>(name);
|
||||
return Field_Descriptor<Reflected_Field_Accessor<T, Index>>(name);
|
||||
}
|
||||
template <Reflected_Type T, std::size_t Index>
|
||||
auto reflected_field(std::string label) {
|
||||
@@ -335,7 +332,7 @@ auto reflected_field(std::string label) {
|
||||
if(name.empty()) {
|
||||
throw std::invalid_argument("reflected field name must not be empty");
|
||||
}
|
||||
return Reflected_Field_Descriptor<T, Index>(name, std::move(label));
|
||||
return Field_Descriptor<Reflected_Field_Accessor<T, Index>>(name, std::move(label));
|
||||
}
|
||||
struct No_Object_Validator {
|
||||
template <class T>
|
||||
@@ -361,6 +358,7 @@ class Object_Descriptor {
|
||||
public:
|
||||
using object_type = T;
|
||||
using validator_type = Validator;
|
||||
using fields_type = std::tuple<Fields...>;
|
||||
Object_Descriptor(std::string name, std::string label, Validator validator, std::tuple<Fields...> fields, Object_List_Options list_options = {}) : name_(std::move(name)), label_(std::move(label)), validator_(std::move(validator)), fields_(std::move(fields)), list_options_(std::move(list_options)) {}
|
||||
template <class New_Validator>
|
||||
auto validator(New_Validator value) const {
|
||||
@@ -538,6 +536,32 @@ auto describe() {
|
||||
validate_descriptor(descriptor);
|
||||
return descriptor;
|
||||
}
|
||||
template <class T>
|
||||
using Descriptor_Type = std::remove_cvref_t<decltype(Type_Descriptor<std::remove_cvref_t<T>>::get())>;
|
||||
template <class T>
|
||||
using Descriptor_Fields = typename Descriptor_Type<T>::fields_type;
|
||||
template <class T, std::size_t Index>
|
||||
using Descriptor_Field = std::tuple_element_t<Index, Descriptor_Fields<T>>;
|
||||
template <Described_Type T>
|
||||
consteval bool described_type_has_managed_writes();
|
||||
template <class Field>
|
||||
consteval bool field_has_managed_writes() {
|
||||
if constexpr(Field::managed_writable) {
|
||||
return true;
|
||||
} else if constexpr(Described_Type<typename Field::member_type>) {
|
||||
return described_type_has_managed_writes<typename Field::member_type>();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
template <Described_Type T, std::size_t... Indexes>
|
||||
consteval bool described_type_has_managed_writes_impl(std::index_sequence<Indexes...>) {
|
||||
return (field_has_managed_writes<Descriptor_Field<T, Indexes>>() || ...);
|
||||
}
|
||||
template <Described_Type T>
|
||||
consteval bool described_type_has_managed_writes() {
|
||||
return described_type_has_managed_writes_impl<T>(std::make_index_sequence<std::tuple_size_v<Descriptor_Fields<T>>>{});
|
||||
}
|
||||
}
|
||||
#define ADMINIVE_FIELD(Type, Member) ::adminive::field<&Type::Member>(#Member)
|
||||
#define ADMINIVE_FIELD_LABEL(Type, Member, Label) ::adminive::field<&Type::Member>(#Member, Label)
|
||||
|
||||
Reference in New Issue
Block a user