1212
1313#include " detail/common.h"
1414#include " detail/descr.h"
15+ #include " detail/native_enum_data.h"
1516#include " detail/smart_holder_sfinae_hooks_only.h"
1617#include " detail/type_caster_base.h"
1718#include " detail/type_caster_odr_guard.h"
@@ -63,12 +64,6 @@ using make_caster_for_intrinsic = type_caster<type>;
6364template <typename type>
6465using make_caster = make_caster_for_intrinsic<intrinsic_t <type>>;
6566
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-
7267// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T
7368template <typename T>
7469typename make_caster<T>::template cast_op_type<T> cast_op (make_caster<T> &caster) {
@@ -81,6 +76,126 @@ cast_op(make_caster<T> &&caster) {
8176 template cast_op_type<typename std::add_rvalue_reference<T>::type>();
8277}
8378
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+
84199template <typename type>
85200class type_caster <std::reference_wrapper<type>> {
86201private:
@@ -1024,11 +1139,11 @@ using move_never = none_of<move_always<T>, move_if_unreferenced<T>>;
10241139// non-reference/pointer `type`s and reference/pointers from a type_caster_generic are safe;
10251140// everything else returns a reference/pointer to a local variable.
10261141template <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>;
10321147
10331148// When a value returned from a C++ function is being cast back to Python, we almost always want to
10341149// force `policy = move`, regardless of the return value policy the function/method was declared
@@ -1086,8 +1201,18 @@ PYBIND11_NAMESPACE_END(detail)
10861201template <typename T, detail::enable_if_t <!detail::is_pyobject<T>::value, int > = 0 >
10871202T cast (const handle &handle) {
10881203 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,
10901206 " 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
10911216 return cast_op<T>(load_type<T>(handle));
10921217}
10931218
0 commit comments