diff --git a/include/pocketpy/bindings.h b/include/pocketpy/bindings.h index 92ac5e0e..f3a6f53d 100644 --- a/include/pocketpy/bindings.h +++ b/include/pocketpy/bindings.h @@ -1,9 +1,9 @@ #pragma once #include "cffi.h" +#include "vm.h" namespace pkpy{ - struct NativeProxyFuncCBase { virtual PyObject* operator()(VM* vm, ArgsView args) = 0; }; @@ -56,62 +56,63 @@ struct NativeProxyMethodC final: NativeProxyFuncCBase { } } }; - -inline PyObject* proxy_wrapper(VM* vm, ArgsView args){ +/*****************************************************************/ +inline PyObject* __proxy_wrapper(VM* vm, ArgsView args){ NativeProxyFuncCBase* pf = lambda_get_userdata(args.begin()); return (*pf)(vm, args); } template -void _bind(VM* vm, PyObject* obj, const char* sig, Ret(*func)(Params...)){ +PyObject* VM::bind(PyObject* obj, const char* sig, Ret(*func)(Params...), BindType bt){ auto proxy = new NativeProxyFuncC(func); - vm->bind(obj, sig, proxy_wrapper, proxy); + return vm->bind(obj, sig, __proxy_wrapper, proxy, bt); } template -void _bind(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...)){ +PyObject* VM::bind(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...), BindType bt){ auto proxy = new NativeProxyMethodC(func); - vm->bind(obj, sig, proxy_wrapper, proxy); + return vm->bind(obj, sig, __proxy_wrapper, proxy, bt); } -/*****************************************************************/ -#define PY_FIELD_EX(T, NAME, REF, EXPR) \ - vm->bind_property(type, NAME, \ - [](VM* vm, ArgsView args){ \ - T& self = PK_OBJ_GET(T, args[0]); \ - return VAR(self.REF()->EXPR); \ - }, \ - [](VM* vm, ArgsView args){ \ - T& self = PK_OBJ_GET(T, args[0]); \ - self.REF()->EXPR = CAST(decltype(self.REF()->EXPR), args[1]); \ - return vm->None; \ - }); -#define PY_READONLY_FIELD_EX(T, NAME, REF, EXPR) \ - vm->bind_property(type, NAME, \ - [](VM* vm, ArgsView args){ \ - T& self = PK_OBJ_GET(T, args[0]); \ - return VAR(self.REF()->EXPR); \ - }); +template +PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(*func)(Params...), BindType bt){ + auto proxy = new NativeProxyFuncC(func); + return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt); +} -#define PY_PROPERTY_EX(T, NAME, REF, FGET, FSET) \ - vm->bind_property(type, NAME, \ - [](VM* vm, ArgsView args){ \ - T& self = PK_OBJ_GET(T, args[0]); \ - return VAR(self.REF()->FGET()); \ - }, \ - [](VM* vm, ArgsView args){ \ - T& self = _CAST(T&, args[0]); \ - using __NT = decltype(self.REF()->FGET()); \ - self.REF()->FSET(CAST(__NT, args[1])); \ - return vm->None; \ - }); +template +PyObject* VM::bind(VM* vm, PyObject* obj, const char* sig, const char* docstring, Ret(T::*func)(Params...), BindType bt){ + auto proxy = new NativeProxyMethodC(func); + return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt); +} -#define PY_READONLY_PROPERTY_EX(T, NAME, REF, FGET) \ - vm->bind_property(type, NAME, \ - [](VM* vm, ArgsView args){ \ - T& self = PK_OBJ_GET(T, args[0]); \ - return VAR(self.REF()->FGET()); \ - }); +template +PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){ + static_assert(!std::is_reference_v); + 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) -> PyObject*{ + T& self = PK_OBJ_GET(T, args[0]); + F T::*field = lambda_get_userdata(args.begin()); + return VAR(self.*field); + }; + PyObject* _0 = heap.gcnew(tp_native_func, fget, 1, false); + PK_OBJ_GET(NativeFunc, _0).set_userdata(field); + PyObject* _1 = vm->None; + if constexpr (!ReadOnly){ + auto fset = [](VM* vm, ArgsView args){ + T& self = PK_OBJ_GET(T, args[0]); + F T::*field = lambda_get_userdata(args.begin()); + self.*field = py_cast(vm, args[1]); + return vm->None; + }; + _1 = heap.gcnew(tp_native_func, fset, 2, false); + PK_OBJ_GET(NativeFunc, _1).set_userdata(field); + } + PyObject* prop = VAR(Property(_0, _1)); + obj->attr().set(StrName(name_sv), prop); + return prop; +} /*****************************************************************/ #define PY_FIELD(T, NAME, EXPR) \ vm->bind_property(type, NAME, \ @@ -152,7 +153,6 @@ void _bind(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...)){ return VAR(self.FGET()); \ }); /*****************************************************************/ - #define PY_STRUCT_LIKE(wT) \ static_assert(std::is_trivially_copyable::value); \ type->attr().set("__struct__", vm->True); \ diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index c4f3a086..5bb2d2af 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -302,6 +302,16 @@ public: } PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT); PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT); + + template + PyObject* bind(PyObject* obj, const char* sig, Ret(*func)(Params...), BindType bt=BindType::DEFAULT); + template + PyObject* bind(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...), BindType bt=BindType::DEFAULT); + template + PyObject* bind(PyObject* obj, const char* sig, const char* docstring, Ret(*func)(Params...), BindType bt=BindType::DEFAULT); + template + PyObject* bind(VM* vm, PyObject* obj, const char* sig, const char* docstring, Ret(T::*func)(Params...), BindType bt=BindType::DEFAULT); + PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset=nullptr); template PyObject* bind_field(PyObject*, const char*, F T::*); @@ -344,24 +354,8 @@ public: Type _tp_user(){ return _find_type_in_cxx_typeid_map(); } template bool is_user_type(PyObject* obj){ return _tp(obj) == _tp_user(); } - template - PyObject* register_user_class(PyObject* mod, StrName name, bool subclass_enabled=false){ - PyObject* type = new_type_object(mod, name, 0, subclass_enabled); - mod->attr().set(name, type); - _cxx_typeid_map[typeid(T)] = PK_OBJ_GET(Type, type); - T::_register(vm, mod, type); - // check if T is trivially constructible - if constexpr(!std::is_default_constructible_v){ - if(!type->attr().contains(__new__)){ - bind_func(type, __new__, -1, [](VM* vm, ArgsView args){ - vm->NotImplementedError(); - return vm->None; - }); - } - } - return type; - } + PyObject* register_user_class(PyObject* mod, StrName name, bool subclass_enabled=false); template PyObject* new_user_object(Args&&... args){ @@ -548,32 +542,22 @@ __T py_cast(VM* vm, PyObject* obj) { return _py_cast__internal<__T, true>(vm, o template __T _py_cast(VM* vm, PyObject* obj) { return _py_cast__internal<__T, false>(vm, obj); } -template -PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){ - static_assert(!std::is_reference_v); - 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) -> PyObject*{ - T& self = PK_OBJ_GET(T, args[0]); - F T::*field = lambda_get_userdata(args.begin()); - return VAR(self.*field); - }; - PyObject* _0 = heap.gcnew(tp_native_func, fget, 1, false); - PK_OBJ_GET(NativeFunc, _0).set_userdata(field); - PyObject* _1 = vm->None; - if constexpr (!ReadOnly){ - auto fset = [](VM* vm, ArgsView args){ - T& self = PK_OBJ_GET(T, args[0]); - F T::*field = lambda_get_userdata(args.begin()); - self.*field = py_cast(vm, args[1]); - return vm->None; - }; - _1 = heap.gcnew(tp_native_func, fset, 2, false); - PK_OBJ_GET(NativeFunc, _1).set_userdata(field); +template +PyObject* VM::register_user_class(PyObject* mod, StrName name, bool subclass_enabled){ + PyObject* type = new_type_object(mod, name, 0, subclass_enabled); + mod->attr().set(name, type); + _cxx_typeid_map[typeid(T)] = PK_OBJ_GET(Type, type); + T::_register(vm, mod, type); + // check if T is trivially constructible + if constexpr(!std::is_default_constructible_v){ + if(!type->attr().contains(__new__)){ + bind_func(type, __new__, -1, [](VM* vm, ArgsView args){ + vm->NotImplementedError(); + return vm->None; + }); + } } - PyObject* prop = VAR(Property(_0, _1)); - obj->attr().set(StrName(name_sv), prop); - return prop; + return type; } } // namespace pkpy \ No newline at end of file