diff --git a/include/pocketpy/bindings.h b/include/pocketpy/bindings.h index 1dd494f2..18655866 100644 --- a/include/pocketpy/bindings.h +++ b/include/pocketpy/bindings.h @@ -113,4 +113,18 @@ void _bind(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...)){ return VAR(self.REF().FGET()); \ }); +#define PY_STRUCT_LIKE_OBJECT(T) \ + static_assert(std::is_trivially_copyable::value); \ + vm->bind_func<1>(type, "__from_struct__", [](VM* vm, ArgsView args){ \ + C99Struct& s = CAST(C99Struct&, args[0]); \ + if(s.size != sizeof(T)) vm->ValueError("size mismatch"); \ + PyObject* obj = vm->heap.gcnew(T::_type(vm)); \ + memcpy(&_CAST(T&, obj), s.p, sizeof(T)); \ + return obj; \ + }); \ + vm->bind_method<0>(type, "__to_struct__", [](VM* vm, ArgsView args){ \ + T& self = _CAST(T&, args[0]); \ + return VAR_T(C99Struct, &self, sizeof(T)); \ + }); + } // namespace pkpy \ No newline at end of file diff --git a/include/pocketpy/linalg.h b/include/pocketpy/linalg.h index c3bdc77b..a7c94318 100644 --- a/include/pocketpy/linalg.h +++ b/include/pocketpy/linalg.h @@ -1,6 +1,6 @@ #pragma once -#include "cffi.h" +#include "bindings.h" namespace pkpy{ diff --git a/include/pocketpy/str.h b/include/pocketpy/str.h index 2f387aa1..e89ee5bc 100644 --- a/include/pocketpy/str.h +++ b/include/pocketpy/str.h @@ -192,6 +192,9 @@ const StrName __package__ = StrName::get("__package__"); const StrName __path__ = StrName::get("__path__"); const StrName __class__ = StrName::get("__class__"); +const StrName __to_struct__ = StrName::get("__to_struct__"); +const StrName __from_struct__ = StrName::get("__from_struct__"); + const StrName pk_id_add = StrName::get("add"); const StrName pk_id_set = StrName::get("set"); const StrName pk_id_eval = StrName::get("eval"); diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index 92c50bf4..3d597cff 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -399,10 +399,14 @@ public: return _all_types[t.index].obj; } + Type _tp(PyObject* obj){ + if(is_int(obj)) return tp_int; + if(is_float(obj)) return tp_float; + return obj->type; + } + PyObject* _t(PyObject* obj){ - if(is_int(obj)) return _t(tp_int); - if(is_float(obj)) return _t(tp_float); - return _all_types[obj->type].obj; + return _all_types[_tp(obj).index].obj; } struct ImportContext{ diff --git a/include/typings/c.pyi b/include/typings/c.pyi index 3a0348fe..92f69c65 100644 --- a/include/typings/c.pyi +++ b/include/typings/c.pyi @@ -127,3 +127,6 @@ class array(struct): def __getitem__(self, index: int) -> struct: ... def __setitem__(self, index: int, value: struct) -> None: ... def __len__(self) -> int: ... + +def to_struct(obj) -> struct: ... +def from_struct(T: type, obj: struct): ... \ No newline at end of file diff --git a/src/cffi.cpp b/src/cffi.cpp index 27e98605..ed5f852a 100644 --- a/src/cffi.cpp +++ b/src/cffi.cpp @@ -1,4 +1,5 @@ #include "pocketpy/cffi.h" +#include "pocketpy/str.h" namespace pkpy{ @@ -136,7 +137,7 @@ namespace pkpy{ vm->bind_method<0>(type, "copy", [](VM* vm, ArgsView args){ const C99Struct& self = _CAST(C99Struct&, args[0]); - return VAR_T(C99Struct, self); + return vm->heap.gcnew(vm->_tp(args[0]), self); }); vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ @@ -233,6 +234,15 @@ void add_module_c(VM* vm){ return vm->None; }); + vm->bind_func<1>(mod, "to_struct", [](VM* vm, ArgsView args){ + return vm->call_method(args[0], __to_struct__); + }); + + vm->bind_func<2>(mod, "from_struct", [](VM* vm, ArgsView args){ + PyObject* f = vm->getattr(args[0], __from_struct__); + return vm->call(f, args[1]); + }); + VoidP::register_class(vm, mod); C99Struct::register_class(vm, mod); mod->attr().set("NULL", VAR_T(VoidP, nullptr)); diff --git a/src/linalg.cpp b/src/linalg.cpp index 7c0cbae9..aedb049c 100644 --- a/src/linalg.cpp +++ b/src/linalg.cpp @@ -48,6 +48,8 @@ namespace pkpy{ void PyVec2::_register(VM* vm, PyObject* mod, PyObject* type){ + PY_STRUCT_LIKE_OBJECT(PyVec2) + vm->bind_constructor<3>(type, [](VM* vm, ArgsView args){ float x = CAST_F(args[1]); float y = CAST_F(args[2]); @@ -112,6 +114,8 @@ namespace pkpy{ } void PyVec3::_register(VM* vm, PyObject* mod, PyObject* type){ + PY_STRUCT_LIKE_OBJECT(PyVec3) + vm->bind_constructor<4>(type, [](VM* vm, ArgsView args){ float x = CAST_F(args[1]); float y = CAST_F(args[2]); @@ -154,6 +158,8 @@ namespace pkpy{ } void PyVec4::_register(VM* vm, PyObject* mod, PyObject* type){ + PY_STRUCT_LIKE_OBJECT(PyVec4) + vm->bind_constructor<1+4>(type, [](VM* vm, ArgsView args){ float x = CAST_F(args[1]); float y = CAST_F(args[2]); @@ -204,6 +210,8 @@ namespace pkpy{ #undef BIND_VEC_FUNCTION_1 void PyMat3x3::_register(VM* vm, PyObject* mod, PyObject* type){ + PY_STRUCT_LIKE_OBJECT(PyMat3x3) + vm->bind_constructor<-1>(type, [](VM* vm, ArgsView args){ if(args.size() == 1+0) return VAR_T(PyMat3x3, Mat3x3::zeros()); if(args.size() == 1+9){ diff --git a/tests/80_linalg.py b/tests/80_linalg.py index afc880f7..a97c7fe5 100644 --- a/tests/80_linalg.py +++ b/tests/80_linalg.py @@ -470,4 +470,10 @@ temp_vec2 = test_mat_copy.transform_point(test_vec2_copy) test_mat_copy = test_mat.copy() test_mat_copy = test_mat.copy() test_vec2_copy = test_vec2.copy() -temp_vec2 = test_mat_copy.transform_vector(test_vec2_copy) \ No newline at end of file +temp_vec2 = test_mat_copy.transform_vector(test_vec2_copy) + +import c +a = vec2(1, 2) +b = c.to_struct(a) +assert b.size() == 8 +assert c.from_struct(vec2, b) == a \ No newline at end of file