diff --git a/include/cpprtti/misc/variant.h b/include/cpprtti/misc/variant.h index 06bf10e..078addb 100644 --- a/include/cpprtti/misc/variant.h +++ b/include/cpprtti/misc/variant.h @@ -109,6 +109,11 @@ namespace cpprtti template inline variant to() const; + /** + * @brief Convert this variant to another type. + */ + inline variant to(cpprtti::type_id id) const; + /** * @brief Convert this variant to another type. */ @@ -129,6 +134,11 @@ namespace cpprtti * @brief Check if the variant has a value assigned, if not throw an exception. */ inline void check_impl() const; + + /** + * @brief Check if the passed type id is supported by the type stored in this variant. + */ + inline bool check_type(const cpprtti::type& t, type_id id) const; }; constexpr decltype(auto) make_variant = cppmp::generic_predicate<__impl::variant_builder> { }; diff --git a/include/cpprtti/misc/variant.inl b/include/cpprtti/misc/variant.inl index 53aebf8..4dcfb3f 100644 --- a/include/cpprtti/misc/variant.inl +++ b/include/cpprtti/misc/variant.inl @@ -8,6 +8,8 @@ #include #include +#include + #include "variant.h" #include "exception.h" #include "../registry.h" @@ -303,7 +305,7 @@ namespace cpprtti { check_impl(); - if (_impl->type.id() != get_type_id>()) + if (!check_type(_impl->type, get_type_id>())) { throw exception( error_code::variant_type_mismatch, @@ -326,7 +328,36 @@ namespace cpprtti variant variant::to() const { using to_type = cppmp::decay_t; - return to(get_type_id()); + auto * t = type().registry().find(); + if (!t) + { + throw exception( + error_code::variant_is_empty, + cppcore::string_builder() + << "No known conversion from type '" + << type().name() + << "' to type '" + << get_type_name() + << "'!"); + } + return to(*t); + } + + variant variant::to(cpprtti::type_id id) const + { + auto t = type().registry().find(id); + if (!t) + { + throw exception( + error_code::variant_is_empty, + cppcore::string_builder() + << "No known conversion from type '" + << type().name() + << "' to type id '" + << id + << "'!"); + } + return to(*t); } variant variant::to(const cpprtti::type& t) const @@ -372,4 +403,25 @@ namespace cpprtti } } + bool variant::check_type(const cpprtti::type& t, type_id id) const + { + if (t.id() == id) + return true; + + if (t.rtti_type() == cpprtti::rtti_type::class_type) + { + auto* _ct = dynamic_cast(&t); + assert(_ct); + auto& ct = *_ct; + + for (auto& kvp : ct.base_classes()) + { + if (check_type(*kvp, id)) + return true; + } + } + + return false; + } + } diff --git a/include/cpprtti/types/class_type.h b/include/cpprtti/types/class_type.h index b792b53..4818bc2 100644 --- a/include/cpprtti/types/class_type.h +++ b/include/cpprtti/types/class_type.h @@ -31,6 +31,11 @@ namespace cpprtti type_id p_id, const std::string& p_name); + /** + * @brief Get the vector of base classes. + */ + inline const class_type_vector& base_classes() const; + /** * @brief Get a map of all registered members. */ diff --git a/include/cpprtti/types/class_type.inl b/include/cpprtti/types/class_type.inl index 5748eff..3a87b93 100644 --- a/include/cpprtti/types/class_type.inl +++ b/include/cpprtti/types/class_type.inl @@ -16,6 +16,9 @@ namespace cpprtti : type(p_registry, p_id, p_name, rtti_type_t::class_type) { } + const class_type::class_type_vector& class_type::base_classes() const + { return _base_classes; } + const member& class_type::member( const std::string& p_name) const { diff --git a/include/cpprtti/types/member/member_variable.h b/include/cpprtti/types/member/member_variable.h index 6cf3c50..3a4191d 100644 --- a/include/cpprtti/types/member/member_variable.h +++ b/include/cpprtti/types/member/member_variable.h @@ -54,12 +54,22 @@ namespace cpprtti template inline variant get(T_object& obj) const; + /** + * @brief Get the current value of the member. + */ + inline variant get(const variant& obj) const; + /** * @brief Set the new value of the member. */ template inline void set(T_object& obj, const T_value& value) const; + /** + * @brief Set the new value of the member. + */ + inline void set(const variant& obj, const variant& value) const; + protected: /** * @brief Get the current value of the member. diff --git a/include/cpprtti/types/member/member_variable.inl b/include/cpprtti/types/member/member_variable.inl index 783d52e..b14d227 100644 --- a/include/cpprtti/types/member/member_variable.inl +++ b/include/cpprtti/types/member/member_variable.inl @@ -47,6 +47,9 @@ namespace cpprtti return get_impl(make_variant(_owner.registry(), obj)); } + variant member_variable::get(const variant& obj) const + { return get_impl(obj); } + template inline void member_variable::set(T_object& obj, const T_value& value) const { @@ -64,6 +67,9 @@ namespace cpprtti return set_impl(make_variant(_owner.registry(), obj), make_variant(_owner.registry(), value)); } + void member_variable::set(const variant& obj, const variant& value) const + { return set_impl(obj, value); } + namespace __impl {