diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 72d2315..8b9d8c8 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -107,6 +107,71 @@ namespace chaiscript }; + template + class Static_Caster + { + public: + static Boxed_Value cast(const Boxed_Value &t_from) + { + if (t_from.get_type_info().bare_equal(chaiscript::user_type())) + { + if (t_from.is_pointer()) + { + // Dynamic cast out the contained boxed value, which we know is the type we want + if (t_from.is_const()) + { + return Boxed_Value( + [&]()->std::shared_ptr{ + if (auto data = std::static_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr))) + { + return data; + } else { + throw std::bad_cast(); + } + }() + ); + } else { + return Boxed_Value( + [&]()->std::shared_ptr{ + if (auto data = std::static_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr))) + { + return data; + } else { +#ifdef CHAISCRIPT_LIBCPP + /// \todo fix this someday after libc++ is fixed. + if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) { + auto from = detail::Cast_Helper >::cast(t_from, nullptr); + if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) { + return std::static_pointer_cast(from); + } + } +#endif + throw std::bad_cast(); + } + }() + ); + } + } else { + // Pull the reference out of the contained boxed value, which we know is the type we want + if (t_from.is_const()) + { + const From &d = detail::Cast_Helper::cast(t_from, nullptr); + const To &data = static_cast(d); + return Boxed_Value(std::cref(data)); + } else { + From &d = detail::Cast_Helper::cast(t_from, nullptr); + To &data = static_cast(d); + return Boxed_Value(std::ref(data)); + } + } + } else { + throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); + } + } + + }; + + template class Dynamic_Caster { @@ -168,8 +233,10 @@ namespace chaiscript throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); } } + }; + template class Dynamic_Conversion_Impl : public Type_Conversion_Base { @@ -186,10 +253,31 @@ namespace chaiscript virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE { - return Dynamic_Caster::cast(t_derived); + return Static_Caster::cast(t_derived); } }; + template + class Static_Conversion_Impl : public Type_Conversion_Base + { + public: + Static_Conversion_Impl() + : Type_Conversion_Base(chaiscript::user_type(), chaiscript::user_type()) + { + } + + virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE + { + throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived), "Unable to cast down inheritance hierarchy with non-polymorphic types"); + } + + virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE + { + return Static_Caster::cast(t_derived); + } + }; + + template class Type_Conversion_Impl : public Type_Conversion_Base @@ -417,17 +505,26 @@ namespace chaiscript /// \endcode /// template - Type_Conversion base_class() + Type_Conversion base_class(typename std::enable_if::value && std::is_polymorphic::value>::type* = nullptr) { //Can only be used with related polymorphic types //may be expanded some day to support conversions other than child -> parent static_assert(std::is_base_of::value, "Classes are not related by inheritance"); - static_assert(std::is_polymorphic::value, "Base class must be polymorphic"); - static_assert(std::is_polymorphic::value, "Derived class must be polymorphic"); return chaiscript::make_shared>(); } + template + Type_Conversion base_class(typename std::enable_if::value || !std::is_polymorphic::value>::type* = nullptr) + { + //Can only be used with related polymorphic types + //may be expanded some day to support conversions other than child -> parent + static_assert(std::is_base_of::value, "Classes are not related by inheritance"); + + return chaiscript::make_shared>(); + } + + template Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, const Callable &t_func)