12
12
13
13
#include " detail/common.h"
14
14
#include " detail/descr.h"
15
+ #include " detail/native_enum_data.h"
15
16
#include " detail/smart_holder_sfinae_hooks_only.h"
16
17
#include " detail/type_caster_base.h"
17
18
#include " detail/type_caster_odr_guard.h"
@@ -63,12 +64,6 @@ using make_caster_for_intrinsic = type_caster<type>;
63
64
template <typename type>
64
65
using make_caster = make_caster_for_intrinsic<intrinsic_t <type>>;
65
66
66
- template <typename T>
67
- struct type_uses_smart_holder_type_caster {
68
- static constexpr bool value
69
- = std::is_base_of<smart_holder_type_caster_base_tag, make_caster<T>>::value;
70
- };
71
-
72
67
// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T
73
68
template <typename T>
74
69
typename make_caster<T>::template cast_op_type<T> cast_op (make_caster<T> &caster) {
@@ -81,6 +76,126 @@ cast_op(make_caster<T> &&caster) {
81
76
template cast_op_type<typename std::add_rvalue_reference<T>::type>();
82
77
}
83
78
79
+ template <typename EnumType>
80
+ class type_caster_enum_type {
81
+ private:
82
+ using Underlying = typename std::underlying_type<EnumType>::type;
83
+
84
+ public:
85
+ static constexpr auto name = const_name<EnumType>();
86
+
87
+ template <typename SrcType>
88
+ static handle cast (SrcType &&src, return_value_policy, handle parent) {
89
+ auto const &natives = cross_extension_shared_states::native_enum_type_map::get ();
90
+ auto found = natives.find (std::type_index (typeid (EnumType)));
91
+ if (found != natives.end ()) {
92
+ return handle (found->second )(static_cast <Underlying>(src)).release ();
93
+ }
94
+ return type_caster_for_class_<EnumType>::cast (
95
+ std::forward<SrcType>(src),
96
+ // Fixes https://github.com/pybind/pybind11/pull/3643#issuecomment-1022987818:
97
+ return_value_policy::copy,
98
+ parent);
99
+ }
100
+
101
+ bool load (handle src, bool convert) {
102
+ auto const &natives = cross_extension_shared_states::native_enum_type_map::get ();
103
+ auto found = natives.find (std::type_index (typeid (EnumType)));
104
+ if (found != natives.end ()) {
105
+ if (!isinstance (src, found->second )) {
106
+ return false ;
107
+ }
108
+ type_caster<Underlying> underlying_caster;
109
+ if (!underlying_caster.load (src.attr (" value" ), convert)) {
110
+ pybind11_fail (" native_enum internal consistency failure." );
111
+ }
112
+ value = static_cast <EnumType>(static_cast <Underlying>(underlying_caster));
113
+ return true ;
114
+ }
115
+ if (!pybind11_enum_) {
116
+ pybind11_enum_.reset (new type_caster_for_class_<EnumType>());
117
+ }
118
+ return pybind11_enum_->load (src, convert);
119
+ }
120
+
121
+ template <typename T>
122
+ using cast_op_type = detail::cast_op_type<T>;
123
+
124
+ // NOLINTNEXTLINE(google-explicit-constructor)
125
+ operator EnumType *() {
126
+ if (!pybind11_enum_) {
127
+ return &value;
128
+ }
129
+ return pybind11_enum_->operator EnumType *();
130
+ }
131
+
132
+ // NOLINTNEXTLINE(google-explicit-constructor)
133
+ operator EnumType &() {
134
+ if (!pybind11_enum_) {
135
+ return value;
136
+ }
137
+ return pybind11_enum_->operator EnumType &();
138
+ }
139
+
140
+ private:
141
+ std::unique_ptr<type_caster_for_class_<EnumType>> pybind11_enum_;
142
+ EnumType value;
143
+ };
144
+
145
+ template <typename EnumType, typename SFINAE = void >
146
+ struct type_caster_enum_type_enabled : std::true_type {};
147
+
148
+ template <typename T>
149
+ struct type_uses_type_caster_enum_type {
150
+ static constexpr bool value
151
+ = std::is_enum<T>::value && type_caster_enum_type_enabled<T>::value;
152
+ };
153
+
154
+ template <typename EnumType>
155
+ class type_caster <EnumType, detail::enable_if_t <type_uses_type_caster_enum_type<EnumType>::value>>
156
+ : public type_caster_enum_type<EnumType> {};
157
+
158
+ template <typename T>
159
+ struct type_uses_smart_holder_type_caster {
160
+ static constexpr bool value
161
+ = std::is_base_of<smart_holder_type_caster_base_tag, make_caster<T>>::value
162
+ #ifdef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
163
+ || type_uses_type_caster_enum_type<T>::value
164
+ #endif
165
+ ;
166
+ };
167
+
168
+ template <typename T, typename SFINAE = void >
169
+ struct type_caster_classh_enum_aware : type_caster<T> {};
170
+
171
+ #ifdef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
172
+ template <typename EnumType>
173
+ struct type_caster_classh_enum_aware <
174
+ EnumType,
175
+ detail::enable_if_t <type_uses_type_caster_enum_type<EnumType>::value>>
176
+ : type_caster_for_class_<EnumType> {};
177
+ #endif
178
+
179
+ template <typename T, detail::enable_if_t <std::is_enum<T>::value, int > = 0 >
180
+ bool isinstance_native_enum_impl (handle obj, const std::type_info &tp) {
181
+ auto const &natives = cross_extension_shared_states::native_enum_type_map::get ();
182
+ auto found = natives.find (tp);
183
+ if (found == natives.end ()) {
184
+ return false ;
185
+ }
186
+ return isinstance (obj, found->second );
187
+ }
188
+
189
+ template <typename T, detail::enable_if_t <!std::is_enum<T>::value, int > = 0 >
190
+ bool isinstance_native_enum_impl (handle, const std::type_info &) {
191
+ return false ;
192
+ }
193
+
194
+ template <typename T>
195
+ bool isinstance_native_enum (handle obj, const std::type_info &tp) {
196
+ return isinstance_native_enum_impl<intrinsic_t <T>>(obj, tp);
197
+ }
198
+
84
199
template <typename type>
85
200
class type_caster <std::reference_wrapper<type>> {
86
201
private:
@@ -1024,11 +1139,11 @@ using move_never = none_of<move_always<T>, move_if_unreferenced<T>>;
1024
1139
// non-reference/pointer `type`s and reference/pointers from a type_caster_generic are safe;
1025
1140
// everything else returns a reference/pointer to a local variable.
1026
1141
template <typename type>
1027
- using cast_is_temporary_value_reference
1028
- = bool_constant< (std::is_reference<type>::value || std::is_pointer<type>::value)
1029
- && !std::is_base_of<type_caster_generic, make_caster<type>>::value
1030
- && !type_uses_smart_holder_type_caster< intrinsic_t <type>>::value
1031
- && !std::is_same<intrinsic_t <type>, void >::value>;
1142
+ using cast_is_temporary_value_reference = bool_constant<
1143
+ (std::is_reference<type>::value || std::is_pointer<type>::value)
1144
+ && !std::is_base_of<type_caster_generic, make_caster<type>>::value
1145
+ && !std::is_base_of<smart_holder_type_caster_base_tag, make_caster <type>>::value
1146
+ && !std::is_same<intrinsic_t <type>, void >::value>;
1032
1147
1033
1148
// When a value returned from a C++ function is being cast back to Python, we almost always want to
1034
1149
// force `policy = move`, regardless of the return value policy the function/method was declared
@@ -1086,8 +1201,18 @@ PYBIND11_NAMESPACE_END(detail)
1086
1201
template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = 0>
1087
1202
T cast(const handle &handle) {
1088
1203
using namespace detail ;
1089
- static_assert (!cast_is_temporary_value_reference<T>::value,
1204
+ constexpr bool is_enum_cast = type_uses_type_caster_enum_type<intrinsic_t <T>>::value;
1205
+ static_assert (!cast_is_temporary_value_reference<T>::value || is_enum_cast,
1090
1206
" Unable to cast type to reference: value is local to type caster" );
1207
+ #ifndef NDEBUG
1208
+ if (is_enum_cast && cast_is_temporary_value_reference<T>::value) {
1209
+ if (cross_extension_shared_states::native_enum_type_map::get ().count (
1210
+ std::type_index (typeid (intrinsic_t <T>)))
1211
+ != 0 ) {
1212
+ pybind11_fail (" Unable to cast native enum type to reference" );
1213
+ }
1214
+ }
1215
+ #endif
1091
1216
return cast_op<T>(load_type<T>(handle));
1092
1217
}
1093
1218
0 commit comments