#pragma once #include "types.h" #include "type_traits.h" namespace pybind11 { inline object eval(std::string_view code, const handle& global = none{}, handle local = none{}) { return vm->py_eval(code, global.ptr(), local.ptr()); } inline void exec(std::string_view code, const handle& global = none{}, handle local = none{}) { vm->py_exec(code, global.ptr(), local.ptr()); } /// globas() in pkpy is immutable, your changes will not be reflected in the Python interpreter inline dict globals() { auto& proxy = eval("globals()")._as().attr(); dict result; #if PK_VERSION_MAJOR == 2 proxy.apply( [](pkpy::StrName key, pkpy::PyVar value, void* data) { auto& dict = static_cast(data)->_as(); auto key_ = pybind11::str(key.sv()).ptr(); dict.set(vm, key_, value); }, &result); #else proxy.apply([&](pkpy::StrName key, pkpy::PyVar value) { result.setitem(str(key.sv()), value); }); #endif return result; } // wrapper for builtin functions in Python inline bool hasattr(const handle& obj, const handle& name) { return vm->getattr(obj.ptr(), name._as(), false) != nullptr; } inline bool hasattr(const handle& obj, const char* name) { return vm->getattr(obj.ptr(), name, false) != nullptr; } inline void delattr(const handle& obj, const handle& name) { vm->delattr(obj.ptr(), name._as()); } inline void delattr(const handle& obj, const char* name) { vm->delattr(obj.ptr(), name); } inline object getattr(const handle& obj, const handle& name) { return vm->getattr(obj.ptr(), name._as()); } inline object getattr(const handle& obj, const char* name) { return vm->getattr(obj.ptr(), name); } inline object getattr(const handle& obj, const handle& name, const handle& default_) { auto attr = vm->getattr(obj.ptr(), name._as(), false); if(attr) { return attr; } return default_; } inline object getattr(const handle& obj, const char* name, const handle& default_) { auto attr = vm->getattr(obj.ptr(), name, false); if(attr) { return attr; } return default_; } inline void setattr(const handle& obj, const handle& name, const handle& value) { vm->setattr(obj.ptr(), name._as(), value.ptr()); } inline void setattr(const handle& obj, const char* name, const handle& value) { vm->setattr(obj.ptr(), name, value.ptr()); } template inline bool isinstance(const handle& obj) { return type_visitor::check(obj); } template <> inline bool isinstance(const handle&) = delete; inline bool isinstance(const handle& obj, const handle& type) { return vm->isinstance(obj.ptr(), type._as()); } inline int64_t hash(const handle& obj) { return vm->py_hash(obj.ptr()); } namespace impl { template struct type_caster; } template handle cast(T&& value, return_value_policy policy, handle parent) { // decay_t can resolve c-array type, but remove_cv_ref_t can't. using underlying_type = std::decay_t; if constexpr(std::is_convertible_v) { return std::forward(value); } else { static_assert(!is_multiple_pointer_v, "multiple pointer is not supported."); static_assert(!std::is_void_v>, "void* is not supported, consider using py::capsule."); // resolve for automatic policy. if(policy == return_value_policy::automatic) { policy = std::is_pointer_v ? return_value_policy::take_ownership : std::is_lvalue_reference_v ? return_value_policy::copy : return_value_policy::move; } else if(policy == return_value_policy::automatic_reference) { policy = std::is_pointer_v ? return_value_policy::reference : std::is_lvalue_reference_v ? return_value_policy::copy : return_value_policy::move; } return impl::type_caster::cast(std::forward(value), policy, parent); } } template T cast(const handle& obj, bool convert) { assert(obj.ptr() != nullptr); impl::type_caster caster = {}; if(caster.load(obj, convert)) { return caster.value; } else { std::string msg = "cast python instance to c++ failed, "; msg += "obj type is: {"; msg += type::of(obj).name(); msg += "}, target type is: {"; msg += type_name(); msg += "}."; vm->TypeError(msg); PK_UNREACHABLE(); } } struct kwargs_proxy { handle value; }; struct args_proxy { handle value; kwargs_proxy operator* () { return kwargs_proxy{value}; } }; template args_proxy interface::operator* () const { return args_proxy{ptr()}; } template handle interpreter::vectorcall(const handle& callable, const handle& self, const Args&... args) { vm->s_data.push(callable.ptr()); #if PK_VERSION_MAJOR == 2 vm->s_data.push(self ? self.ptr() : PY_NULL); #else vm->s_data.push(self ? self.ptr() : pkpy::PY_NULL); #endif int argc = 0; int kwargsc = 0; auto push_arg = [&](const handle& value) { assert(value); vm->s_data.push(value.ptr()); argc++; }; auto push_named_arg = [&](std::string_view name, const handle& value) { assert(value); vm->s_data.push(int_(pkpy::StrName(name).index).ptr()); vm->s_data.push(value.ptr()); kwargsc++; }; auto foreach_ = [&](const auto& arg) { using T = std::decay_t; if constexpr(std::is_convertible_v) { push_arg(arg); } else if constexpr(std::is_same_v) { pybind11::tuple args = arg.value.template cast(); for(auto item: args) { push_arg(item); } } else if constexpr(std::is_same_v) { push_named_arg(arg.name, arg.default_); } else if constexpr(std::is_same_v) { pybind11::dict kwargs = arg.value.template cast(); for(auto item: kwargs) { str name = item.first.template cast(); push_named_arg(name, item.second); } } else { static_assert(dependent_false, "unsupported type"); } }; (foreach_(args), ...); return vm->vectorcall(argc, kwargsc); } template template inline object interface::operator() (Args&&... args) const { auto _cast = [&](auto&& arg) { using T = std::decay_t; if constexpr(std::is_same_v || std::is_same_v || std::is_same_v || std::is_convertible_v) { return arg; } else { return pybind11::cast(std::forward(arg), policy); } }; return interpreter::vectorcall(ptr(), handle(), _cast(std::forward(args))...); } template void print(Args&&... args) { handle print = getattr(vm->builtins, "print"); print(std::forward(args)...); } } // namespace pybind11