bindings.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #pragma once
  2. #include "cffi.h"
  3. #include "vm.h"
  4. namespace pkpy{
  5. struct NativeProxyFuncCBase {
  6. virtual PyVar operator()(VM* vm, ArgsView args) = 0;
  7. };
  8. template<typename Ret, typename... Params>
  9. struct NativeProxyFuncC final: NativeProxyFuncCBase {
  10. static constexpr int N = sizeof...(Params);
  11. using _Fp = Ret(*)(Params...);
  12. _Fp func;
  13. NativeProxyFuncC(_Fp func) : func(func) {}
  14. PyVar operator()(VM* vm, ArgsView args) override {
  15. PK_DEBUG_ASSERT(args.size() == N);
  16. return call<Ret>(vm, args, std::make_index_sequence<N>());
  17. }
  18. template<typename __Ret, size_t... Is>
  19. PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){
  20. if constexpr(std::is_void_v<__Ret>){
  21. func(py_cast<Params>(vm, args[Is])...);
  22. return vm->None;
  23. }else{
  24. __Ret ret = func(py_cast<Params>(vm, args[Is])...);
  25. return VAR(std::move(ret));
  26. }
  27. }
  28. };
  29. template<typename Ret, typename T, typename... Params>
  30. struct NativeProxyMethodC final: NativeProxyFuncCBase {
  31. static constexpr int N = sizeof...(Params);
  32. using _Fp = Ret(T::*)(Params...);
  33. _Fp func;
  34. NativeProxyMethodC(_Fp func) : func(func) {}
  35. PyVar operator()(VM* vm, ArgsView args) override {
  36. PK_DEBUG_ASSERT(args.size() == N+1);
  37. return call<Ret>(vm, args, std::make_index_sequence<N>());
  38. }
  39. template<typename __Ret, size_t... Is>
  40. PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){
  41. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); // use unsafe cast for derived classes
  42. if constexpr(std::is_void_v<__Ret>){
  43. (self.*func)(py_cast<Params>(vm, args[Is+1])...);
  44. return vm->None;
  45. }else{
  46. __Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
  47. return VAR(std::move(ret));
  48. }
  49. }
  50. };
  51. /*****************************************************************/
  52. inline PyVar __proxy_wrapper(VM* vm, ArgsView args){
  53. NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
  54. return (*pf)(vm, args);
  55. }
  56. template<typename Ret, typename... Params>
  57. PyObject* VM::bind(PyObject* obj, const char* sig, Ret(*func)(Params...), BindType bt){
  58. NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
  59. return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
  60. }
  61. template<typename Ret, typename T, typename... Params>
  62. PyObject* VM::bind(PyObject* obj, const char* sig, Ret(T::*func)(Params...), BindType bt){
  63. NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
  64. return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
  65. }
  66. template<typename Ret, typename... Params>
  67. PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(*func)(Params...), BindType bt){
  68. NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
  69. return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
  70. }
  71. template<typename Ret, typename T, typename... Params>
  72. PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(T::*func)(Params...), BindType bt){
  73. NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
  74. return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
  75. }
  76. template<typename T, typename F, bool ReadOnly>
  77. PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
  78. static_assert(!std::is_reference_v<F>);
  79. PK_ASSERT(is_type(obj, tp_type));
  80. std::string_view name_sv(name); int pos = name_sv.find(':');
  81. if(pos > 0) name_sv = name_sv.substr(0, pos);
  82. auto fget = [](VM* vm, ArgsView args) -> PyVar{
  83. obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
  84. F T::*field = lambda_get_userdata<F T::*>(args.begin());
  85. return VAR(self.*field);
  86. };
  87. PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1, field);
  88. PyVar _1 = vm->None;
  89. if constexpr (!ReadOnly){
  90. auto fset = [](VM* vm, ArgsView args){
  91. obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
  92. F T::*field = lambda_get_userdata<F T::*>(args.begin());
  93. self.*field = py_cast<F>(vm, args[1]);
  94. return vm->None;
  95. };
  96. _1 = new_object<NativeFunc>(tp_native_func, fset, 2, field);
  97. }
  98. PyObject* prop = heap.gcnew<Property>(tp_property, _0, _1);
  99. obj->attr().set(StrName(name_sv), prop);
  100. return prop;
  101. }
  102. /*****************************************************************/
  103. #define PY_FIELD(T, NAME, EXPR) \
  104. vm->bind_property(type, NAME, \
  105. [](VM* vm, ArgsView args){ \
  106. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  107. return VAR(self.EXPR); \
  108. }, \
  109. [](VM* vm, ArgsView args){ \
  110. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  111. self.EXPR = CAST(decltype(self.EXPR), args[1]); \
  112. return vm->None; \
  113. });
  114. #define PY_READONLY_FIELD(T, NAME, EXPR) \
  115. vm->bind_property(type, NAME, \
  116. [](VM* vm, ArgsView args){ \
  117. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  118. return VAR(self.EXPR); \
  119. });
  120. #define PY_PROPERTY(T, NAME, FGET, FSET) \
  121. vm->bind_property(type, NAME, \
  122. [](VM* vm, ArgsView args){ \
  123. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  124. return VAR(self.FGET()); \
  125. }, \
  126. [](VM* vm, ArgsView args){ \
  127. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  128. using __NT = decltype(self.FGET()); \
  129. self.FSET(CAST(__NT, args[1])); \
  130. return vm->None; \
  131. });
  132. #define PY_READONLY_PROPERTY(T, NAME, FGET) \
  133. vm->bind_property(type, NAME, \
  134. [](VM* vm, ArgsView args){ \
  135. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  136. return VAR(self.FGET()); \
  137. });
  138. /*****************************************************************/
  139. #define PY_STRUCT_LIKE(wT) \
  140. static_assert(std::is_trivially_copyable<wT>::value); \
  141. static_assert(!is_sso_v<wT>); \
  142. type->attr().set("__struct__", vm->True); \
  143. vm->bind_func(type, "fromstruct", 1, [](VM* vm, ArgsView args){ \
  144. Struct& s = CAST(Struct&, args[0]); \
  145. if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
  146. PyVar obj = vm->new_user_object<wT>(); \
  147. memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
  148. return obj; \
  149. }, {}, BindType::STATICMETHOD); \
  150. vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args){ \
  151. wT& self = _CAST(wT&, args[0]); \
  152. return vm->new_user_object<Struct>(&self, sizeof(wT)); \
  153. }); \
  154. vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args){ \
  155. wT& self = _CAST(wT&, args[0]); \
  156. return vm->new_user_object<VoidP>(&self); \
  157. }); \
  158. vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args){ \
  159. wT& self = _CAST(wT&, args[0]); \
  160. return vm->new_user_object<wT>(self); \
  161. }); \
  162. vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args){ \
  163. return VAR(sizeof(wT)); \
  164. }); \
  165. vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
  166. wT& self = _CAST(wT&, _0); \
  167. if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
  168. wT& other = _CAST(wT&, _1); \
  169. return VAR(self == other); \
  170. }); \
  171. #define PY_POINTER_SETGETITEM(T) \
  172. vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
  173. obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
  174. i64 i = CAST(i64, _1); \
  175. T* tgt = reinterpret_cast<T*>(self.ptr); \
  176. return VAR(tgt[i]); \
  177. }); \
  178. vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){ \
  179. obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
  180. i64 i = CAST(i64, _1); \
  181. T* tgt = reinterpret_cast<T*>(self.ptr); \
  182. tgt[i] = CAST(T, _2); \
  183. }); \
  184. } // namespace pkpy