From aa24ed37e885ec4cc1f0a7be8280e7af5fde6ea3 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 12 Feb 2022 08:07:46 +0700 Subject: [PATCH] binds opts with metadata --- headers/meta.hpp/meta_binds.hpp | 244 +++++++++++++++----- headers/meta.hpp/meta_binds/class_bind.hpp | 211 +++++++++++++++--- headers/meta.hpp/meta_binds/enum_bind.hpp | 19 +- headers/meta.hpp/meta_binds/scope_bind.hpp | 91 ++++++-- untests/meta_states/metadata_tests.cpp | 246 +++++++++++++++++++++ untests/meta_utilities/arg_tests.cpp | 4 +- untests/meta_utilities/inst_tests.cpp | 4 +- 7 files changed, 711 insertions(+), 108 deletions(-) create mode 100644 untests/meta_states/metadata_tests.cpp diff --git a/headers/meta.hpp/meta_binds.hpp b/headers/meta.hpp/meta_binds.hpp index ae030af..d3aa25f 100644 --- a/headers/meta.hpp/meta_binds.hpp +++ b/headers/meta.hpp/meta_binds.hpp @@ -9,42 +9,98 @@ #include "meta_base.hpp" #include "meta_states.hpp" +namespace meta_hpp::detail +{ + template < typename Class, typename... Args > + concept class_bind_constructor_kind = + class_kind && + requires(Args&&... args) { { Class{std::forward(args)...} }; }; + + template < typename Class > + concept class_bind_destructor_kind = + class_kind && + requires(Class&& inst) { { inst.~Class() }; }; + + template < typename Class, typename Base > + concept class_bind_base_kind = + class_kind && class_kind && + stdex::derived_from; + + template < typename Class, typename Member > + concept class_bind_member_kind = + class_kind && member_kind && + stdex::same_as::class_type>; + + template < typename Class, typename Method > + concept class_bind_method_kind = + class_kind && method_kind && + stdex::same_as::class_type>; +} + namespace meta_hpp { - namespace detail - { - template < typename Class, typename... Args > - concept class_bind_constructor_kind = - class_kind && - requires(Args&&... args) { { Class{std::forward(args)...} }; }; + struct class_opts final { + metadata_map metadata{}; + }; - template < typename Class > - concept class_bind_destructor_kind = - class_kind && - requires(Class&& inst) { { inst.~Class() }; }; + struct enum_opts final { + metadata_map metadata{}; + }; - template < typename Class, typename Base > - concept class_bind_base_kind = - class_kind && class_kind && - stdex::derived_from; + struct scope_opts final { + metadata_map metadata{}; + }; +} - template < typename Class, typename Member > - concept class_bind_member_kind = - class_kind && member_kind && - stdex::same_as::class_type>; +namespace meta_hpp +{ + struct argument_opts final { + std::string name{}; + metadata_map metadata{}; + }; - template < typename Class, typename Method > - concept class_bind_method_kind = - class_kind && method_kind && - stdex::same_as::class_type>; - } + struct constructor_opts final { + std::vector arguments{}; + metadata_map metadata{}; + }; + struct destructor_opts final { + metadata_map metadata{}; + }; + + struct evalue_opts final { + metadata_map metadata{}; + }; + + struct function_opts final { + std::vector arguments{}; + metadata_map metadata{}; + }; + + struct member_opts final { + metadata_map metadata{}; + }; + + struct method_opts final { + std::vector arguments{}; + metadata_map metadata{}; + }; + + struct variable_opts final { + metadata_map metadata{}; + }; +} + +namespace meta_hpp +{ template < detail::class_kind Class > class class_bind final { public: - explicit class_bind(); + explicit class_bind(class_opts opts); operator class_type() const noexcept; + // constructor_ + template < typename... Args , constructor_policy_kind Policy = constructor_policy::as_object > class_bind& constructor_(Policy = Policy{}) @@ -52,38 +108,75 @@ namespace meta_hpp template < typename... Args , constructor_policy_kind Policy = constructor_policy::as_object > - class_bind& constructor_( - std::initializer_list anames, - Policy = Policy{}) + class_bind& constructor_(constructor_opts opts, Policy = Policy{}) requires detail::class_bind_constructor_kind; + // destructor_ + class_bind& destructor_() requires detail::class_bind_destructor_kind; + class_bind& destructor_(destructor_opts opts) + requires detail::class_bind_destructor_kind; + + // base_ + template < detail::class_kind Base > class_bind& base_() requires detail::class_bind_base_kind; - template < detail::function_kind Function - , function_policy_kind Policy = function_policy::as_copy > - class_bind& function_(std::string name, Function function, Policy = Policy{}); + // function_ template < detail::function_kind Function , function_policy_kind Policy = function_policy::as_copy > class_bind& function_( std::string name, Function function, - std::initializer_list anames, Policy = Policy{}); + template < detail::function_kind Function + , function_policy_kind Policy = function_policy::as_copy > + class_bind& function_( + std::string name, + Function function, + function_opts opts, + Policy = Policy{}); + + template < detail::function_kind Function + , function_policy_kind Policy = function_policy::as_copy > + class_bind& function_( + std::string name, + Function function, + std::initializer_list arguments, + Policy = Policy{}); + + // member_ + template < detail::member_kind Member , member_policy_kind Policy = member_policy::as_copy > - class_bind& member_(std::string name, Member member, Policy = Policy{}) + class_bind& member_( + std::string name, + Member member, + Policy = Policy{}) requires detail::class_bind_member_kind; + template < detail::member_kind Member + , member_policy_kind Policy = member_policy::as_copy > + class_bind& member_( + std::string name, + Member member, + member_opts opts, + Policy = Policy{}) + requires detail::class_bind_member_kind; + + // method_ + template < detail::method_kind Method , method_policy_kind Policy = method_policy::as_copy > - class_bind& method_(std::string name, Method method, Policy = Policy{}) + class_bind& method_( + std::string name, + Method method, + Policy = Policy{}) requires detail::class_bind_method_kind; template < detail::method_kind Method @@ -91,13 +184,35 @@ namespace meta_hpp class_bind& method_( std::string name, Method method, - std::initializer_list anames, + method_opts opts, Policy = Policy{}) requires detail::class_bind_method_kind; + template < detail::method_kind Method + , method_policy_kind Policy = method_policy::as_copy > + class_bind& method_( + std::string name, + Method method, + std::initializer_list arguments, + Policy = Policy{}) + requires detail::class_bind_method_kind; + + // variable_ + template < detail::pointer_kind Pointer , variable_policy_kind Policy = variable_policy::as_copy > - class_bind& variable_(std::string name, Pointer pointer, Policy = Policy{}); + class_bind& variable_( + std::string name, + Pointer pointer, + Policy = Policy{}); + + template < detail::pointer_kind Pointer + , variable_policy_kind Policy = variable_policy::as_copy > + class_bind& variable_( + std::string name, + Pointer pointer, + variable_opts opts, + Policy = Policy{}); private: detail::class_type_data_ptr data_; }; @@ -108,10 +223,11 @@ namespace meta_hpp template < detail::enum_kind Enum > class enum_bind final { public: - explicit enum_bind(); + explicit enum_bind(enum_opts opts); operator enum_type() const noexcept; enum_bind& evalue_(std::string name, Enum value); + enum_bind& evalue_(std::string name, Enum value, evalue_opts opts); private: detail::enum_type_data_ptr data_; }; @@ -124,8 +240,8 @@ namespace meta_hpp struct local_tag {}; struct static_tag {}; - explicit scope_bind(std::string name, local_tag); - explicit scope_bind(std::string_view name, static_tag); + explicit scope_bind(std::string name, scope_opts opts, local_tag); + explicit scope_bind(std::string_view name, scope_opts opts, static_tag); operator scope() const noexcept; template < detail::class_kind Class > @@ -134,21 +250,47 @@ namespace meta_hpp template < detail::enum_kind Enum > scope_bind& enum_(std::string name); - template < detail::function_kind Function - , function_policy_kind Policy = function_policy::as_copy > - scope_bind& function_(std::string name, Function function, Policy = Policy{}); + // function_ template < detail::function_kind Function , function_policy_kind Policy = function_policy::as_copy > scope_bind& function_( std::string name, Function function, - std::initializer_list anames, + Policy = Policy{}); + + template < detail::function_kind Function + , function_policy_kind Policy = function_policy::as_copy > + scope_bind& function_( + std::string name, + Function function, + function_opts opts, + Policy = Policy{}); + + template < detail::function_kind Function + , function_policy_kind Policy = function_policy::as_copy > + scope_bind& function_( + std::string name, + Function function, + std::initializer_list arguments, + Policy = Policy{}); + + // variable_ + + template < detail::pointer_kind Pointer + , variable_policy_kind Policy = variable_policy::as_copy > + scope_bind& variable_( + std::string name, + Pointer pointer, Policy = Policy{}); template < detail::pointer_kind Pointer , variable_policy_kind Policy = variable_policy::as_copy > - scope_bind& variable_(std::string name, Pointer pointer, Policy = Policy{}); + scope_bind& variable_( + std::string name, + Pointer pointer, + variable_opts opts, + Policy = Policy{}); private: detail::scope_state_ptr state_; }; @@ -157,20 +299,20 @@ namespace meta_hpp namespace meta_hpp { template < detail::class_kind Class > - class_bind class_() { - return class_bind{}; + class_bind class_(class_opts opts = {}) { + return class_bind{std::move(opts)}; } template < detail::enum_kind Enum > - enum_bind enum_() { - return enum_bind{}; + enum_bind enum_(enum_opts opts = {}) { + return enum_bind{std::move(opts)}; } - inline scope_bind local_scope_(std::string name) { - return scope_bind{std::move(name), scope_bind::local_tag()}; + inline scope_bind local_scope_(std::string name, scope_opts opts = {}) { + return scope_bind{std::move(name), std::move(opts), scope_bind::local_tag()}; } - inline scope_bind static_scope_(std::string_view name) { - return scope_bind{name, scope_bind::static_tag()}; + inline scope_bind static_scope_(std::string_view name, scope_opts opts = {}) { + return scope_bind{name, std::move(opts), scope_bind::static_tag()}; } } diff --git a/headers/meta.hpp/meta_binds/class_bind.hpp b/headers/meta.hpp/meta_binds/class_bind.hpp index 1bcc488..034fd61 100644 --- a/headers/meta.hpp/meta_binds/class_bind.hpp +++ b/headers/meta.hpp/meta_binds/class_bind.hpp @@ -14,14 +14,21 @@ namespace meta_hpp { template < detail::class_kind Class > - class_bind::class_bind() - : data_{detail::type_access(detail::resolve_type())} {} + class_bind::class_bind(class_opts opts) + : data_{detail::type_access(detail::resolve_type())} { + data_->metadata.swap(opts.metadata); + data_->metadata.merge(opts.metadata); + } template < detail::class_kind Class > class_bind::operator class_type() const noexcept { return class_type{data_}; } + // + // constructor_ + // + template < detail::class_kind Class > template < typename... Args, constructor_policy_kind Policy > class_bind& class_bind::constructor_(Policy policy) @@ -33,34 +40,50 @@ namespace meta_hpp template < detail::class_kind Class > template < typename... Args, constructor_policy_kind Policy > class_bind& class_bind::constructor_( - std::initializer_list anames, + constructor_opts opts, [[maybe_unused]] Policy policy) requires detail::class_bind_constructor_kind { - auto constructor_state = detail::constructor_state::make(); + auto state = detail::constructor_state::make(std::move(opts.metadata)); - if ( anames.size() > constructor_state->arguments.size() ) { + if ( opts.arguments.size() > state->arguments.size() ) { detail::throw_exception_with("provided argument names don't match constructor argument count"); } - for ( std::size_t i = 0; i < anames.size(); ++i ) { - argument& arg = constructor_state->arguments[i]; - detail::state_access(arg)->name = std::string{std::data(anames)[i]}; + for ( std::size_t i = 0; i < opts.arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::move(opts.arguments[i].name); + detail::state_access(arg)->metadata = std::move(opts.arguments[i].metadata); } - data_->constructors.emplace(constructor_state->index, std::move(constructor_state)); + data_->constructors.insert_or_assign(state->index, std::move(state)); return *this; } + // + // destructor_ + // + template < detail::class_kind Class > class_bind& class_bind::destructor_() requires detail::class_bind_destructor_kind { - auto destructor_state = detail::destructor_state::make(); - data_->destructors.emplace(destructor_state->index, std::move(destructor_state)); + return destructor_({}); + } + + template < detail::class_kind Class > + class_bind& class_bind::destructor_(destructor_opts opts) + requires detail::class_bind_destructor_kind + { + auto state = detail::destructor_state::make(std::move(opts.metadata)); + data_->destructors.insert_or_assign(state->index, std::move(state)); return *this; } + // + // base_ + // + template < detail::class_kind Class > template < detail::class_kind Base > class_bind& class_bind::base_() @@ -75,9 +98,17 @@ namespace meta_hpp return *this; } + // + // function_ + // + template < detail::class_kind Class > template < detail::function_kind Function, function_policy_kind Policy > - class_bind& class_bind::function_(std::string name, Function function, Policy policy) { + class_bind& class_bind::function_( + std::string name, + Function function, + Policy policy) + { return function_(std::move(name), std::move(function), {}, policy); } @@ -86,37 +117,96 @@ namespace meta_hpp class_bind& class_bind::function_( std::string name, Function function, - std::initializer_list anames, + function_opts opts, [[maybe_unused]] Policy policy) { - auto function_state = detail::function_state::make(std::move(name), std::move(function)); + auto state = detail::function_state::make( + std::move(name), + std::move(function), + std::move(opts.metadata)); - if ( anames.size() > function_state->arguments.size() ) { + if ( opts.arguments.size() > state->arguments.size() ) { + detail::throw_exception_with("provided arguments don't match function argument count"); + } + + for ( std::size_t i = 0; i < opts.arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::move(opts.arguments[i].name); + detail::state_access(arg)->metadata = std::move(opts.arguments[i].metadata); + } + + data_->functions.insert_or_assign(state->index, std::move(state)); + return *this; + } + + template < detail::class_kind Class > + template < detail::function_kind Function, function_policy_kind Policy > + class_bind& class_bind::function_( + std::string name, + Function function, + std::initializer_list arguments, + [[maybe_unused]] Policy policy) + { + auto state = detail::function_state::make( + std::move(name), + std::move(function), + {}); + + if ( arguments.size() > state->arguments.size() ) { detail::throw_exception_with("provided argument names don't match function argument count"); } - for ( std::size_t i = 0; i < anames.size(); ++i ) { - argument& arg = function_state->arguments[i]; - detail::state_access(arg)->name = std::string{std::data(anames)[i]}; + for ( std::size_t i = 0; i < arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::data(arguments)[i]; } - data_->functions.emplace(function_state->index, std::move(function_state)); + data_->functions.insert_or_assign(state->index, std::move(state)); return *this; } + // + // member_ + // + + template < detail::class_kind Class > + template < detail::member_kind Member, member_policy_kind Policy > + class_bind& class_bind::member_( + std::string name, + Member member, + Policy policy) + requires detail::class_bind_member_kind + { + return member_(std::move(name), std::move(member), {}, policy); + } + template < detail::class_kind Class > template < detail::member_kind Member, member_policy_kind Policy > - class_bind& class_bind::member_(std::string name, Member member, [[maybe_unused]] Policy policy) + class_bind& class_bind::member_( + std::string name, + Member member, + member_opts opts, + [[maybe_unused]] Policy policy) requires detail::class_bind_member_kind { - auto member_state = detail::member_state::make(std::move(name), std::move(member)); - data_->members.emplace(member_state->index, std::move(member_state)); + auto state = detail::member_state::make( + std::move(name), + std::move(member), + std::move(opts.metadata)); + data_->members.insert_or_assign(state->index, std::move(state)); return *this; } + // + // method_ + // + template < detail::class_kind Class > template < detail::method_kind Method, method_policy_kind Policy > - class_bind& class_bind::method_(std::string name, Method method, Policy policy) + class_bind& class_bind::method_( + std::string name, + Method method, + Policy policy) requires detail::class_bind_method_kind { return method_(std::move(name), std::move(method), {}, policy); @@ -127,30 +217,83 @@ namespace meta_hpp class_bind& class_bind::method_( std::string name, Method method, - std::initializer_list anames, + method_opts opts, [[maybe_unused]] Policy policy) requires detail::class_bind_method_kind { - auto method_state = detail::method_state::make(std::move(name), std::move(method)); + auto state = detail::method_state::make( + std::move(name), + std::move(method), + std::move(opts.metadata)); - if ( anames.size() > method_state->arguments.size() ) { - detail::throw_exception_with("provided argument names don't match method argument count"); + if ( opts.arguments.size() > state->arguments.size() ) { + detail::throw_exception_with("provided arguments don't match method argument count"); } - for ( std::size_t i = 0; i < anames.size(); ++i ) { - argument& arg = method_state->arguments[i]; - detail::state_access(arg)->name = std::string{std::data(anames)[i]}; + for ( std::size_t i = 0; i < opts.arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::move(opts.arguments[i].name); + detail::state_access(arg)->metadata = std::move(opts.arguments[i].metadata); } - data_->methods.emplace(method_state->index, std::move(method_state)); + data_->methods.insert_or_assign(state->index, std::move(state)); return *this; } + template < detail::class_kind Class > + template < detail::method_kind Method, method_policy_kind Policy > + class_bind& class_bind::method_( + std::string name, + Method method, + std::initializer_list arguments, + [[maybe_unused]] Policy policy) + requires detail::class_bind_method_kind + { + auto state = detail::method_state::make( + std::move(name), + std::move(method), + {}); + + if ( arguments.size() > state->arguments.size() ) { + detail::throw_exception_with("provided argument names don't match method argument count"); + } + + for ( std::size_t i = 0; i < arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::data(arguments)[i]; + } + + data_->methods.insert_or_assign(state->index, std::move(state)); + return *this; + } + + // + // variable_ + // + template < detail::class_kind Class > template < detail::pointer_kind Pointer, variable_policy_kind Policy > - class_bind& class_bind::variable_( std::string name, Pointer pointer, [[maybe_unused]] Policy policy) { - auto variable_state = detail::variable_state::make(std::move(name), std::move(pointer)); - data_->variables.emplace(variable_state->index, std::move(variable_state)); + class_bind& class_bind::variable_( + std::string name, + Pointer pointer, + Policy policy) + { + return variable_(std::move(name), std::move(pointer), {}, policy); + } + + template < detail::class_kind Class > + template < detail::pointer_kind Pointer, variable_policy_kind Policy > + class_bind& class_bind::variable_( + std::string name, + Pointer pointer, + variable_opts opts, + [[maybe_unused]] Policy policy) + { + auto state = detail::variable_state::make( + std::move(name), + std::move(pointer), + std::move(opts.metadata)); + data_->variables.insert_or_assign(state->index, std::move(state)); return *this; } } diff --git a/headers/meta.hpp/meta_binds/enum_bind.hpp b/headers/meta.hpp/meta_binds/enum_bind.hpp index 4ea73de..5c347b3 100644 --- a/headers/meta.hpp/meta_binds/enum_bind.hpp +++ b/headers/meta.hpp/meta_binds/enum_bind.hpp @@ -14,8 +14,11 @@ namespace meta_hpp { template < detail::enum_kind Enum > - enum_bind::enum_bind() - : data_{detail::type_access(detail::resolve_type())} {} + enum_bind::enum_bind(enum_opts opts) + : data_{detail::type_access(detail::resolve_type())} { + data_->metadata.swap(opts.metadata); + data_->metadata.merge(opts.metadata); + } template < detail::enum_kind Enum > enum_bind::operator enum_type() const noexcept { @@ -24,8 +27,16 @@ namespace meta_hpp template < detail::enum_kind Enum > enum_bind& enum_bind::evalue_(std::string name, Enum value) { - auto evalue_state = detail::evalue_state::make(std::move(name), std::move(value)); - data_->evalues.emplace(evalue_state->index, std::move(evalue_state)); + return evalue_(std::move(name), std::move(value), {}); + } + + template < detail::enum_kind Enum > + enum_bind& enum_bind::evalue_(std::string name, Enum value, evalue_opts opts) { + auto state = detail::evalue_state::make( + std::move(name), + std::move(value), + std::move(opts.metadata)); + data_->evalues.insert_or_assign(state->index, std::move(state)); return *this; } } diff --git a/headers/meta.hpp/meta_binds/scope_bind.hpp b/headers/meta.hpp/meta_binds/scope_bind.hpp index 66859c4..5ed613d 100644 --- a/headers/meta.hpp/meta_binds/scope_bind.hpp +++ b/headers/meta.hpp/meta_binds/scope_bind.hpp @@ -15,12 +15,15 @@ namespace meta_hpp { // NOLINTNEXTLINE(readability-named-parameter) - inline scope_bind::scope_bind(std::string name, local_tag) - : state_{detail::scope_state::make(std::move(name))} {} + inline scope_bind::scope_bind(std::string name, scope_opts opts, local_tag) + : state_{detail::scope_state::make(std::move(name), std::move(opts.metadata))} {} // NOLINTNEXTLINE(readability-named-parameter) - inline scope_bind::scope_bind(std::string_view name, static_tag) - : state_{detail::state_access(detail::resolve_scope(name))} {} + inline scope_bind::scope_bind(std::string_view name, scope_opts opts, static_tag) + : state_{detail::state_access(detail::resolve_scope(name))} { + state_->metadata.swap(opts.metadata); + state_->metadata.merge(opts.metadata); + } inline scope_bind::operator scope() const noexcept { return scope{state_}; @@ -38,8 +41,16 @@ namespace meta_hpp return *this; } + // + // function_ + // + template < detail::function_kind Function, function_policy_kind Policy > - scope_bind& scope_bind::function_(std::string name, Function function, Policy policy) { + scope_bind& scope_bind::function_( + std::string name, + Function function, + Policy policy) + { return function_(std::move(name), std::move(function), {}, policy); } @@ -47,28 +58,78 @@ namespace meta_hpp scope_bind& scope_bind::function_( std::string name, Function function, - std::initializer_list anames, + function_opts opts, [[maybe_unused]] Policy policy) { - auto function_state = detail::function_state::make(std::move(name), std::move(function)); + auto state = detail::function_state::make( + std::move(name), + std::move(function), + std::move(opts.metadata)); - if ( anames.size() > function_state->arguments.size() ) { + if ( opts.arguments.size() > state->arguments.size() ) { + detail::throw_exception_with("provided arguments don't match function argument count"); + } + + for ( std::size_t i = 0; i < opts.arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::move(opts.arguments[i].name); + detail::state_access(arg)->metadata = std::move(opts.arguments[i].metadata); + } + + state_->functions.insert_or_assign(state->index, std::move(state)); + return *this; + } + + template < detail::function_kind Function, function_policy_kind Policy > + scope_bind& scope_bind::function_( + std::string name, + Function function, + std::initializer_list arguments, + [[maybe_unused]] Policy policy) + { + auto state = detail::function_state::make( + std::move(name), + std::move(function), + {}); + + if ( arguments.size() > state->arguments.size() ) { detail::throw_exception_with("provided argument names don't match function argument count"); } - for ( std::size_t i = 0; i < anames.size(); ++i ) { - argument& arg = function_state->arguments[i]; - detail::state_access(arg)->name = std::string{std::data(anames)[i]}; + for ( std::size_t i = 0; i < arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::data(arguments)[i]; } - state_->functions.emplace(function_state->index, std::move(function_state)); + state_->functions.insert_or_assign(state->index, std::move(state)); return *this; } + // + // variable_ + // + + template < detail::pointer_kind Pointer, variable_policy_kind Policy > + scope_bind& scope_bind::variable_( + std::string name, + Pointer pointer, + Policy policy) + { + return variable_(std::move(name), std::move(pointer), {}, policy); + } + template < detail::pointer_kind Pointer, variable_policy_kind Policy > - scope_bind& scope_bind::variable_(std::string name, Pointer pointer, [[maybe_unused]] Policy policy) { - auto variable_state = detail::variable_state::make(std::move(name), std::move(pointer)); - state_->variables.emplace(variable_state->index, std::move(variable_state)); + scope_bind& scope_bind::variable_( + std::string name, + Pointer pointer, + variable_opts opts, + [[maybe_unused]] Policy policy) + { + auto state = detail::variable_state::make( + std::move(name), + std::move(pointer), + std::move(opts.metadata)); + state_->variables.insert_or_assign(state->index, std::move(state)); return *this; } } diff --git a/untests/meta_states/metadata_tests.cpp b/untests/meta_states/metadata_tests.cpp new file mode 100644 index 0000000..07794b0 --- /dev/null +++ b/untests/meta_states/metadata_tests.cpp @@ -0,0 +1,246 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/meta.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2021-2022, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include "../meta_untests.hpp" + +namespace +{ + enum class color : unsigned { + red = 0xFF0000, + green = 0x00FF00, + blue = 0x0000FF, + }; + + struct ivec2 { + int x{}; + int y{}; + + explicit ivec2(int v) : x{v}, y{v} {} + ivec2(int x, int y) : x{x}, y{y} {} + + ivec2& add(const ivec2& other) noexcept { + x += other.x; + y += other.y; + return *this; + } + + static ivec2 iadd(const ivec2& l, const ivec2& r) noexcept { + return {l.x + r.x, l.y + r.y}; + } + }; +} + +TEST_CASE("meta/meta_states/metadata/enum") { + namespace meta = meta_hpp; + using namespace std::string_literals; + + meta::enum_({ + .metadata{ + {"desc1", meta::uvalue{"enum-desc1"s}}, + {"desc2", meta::uvalue{"enum-desc2"s}}, + } + }) + .evalue_("red", color::red, { + .metadata{{"desc1", meta::uvalue{"red-color"s}}} + }) + .evalue_("green", color::green, { + .metadata{{"desc1", meta::uvalue{"green-color"s}}} + }) + .evalue_("blue", color::blue, { + .metadata{{"desc1", meta::uvalue{"blue-color"s}}} + }); + + // metadata override + + meta::enum_({ + .metadata{ + {"desc2", meta::uvalue{"new-enum-desc2"s}}, + {"desc3", meta::uvalue{"new-enum-desc3"s}}, + } + }); + + meta::enum_() + .evalue_("red", color::red, { + .metadata{ + {"desc2", meta::uvalue{"new-red-color"s}}, + } + }); + + // + + const meta::enum_type color_type = meta::resolve_type(); + REQUIRE(color_type); + + SUBCASE("color") { + CHECK(color_type.get_metadata().at("desc1") == "enum-desc1"s); + CHECK(color_type.get_metadata().at("desc2") == "new-enum-desc2"s); + CHECK(color_type.get_metadata().at("desc3") == "new-enum-desc3"s); + } + + SUBCASE("color::red") { + const meta::evalue red_evalue = color_type.get_evalue("red"); + REQUIRE(red_evalue); + CHECK_FALSE(red_evalue.get_metadata().contains("desc1")); + CHECK(red_evalue.get_metadata().at("desc2") == "new-red-color"s); + } +} + +TEST_CASE("meta/meta_states/metadata/class") { + namespace meta = meta_hpp; + using namespace std::string_literals; + + meta::class_({ + .metadata{ + {"desc1", meta::uvalue{"class-desc1"s}}, + {"desc2", meta::uvalue{"class-desc2"s}}, + }, + }) + .constructor_({ + .arguments{{ + .name{"v"}, + .metadata{{"desc", meta::uvalue{"the ctor arg"s}}}, + }}, + .metadata{{"desc", meta::uvalue{"one arg 2d vector ctor"s}}}, + }) + .constructor_({ + .arguments{{ + .name{"x"}, + .metadata{{"desc", meta::uvalue{"the 1st ctor arg"s}}}, + },{ + .name{"y"}, + .metadata{{"desc", meta::uvalue{"the 2nd ctor arg"s}}}, + }}, + .metadata{{"desc", meta::uvalue{"two args 2d vector ctor"s}}} + }) + .member_("x", &ivec2::x, { + .metadata{{"desc", meta::uvalue{"x-member"s}}} + }) + .member_("y", &ivec2::y, { + .metadata{{"desc", meta::uvalue{"y-member"s}}} + }) + .method_("add", &ivec2::add, { + .arguments{{ + .name{"other"}, + .metadata{{"desc", meta::uvalue{"other-arg"s}}} + }}, + .metadata{{"desc", meta::uvalue{"add-method"s}}} + }) + .function_("iadd", &ivec2::iadd, { + .arguments{{ + .name{"l"}, + .metadata{{"desc", meta::uvalue{"l-arg"s}}} + },{ + .name{"r"}, + .metadata{{"desc", meta::uvalue{"r-arg"s}}} + }}, + .metadata{{"desc", meta::uvalue{"iadd-function"s}}} + }); + + // metadata override + + meta::class_({ + .metadata{ + {"desc2", meta::uvalue{"new-class-desc2"s}}, + {"desc3", meta::uvalue{"new-class-desc3"s}}, + } + }); + + // + + const meta::class_type ivec2_type = meta::resolve_type(); + REQUIRE(ivec2_type); + + SUBCASE("ivec2") { + CHECK(ivec2_type.get_metadata().at("desc1") == "class-desc1"s); + CHECK(ivec2_type.get_metadata().at("desc2") == "new-class-desc2"s); + CHECK(ivec2_type.get_metadata().at("desc3") == "new-class-desc3"s); + } + + SUBCASE("ivec2(int)") { + const meta::constructor ivec2_ctor = ivec2_type.get_constructor_with(); + REQUIRE(ivec2_ctor); + + REQUIRE(ivec2_ctor.get_metadata().contains("desc")); + CHECK(ivec2_ctor.get_metadata().at("desc") == "one arg 2d vector ctor"s); + + REQUIRE(ivec2_ctor.get_argument(0)); + CHECK(ivec2_ctor.get_argument(0).get_name() == "v"); + CHECK(ivec2_ctor.get_argument(0).get_position() == 0); + CHECK(ivec2_ctor.get_argument(0).get_type() == meta::resolve_type()); + REQUIRE(ivec2_ctor.get_argument(0).get_metadata().contains("desc")); + CHECK(ivec2_ctor.get_argument(0).get_metadata().at("desc") == "the ctor arg"s); + + REQUIRE_FALSE(ivec2_ctor.get_argument(1)); + } + + SUBCASE("ivec2(int, int)") { + const meta::constructor ivec2_ctor = ivec2_type.get_constructor_with(); + REQUIRE(ivec2_ctor); + + REQUIRE(ivec2_ctor.get_metadata().contains("desc")); + CHECK(ivec2_ctor.get_metadata().at("desc") == "two args 2d vector ctor"s); + + REQUIRE(ivec2_ctor.get_argument(0)); + CHECK(ivec2_ctor.get_argument(0).get_name() == "x"); + CHECK(ivec2_ctor.get_argument(0).get_position() == 0); + CHECK(ivec2_ctor.get_argument(0).get_type() == meta::resolve_type()); + REQUIRE(ivec2_ctor.get_argument(0).get_metadata().contains("desc")); + CHECK(ivec2_ctor.get_argument(0).get_metadata().at("desc") == "the 1st ctor arg"s); + + REQUIRE(ivec2_ctor.get_argument(1)); + CHECK(ivec2_ctor.get_argument(1).get_name() == "y"); + CHECK(ivec2_ctor.get_argument(1).get_position() == 1); + CHECK(ivec2_ctor.get_argument(1).get_type() == meta::resolve_type()); + REQUIRE(ivec2_ctor.get_argument(1).get_metadata().contains("desc")); + CHECK(ivec2_ctor.get_argument(1).get_metadata().at("desc") == "the 2nd ctor arg"s); + + REQUIRE_FALSE(ivec2_ctor.get_argument(2)); + } + + SUBCASE("ivec2::x") { + const meta::member ivec2_x = ivec2_type.get_member("x"); + REQUIRE(ivec2_x); + + REQUIRE(ivec2_x.get_metadata().contains("desc")); + CHECK(ivec2_x.get_metadata().at("desc") == "x-member"s); + } + + SUBCASE("ivec2::y") { + const meta::member ivec2_y = ivec2_type.get_member("y"); + REQUIRE(ivec2_y); + + REQUIRE(ivec2_y.get_metadata().contains("desc")); + CHECK(ivec2_y.get_metadata().at("desc") == "y-member"s); + } + + SUBCASE("ivec2::add") { + const meta::method ivec2_add = ivec2_type.get_method("add"); + REQUIRE(ivec2_add); + + REQUIRE(ivec2_add.get_metadata().contains("desc")); + CHECK(ivec2_add.get_metadata().at("desc") == "add-method"s); + + REQUIRE(ivec2_add.get_argument(0)); + REQUIRE(ivec2_add.get_argument(0).get_metadata().contains("desc")); + CHECK(ivec2_add.get_argument(0).get_metadata().at("desc") == "other-arg"s); + } + + SUBCASE("ivec2::iadd") { + const meta::function ivec2_iadd = ivec2_type.get_function("iadd"); + REQUIRE(ivec2_iadd); + + REQUIRE(ivec2_iadd.get_metadata().contains("desc")); + CHECK(ivec2_iadd.get_metadata().at("desc") == "iadd-function"s); + + REQUIRE(ivec2_iadd.get_argument(0)); + REQUIRE(ivec2_iadd.get_argument(0).get_metadata().contains("desc")); + CHECK(ivec2_iadd.get_argument(0).get_metadata().at("desc") == "l-arg"s); + + REQUIRE(ivec2_iadd.get_argument(1)); + REQUIRE(ivec2_iadd.get_argument(1).get_metadata().contains("desc")); + CHECK(ivec2_iadd.get_argument(1).get_metadata().at("desc") == "r-arg"s); + } +} diff --git a/untests/meta_utilities/arg_tests.cpp b/untests/meta_utilities/arg_tests.cpp index 245e2ff..666025b 100644 --- a/untests/meta_utilities/arg_tests.cpp +++ b/untests/meta_utilities/arg_tests.cpp @@ -70,7 +70,7 @@ namespace {\ using namespace meta::detail;\ auto function_ptr = meta::select_overload(&FName);\ - meta::function f_state{function_state::make("", function_ptr)};\ + meta::function f_state{function_state::make("", function_ptr, {})};\ \ if ( std::is_invocable_v ) {\ CHECK(uarg{FromValue}.can_cast_to());\ @@ -94,7 +94,7 @@ namespace {\ using namespace meta::detail;\ auto function_ptr = meta::select_overload(&FName);\ - meta::function f_state{function_state::make("", function_ptr)};\ + meta::function f_state{function_state::make("", function_ptr, {})};\ \ if ( std::is_invocable_v ) {\ CHECK(f_state.is_invocable_with());\ diff --git a/untests/meta_utilities/inst_tests.cpp b/untests/meta_utilities/inst_tests.cpp index 17da6db..82ee784 100644 --- a/untests/meta_utilities/inst_tests.cpp +++ b/untests/meta_utilities/inst_tests.cpp @@ -30,7 +30,7 @@ namespace {\ using namespace meta::detail;\ auto method_ptr = meta::select_overload(&clazz::FName);\ - meta::method m_state{method_state::make("", method_ptr)};\ + meta::method m_state{method_state::make("", method_ptr, {})};\ \ if ( std::is_invocable_v ) {\ CHECK(uinst{Inst}.can_cast_to());\ @@ -54,7 +54,7 @@ namespace {\ using namespace meta::detail;\ auto method_ptr = meta::select_overload(&clazz::FName);\ - meta::method m_state{method_state::make("", method_ptr)};\ + meta::method m_state{method_state::make("", method_ptr, {})};\ \ if ( std::is_invocable_v ) {\ CHECK(m_state.is_invocable_with());\