bindings.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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. PyVar VM::bind(PyVar 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. PyVar VM::bind(PyVar 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. PyVar VM::bind(PyVar 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. PyVar VM::bind(PyVar 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. PyVar VM::bind_field(PyVar 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. PyVar prop = VAR(Property(_0, _1));
  99. obj->attr().set(StrName(name_sv), prop);
  100. return prop;
  101. }
  102. template<typename Ret, typename... Params>
  103. [[deprecated]] void _bind(VM* vm, PyVar obj, const char* sig, Ret(*func)(Params...)){
  104. return vm->bind(obj, sig, func);
  105. }
  106. template<typename Ret, typename T, typename... Params>
  107. [[deprecated]] void _bind(VM* vm, PyVar obj, const char* sig, Ret(T::*func)(Params...)){
  108. return vm->bind(obj, sig, func);
  109. }
  110. /*****************************************************************/
  111. #define PY_FIELD(T, NAME, EXPR) \
  112. vm->bind_property(type, NAME, \
  113. [](VM* vm, ArgsView args){ \
  114. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  115. return VAR(self.EXPR); \
  116. }, \
  117. [](VM* vm, ArgsView args){ \
  118. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  119. self.EXPR = CAST(decltype(self.EXPR), args[1]); \
  120. return vm->None; \
  121. });
  122. #define PY_READONLY_FIELD(T, NAME, EXPR) \
  123. vm->bind_property(type, NAME, \
  124. [](VM* vm, ArgsView args){ \
  125. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  126. return VAR(self.EXPR); \
  127. });
  128. #define PY_PROPERTY(T, NAME, FGET, FSET) \
  129. vm->bind_property(type, NAME, \
  130. [](VM* vm, ArgsView args){ \
  131. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  132. return VAR(self.FGET()); \
  133. }, \
  134. [](VM* vm, ArgsView args){ \
  135. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  136. using __NT = decltype(self.FGET()); \
  137. self.FSET(CAST(__NT, args[1])); \
  138. return vm->None; \
  139. });
  140. #define PY_READONLY_PROPERTY(T, NAME, FGET) \
  141. vm->bind_property(type, NAME, \
  142. [](VM* vm, ArgsView args){ \
  143. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  144. return VAR(self.FGET()); \
  145. });
  146. /*****************************************************************/
  147. #define PY_STRUCT_LIKE(wT) \
  148. static_assert(std::is_trivially_copyable<wT>::value); \
  149. static_assert(!is_sso_v<wT>); \
  150. type->attr().set("__struct__", vm->True); \
  151. vm->bind_func(type, "fromstruct", 1, [](VM* vm, ArgsView args){ \
  152. Struct& s = CAST(Struct&, args[0]); \
  153. if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
  154. PyVar obj = vm->new_user_object<wT>(); \
  155. memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
  156. return obj; \
  157. }, {}, BindType::STATICMETHOD); \
  158. vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args){ \
  159. wT& self = _CAST(wT&, args[0]); \
  160. return vm->new_user_object<Struct>(&self, sizeof(wT)); \
  161. }); \
  162. vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args){ \
  163. wT& self = _CAST(wT&, args[0]); \
  164. return vm->new_user_object<VoidP>(&self); \
  165. }); \
  166. vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args){ \
  167. wT& self = _CAST(wT&, args[0]); \
  168. return vm->new_user_object<wT>(self); \
  169. }); \
  170. vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args){ \
  171. return VAR(sizeof(wT)); \
  172. }); \
  173. vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \
  174. wT& self = _CAST(wT&, _0); \
  175. if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
  176. wT& other = _CAST(wT&, _1); \
  177. return VAR(self == other); \
  178. }); \
  179. #define PY_POINTER_SETGETITEM(T) \
  180. vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \
  181. obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
  182. i64 i = CAST(i64, _1); \
  183. T* tgt = reinterpret_cast<T*>(self.ptr); \
  184. return VAR(tgt[i]); \
  185. }); \
  186. vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){ \
  187. obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
  188. i64 i = CAST(i64, _1); \
  189. T* tgt = reinterpret_cast<T*>(self.ptr); \
  190. tgt[i] = CAST(T, _2); \
  191. }); \
  192. } // namespace pkpy