| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- #pragma once
- #include "cffi.h"
- #include "vm.h"
- namespace pkpy{
- struct NativeProxyFuncCBase {
- virtual PyVar operator()(VM* vm, ArgsView args) = 0;
- };
- template<typename Ret, typename... Params>
- struct NativeProxyFuncC final: NativeProxyFuncCBase {
- static constexpr int N = sizeof...(Params);
- using _Fp = Ret(*)(Params...);
- _Fp func;
- NativeProxyFuncC(_Fp func) : func(func) {}
- PyVar operator()(VM* vm, ArgsView args) override {
- PK_DEBUG_ASSERT(args.size() == N);
- return call<Ret>(vm, args, std::make_index_sequence<N>());
- }
- template<typename __Ret, size_t... Is>
- PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){
- if constexpr(std::is_void_v<__Ret>){
- func(py_cast<Params>(vm, args[Is])...);
- return vm->None;
- }else{
- __Ret ret = func(py_cast<Params>(vm, args[Is])...);
- return VAR(std::move(ret));
- }
- }
- };
- template<typename Ret, typename T, typename... Params>
- struct NativeProxyMethodC final: NativeProxyFuncCBase {
- static constexpr int N = sizeof...(Params);
- using _Fp = Ret(T::*)(Params...);
- _Fp func;
- NativeProxyMethodC(_Fp func) : func(func) {}
- PyVar operator()(VM* vm, ArgsView args) override {
- PK_DEBUG_ASSERT(args.size() == N+1);
- return call<Ret>(vm, args, std::make_index_sequence<N>());
- }
- template<typename __Ret, size_t... Is>
- PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){
- obj_get_t<T> self = PK_OBJ_GET(T, args[0]); // use unsafe cast for derived classes
- if constexpr(std::is_void_v<__Ret>){
- (self.*func)(py_cast<Params>(vm, args[Is+1])...);
- return vm->None;
- }else{
- __Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
- return VAR(std::move(ret));
- }
- }
- };
- /*****************************************************************/
- inline PyVar __proxy_wrapper(VM* vm, ArgsView args){
- NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
- return (*pf)(vm, args);
- }
- template<typename Ret, typename... Params>
- PyObject* VM::bind(PyObject* obj, const char* sig, Ret(*func)(Params...), BindType bt){
- NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
- return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
- }
- template<typename Ret, typename T, typename... Params>
- PyObject* VM::bind(PyObject* obj, const char* sig, Ret(T::*func)(Params...), BindType bt){
- NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
- return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
- }
- template<typename Ret, typename... Params>
- PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(*func)(Params...), BindType bt){
- NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
- return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
- }
- template<typename Ret, typename T, typename... Params>
- PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(T::*func)(Params...), BindType bt){
- NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
- return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
- }
- template<typename T, typename F, bool ReadOnly>
- PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
- static_assert(!std::is_reference_v<F>);
- PK_ASSERT(is_type(obj, tp_type));
- std::string_view name_sv(name); int pos = name_sv.find(':');
- if(pos > 0) name_sv = name_sv.substr(0, pos);
- auto fget = [](VM* vm, ArgsView args) -> PyVar{
- obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
- F T::*field = lambda_get_userdata<F T::*>(args.begin());
- return VAR(self.*field);
- };
- PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1, field);
- PyVar _1 = vm->None;
- if constexpr (!ReadOnly){
- auto fset = [](VM* vm, ArgsView args){
- obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
- F T::*field = lambda_get_userdata<F T::*>(args.begin());
- self.*field = py_cast<F>(vm, args[1]);
- return vm->None;
- };
- _1 = new_object<NativeFunc>(tp_native_func, fset, 2, field);
- }
- PyObject* prop = heap.gcnew<Property>(tp_property, _0, _1);
- obj->attr().set(StrName(name_sv), prop);
- return prop;
- }
- /*****************************************************************/
- #define PY_FIELD(T, NAME, EXPR) \
- vm->bind_property(type, NAME, \
- [](VM* vm, ArgsView args){ \
- obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
- return VAR(self.EXPR); \
- }, \
- [](VM* vm, ArgsView args){ \
- obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
- self.EXPR = CAST(decltype(self.EXPR), args[1]); \
- return vm->None; \
- });
- #define PY_READONLY_FIELD(T, NAME, EXPR) \
- vm->bind_property(type, NAME, \
- [](VM* vm, ArgsView args){ \
- obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
- return VAR(self.EXPR); \
- });
- #define PY_PROPERTY(T, NAME, FGET, FSET) \
- vm->bind_property(type, NAME, \
- [](VM* vm, ArgsView args){ \
- obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
- return VAR(self.FGET()); \
- }, \
- [](VM* vm, ArgsView args){ \
- obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
- using __NT = decltype(self.FGET()); \
- self.FSET(CAST(__NT, args[1])); \
- return vm->None; \
- });
- #define PY_READONLY_PROPERTY(T, NAME, FGET) \
- vm->bind_property(type, NAME, \
- [](VM* vm, ArgsView args){ \
- obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
- return VAR(self.FGET()); \
- });
- /*****************************************************************/
- #define PY_STRUCT_LIKE(wT) \
- static_assert(std::is_trivially_copyable<wT>::value); \
- static_assert(!is_sso_v<wT>); \
- type->attr().set("__struct__", vm->True); \
- vm->bind_func(type, "fromstruct", 1, [](VM* vm, ArgsView args){ \
- Struct& s = CAST(Struct&, args[0]); \
- if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
- PyVar obj = vm->new_user_object<wT>(); \
- memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
- return obj; \
- }, {}, BindType::STATICMETHOD); \
- vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args){ \
- wT& self = _CAST(wT&, args[0]); \
- return vm->new_user_object<Struct>(&self, sizeof(wT)); \
- }); \
- vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args){ \
- wT& self = _CAST(wT&, args[0]); \
- return vm->new_user_object<VoidP>(&self); \
- }); \
- vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args){ \
- wT& self = _CAST(wT&, args[0]); \
- return vm->new_user_object<wT>(self); \
- }); \
- vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args){ \
- return VAR(sizeof(wT)); \
- }); \
- vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
- wT& self = _CAST(wT&, _0); \
- if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
- wT& other = _CAST(wT&, _1); \
- return VAR(self == other); \
- }); \
- #define PY_POINTER_SETGETITEM(T) \
- vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
- obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
- i64 i = CAST(i64, _1); \
- T* tgt = reinterpret_cast<T*>(self.ptr); \
- return VAR(tgt[i]); \
- }); \
- vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){ \
- obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
- i64 i = CAST(i64, _1); \
- T* tgt = reinterpret_cast<T*>(self.ptr); \
- tgt[i] = CAST(T, _2); \
- }); \
- } // namespace pkpy
|