1 // sol3 2 3 // The MIT License (MIT) 4 5 // Copyright (c) 2013-2021 Rapptz, ThePhD and contributors 6 7 // Permission is hereby granted, free of charge, to any person obtaining a copy of 8 // this software and associated documentation files (the "Software"), to deal in 9 // the Software without restriction, including without limitation the rights to 10 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 // the Software, and to permit persons to whom the Software is furnished to do so, 12 // subject to the following conditions: 13 14 // The above copyright notice and this permission notice shall be included in all 15 // copies or substantial portions of the Software. 16 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 #ifndef SOL_INHERITANCE_HPP 25 #define SOL_INHERITANCE_HPP 26 27 #include <sol/types.hpp> 28 #include <sol/usertype_traits.hpp> 29 #include <sol/unique_usertype_traits.hpp> 30 31 namespace sol { 32 template <typename... Args> 33 struct base_list { }; 34 template <typename... Args> 35 using bases = base_list<Args...>; 36 37 typedef bases<> base_classes_tag; 38 const auto base_classes = base_classes_tag(); 39 40 template <typename... Args> 41 struct is_to_stringable<base_list<Args...>> : std::false_type { }; 42 43 namespace detail { 44 base_class_check_key()45 inline decltype(auto) base_class_check_key() { 46 static const auto& key = "class_check"; 47 return key; 48 } 49 base_class_cast_key()50 inline decltype(auto) base_class_cast_key() { 51 static const auto& key = "class_cast"; 52 return key; 53 } 54 base_class_index_propogation_key()55 inline decltype(auto) base_class_index_propogation_key() { 56 static const auto& key = u8"\xF0\x9F\x8C\xB2.index"; 57 return key; 58 } 59 base_class_new_index_propogation_key()60 inline decltype(auto) base_class_new_index_propogation_key() { 61 static const auto& key = u8"\xF0\x9F\x8C\xB2.new_index"; 62 return key; 63 } 64 65 template <typename T> 66 struct inheritance { 67 typedef typename base<T>::type bases_t; 68 type_check_basessol::detail::inheritance69 static bool type_check_bases(types<>, const string_view&) { 70 return false; 71 } 72 73 template <typename Base, typename... Args> type_check_basessol::detail::inheritance74 static bool type_check_bases(types<Base, Args...>, const string_view& ti) { 75 return ti == usertype_traits<Base>::qualified_name() || type_check_bases(types<Args...>(), ti); 76 } 77 type_checksol::detail::inheritance78 static bool type_check(const string_view& ti) { 79 return ti == usertype_traits<T>::qualified_name() || type_check_bases(bases_t(), ti); 80 } 81 82 template <typename... Bases> type_check_withsol::detail::inheritance83 static bool type_check_with(const string_view& ti) { 84 return ti == usertype_traits<T>::qualified_name() || type_check_bases(types<Bases...>(), ti); 85 } 86 type_cast_basessol::detail::inheritance87 static void* type_cast_bases(types<>, T*, const string_view&) { 88 return nullptr; 89 } 90 91 template <typename Base, typename... Args> type_cast_basessol::detail::inheritance92 static void* type_cast_bases(types<Base, Args...>, T* data, const string_view& ti) { 93 // Make sure to convert to T first, and then dynamic cast to the proper type 94 return ti != usertype_traits<Base>::qualified_name() ? type_cast_bases(types<Args...>(), data, ti) 95 : static_cast<void*>(static_cast<Base*>(data)); 96 } 97 type_castsol::detail::inheritance98 static void* type_cast(void* voiddata, const string_view& ti) { 99 T* data = static_cast<T*>(voiddata); 100 return static_cast<void*>(ti != usertype_traits<T>::qualified_name() ? type_cast_bases(bases_t(), data, ti) : data); 101 } 102 103 template <typename... Bases> type_cast_withsol::detail::inheritance104 static void* type_cast_with(void* voiddata, const string_view& ti) { 105 T* data = static_cast<T*>(voiddata); 106 return static_cast<void*>(ti != usertype_traits<T>::qualified_name() ? type_cast_bases(types<Bases...>(), data, ti) : data); 107 } 108 109 template <typename U> type_unique_cast_basessol::detail::inheritance110 static bool type_unique_cast_bases(types<>, void*, void*, const string_view&) { 111 return 0; 112 } 113 114 template <typename U, typename Base, typename... Args> type_unique_cast_basessol::detail::inheritance115 static int type_unique_cast_bases(types<Base, Args...>, void* source_data, void* target_data, const string_view& ti) { 116 using uu_traits = unique_usertype_traits<U>; 117 using base_ptr = typename uu_traits::template rebind_actual_type<Base>; 118 string_view base_ti = usertype_traits<Base>::qualified_name(); 119 if (base_ti == ti) { 120 if (target_data != nullptr) { 121 U* source = static_cast<U*>(source_data); 122 base_ptr* target = static_cast<base_ptr*>(target_data); 123 // perform proper derived -> base conversion 124 *target = *source; 125 } 126 return 2; 127 } 128 return type_unique_cast_bases<U>(types<Args...>(), source_data, target_data, ti); 129 } 130 131 template <typename U> type_unique_castsol::detail::inheritance132 static int type_unique_cast(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) { 133 if constexpr (is_actual_type_rebindable_for_v<U>) { 134 using rebound_actual_type = unique_usertype_rebind_actual_t<U>; 135 using maybe_bases_or_empty = meta::conditional_t<std::is_void_v<rebound_actual_type>, types<>, bases_t>; 136 string_view this_rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); 137 if (rebind_ti != this_rebind_ti) { 138 // this is not even of the same unique type 139 return 0; 140 } 141 string_view this_ti = usertype_traits<T>::qualified_name(); 142 if (ti == this_ti) { 143 // direct match, return 1 144 return 1; 145 } 146 return type_unique_cast_bases<U>(maybe_bases_or_empty(), source_data, target_data, ti); 147 } 148 else { 149 (void)rebind_ti; 150 string_view this_ti = usertype_traits<T>::qualified_name(); 151 if (ti == this_ti) { 152 // direct match, return 1 153 return 1; 154 } 155 return type_unique_cast_bases<U>(types<>(), source_data, target_data, ti); 156 } 157 } 158 159 template <typename U, typename... Bases> type_unique_cast_withsol::detail::inheritance160 static int type_unique_cast_with(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) { 161 using uc_bases_t = types<Bases...>; 162 if constexpr (is_actual_type_rebindable_for_v<U>) { 163 using rebound_actual_type = unique_usertype_rebind_actual_t<U>; 164 using cond_bases_t = meta::conditional_t<std::is_void_v<rebound_actual_type>, types<>, uc_bases_t>; 165 string_view this_rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); 166 if (rebind_ti != this_rebind_ti) { 167 // this is not even of the same unique type 168 return 0; 169 } 170 string_view this_ti = usertype_traits<T>::qualified_name(); 171 if (ti == this_ti) { 172 // direct match, return 1 173 return 1; 174 } 175 return type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti); 176 } 177 else { 178 (void)rebind_ti; 179 string_view this_ti = usertype_traits<T>::qualified_name(); 180 if (ti == this_ti) { 181 // direct match, return 1 182 return 1; 183 } 184 return type_unique_cast_bases<U>(types<>(), source_data, target_data, ti); 185 } 186 } 187 }; 188 189 using inheritance_check_function = decltype(&inheritance<void>::type_check); 190 using inheritance_cast_function = decltype(&inheritance<void>::type_cast); 191 using inheritance_unique_cast_function = decltype(&inheritance<void>::type_unique_cast<void>); 192 } // namespace detail 193 } // namespace sol 194 195 #endif // SOL_INHERITANCE_HPP 196