#pragma once #include "module.h" #include namespace pybind11 { struct dynamic_attr {}; template class class_ : public type { protected: handle m_scope; public: using type::type; using underlying_type = T; template class_(const handle& scope, const char* name, const Args&... args) : m_scope(scope), type(type_visitor::create(scope, name)) { auto& info = type_info::of(); info.name = name; // bind __new__ interpreter::bind_func(m_ptr, pkpy::__new__, -1, [](pkpy::VM* vm, pkpy::ArgsView args) { auto cls = handle(args[0])._as(); // check if the class has constructor, if not, raise error if(vm->find_name_in_mro(cls, pkpy::__init__) == nullptr) { vm->RuntimeError("if you want to create instance of bound class, you must bind constructor for it"); } auto var = instance::create(cls, &type_info::of()); if constexpr(types_count_v != 0) { #if PK_VERSION_MAJOR == 2 var.get()->_attr = new pkpy::NameDict(); #else var->_enable_instance_dict(); #endif } return var; }); } /// bind constructor template class_& def(init, const Extra&... extra) { if constexpr(!std::is_constructible_v) { static_assert(std::is_constructible_v, "Invalid constructor arguments"); } else { impl::bind_function( *this, "__init__", [](T* self, Args... args) { new (self) T(args...); }, pkpy::BindType::DEFAULT, extra...); return *this; } } /// bind member function template class_& def(const char* name, Fn&& f, const Extra&... extra) { using first = std::tuple_element_t<0, callable_args_t>>; constexpr bool is_first_base_of_v = std::is_base_of_v, T>; if constexpr(!is_first_base_of_v) { static_assert(is_first_base_of_v, "If you want to bind member function, the first argument must be the base class"); } else { impl::bind_function(*this, name, std::forward(f), pkpy::BindType::DEFAULT, extra...); } return *this; } /// bind operators template class_& def(Operator op, const Extras&... extras) { op.execute(*this, extras...); return *this; } // TODO: factory function /// bind static function template class_& def_static(const char* name, Fn&& f, const Extra&... extra) { impl::bind_function(*this, name, std::forward(f), pkpy::BindType::STATICMETHOD, extra...); return *this; } template class_& def_readwrite(const char* name, MP mp, const Extras&... extras) { if constexpr(!std::is_member_object_pointer_v) { static_assert(std::is_member_object_pointer_v, "def_readwrite only supports pointer to data member"); } else { impl::bind_property(*this, name, mp, mp, extras...); } return *this; } template class_& def_readonly(const char* name, MP mp, const Extras&... extras) { if constexpr(!std::is_member_object_pointer_v) { static_assert(std::is_member_object_pointer_v, "def_readonly only supports pointer to data member"); } else { impl::bind_property(*this, name, mp, nullptr, extras...); } return *this; } template class_& def_property(const char* name, Getter&& g, Setter&& s, const Extras&... extras) { impl::bind_property(*this, name, std::forward(g), std::forward(s), extras...); return *this; } template class_& def_property_readonly(const char* name, Getter&& mp, const Extras&... extras) { impl::bind_property(*this, name, std::forward(mp), nullptr, extras...); return *this; } template class_& def_readwrite_static(const char* name, Var& mp, const Extras&... extras) { static_assert( dependent_false, "define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented."); return *this; } template class_& def_readonly_static(const char* name, Var& mp, const Extras&... extras) { static_assert( dependent_false, "define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented."); return *this; } template class_& def_property_static(const char* name, Getter&& g, Setter&& s, const Extras&... extras) { static_assert( dependent_false, "define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented."); return *this; } }; template class enum_ : public class_ { std::vector> m_values; public: using Base = class_; using class_::class_; template enum_(const handle& scope, const char* name, Args&&... args) : class_(scope, name, std::forward(args)...) { Base::def_property_readonly("value", [](T& self) { return int_(static_cast>(self)); }); } enum_& value(const char* name, T value) { handle var = pybind11::cast(value, return_value_policy::copy); setattr(*this, name, var); m_values.emplace_back(name, var); return *this; } enum_& export_values() { for(auto& [name, value]: m_values) { setattr(Base::m_scope, name, value); } return *this; } }; } // namespace pybind11