bindings.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #pragma once
  2. #include "pocketpy/interpreter/cffi.hpp"
  3. namespace pkpy {
  4. struct NativeProxyFuncCBase {
  5. virtual PyVar operator() (VM* vm, ArgsView args) = 0;
  6. };
  7. template <typename Ret, typename... Params>
  8. struct NativeProxyFuncC final : NativeProxyFuncCBase {
  9. constexpr static int N = sizeof...(Params);
  10. using _Fp = Ret (*)(Params...);
  11. _Fp func;
  12. NativeProxyFuncC(_Fp func) : func(func) {}
  13. PyVar operator() (VM* vm, ArgsView args) override {
  14. assert(args.size() == N);
  15. return call<Ret>(vm, args, std::make_index_sequence<N>());
  16. }
  17. template <typename __Ret, size_t... Is>
  18. PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
  19. if constexpr(std::is_void_v<__Ret>) {
  20. func(py_cast<Params>(vm, args[Is])...);
  21. return vm->None;
  22. } else {
  23. __Ret ret = func(py_cast<Params>(vm, args[Is])...);
  24. return VAR(std::move(ret));
  25. }
  26. }
  27. };
  28. template <typename Ret, typename T, typename... Params>
  29. struct NativeProxyMethodC final : NativeProxyFuncCBase {
  30. constexpr static int N = sizeof...(Params);
  31. using _Fp = Ret (T::*)(Params...);
  32. _Fp func;
  33. NativeProxyMethodC(_Fp func) : func(func) {}
  34. PyVar operator() (VM* vm, ArgsView args) override {
  35. assert(args.size() == N + 1);
  36. return call<Ret>(vm, args, std::make_index_sequence<N>());
  37. }
  38. template <typename __Ret, size_t... Is>
  39. PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
  40. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); // use unsafe cast for derived classes
  41. if constexpr(std::is_void_v<__Ret>) {
  42. (self.*func)(py_cast<Params>(vm, args[Is + 1])...);
  43. return vm->None;
  44. } else {
  45. __Ret ret = (self.*func)(py_cast<Params>(vm, args[Is + 1])...);
  46. return VAR(std::move(ret));
  47. }
  48. }
  49. };
  50. /*****************************************************************/
  51. inline PyVar __proxy_wrapper(VM* vm, ArgsView args) {
  52. NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
  53. return (*pf)(vm, args);
  54. }
  55. template <typename Ret, typename... Params>
  56. PyObject* VM::bind(PyObject* obj, const char* sig, Ret (*func)(Params...), BindType bt) {
  57. NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
  58. return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
  59. }
  60. template <typename Ret, typename T, typename... Params>
  61. PyObject* VM::bind(PyObject* obj, const char* sig, Ret (T::*func)(Params...), BindType bt) {
  62. NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
  63. return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
  64. }
  65. template <typename Ret, typename... Params>
  66. PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret (*func)(Params...), BindType bt) {
  67. NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
  68. return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
  69. }
  70. template <typename Ret, typename T, typename... Params>
  71. PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret (T::*func)(Params...), BindType bt) {
  72. NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
  73. return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
  74. }
  75. template <typename T, typename F, bool ReadOnly>
  76. PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
  77. static_assert(!std::is_reference_v<F>);
  78. assert(is_type(obj, tp_type));
  79. std::string_view name_sv(name);
  80. 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( \
  105. type, \
  106. NAME, \
  107. [](VM* vm, ArgsView args) { \
  108. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  109. return VAR(self.EXPR); \
  110. }, \
  111. [](VM* vm, ArgsView args) { \
  112. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  113. self.EXPR = CAST(decltype(self.EXPR), args[1]); \
  114. return vm->None; \
  115. });
  116. #define PY_READONLY_FIELD(T, NAME, EXPR) \
  117. vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
  118. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  119. return VAR(self.EXPR); \
  120. });
  121. #define PY_PROPERTY(T, NAME, FGET, FSET) \
  122. vm->bind_property( \
  123. type, \
  124. NAME, \
  125. [](VM* vm, ArgsView args) { \
  126. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  127. return VAR(self.FGET()); \
  128. }, \
  129. [](VM* vm, ArgsView args) { \
  130. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  131. using __NT = decltype(self.FGET()); \
  132. self.FSET(CAST(__NT, args[1])); \
  133. return vm->None; \
  134. });
  135. #define PY_READONLY_PROPERTY(T, NAME, FGET) \
  136. vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
  137. obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
  138. return VAR(self.FGET()); \
  139. });
  140. /*****************************************************************/
  141. #define PY_STRUCT_LIKE(wT) \
  142. static_assert(std::is_trivially_copyable<wT>::value); \
  143. static_assert(!is_sso_v<wT>); \
  144. type->attr().set("__struct__", vm->True); \
  145. vm->bind_func( \
  146. type, \
  147. "fromstruct", \
  148. 1, \
  149. [](VM* vm, ArgsView args) { \
  150. Struct& s = CAST(Struct&, args[0]); \
  151. if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
  152. PyVar obj = vm->new_user_object<wT>(); \
  153. std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
  154. return obj; \
  155. }, \
  156. {}, \
  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__(type->as<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__(type->as<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__(type->as<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. #define PK_LAMBDA(x) \
  193. ([](VM* vm, ArgsView args) -> PyVar { \
  194. return x; \
  195. })
  196. #define PK_VAR_LAMBDA(x) \
  197. ([](VM* vm, ArgsView args) -> PyVar { \
  198. return VAR(x); \
  199. })
  200. #define PK_ACTION(x) \
  201. ([](VM* vm, ArgsView args) -> PyVar { \
  202. x; \
  203. return vm->None; \
  204. })
  205. } // namespace pkpy