diff --git a/src/c.pyi b/src/c.pyi index 828b1f68..32a34d94 100644 --- a/src/c.pyi +++ b/src/c.pyi @@ -3,6 +3,11 @@ from typing import overload def malloc(size: int) -> 'void_p': ... def free(ptr: 'void_p') -> None: ... def sizeof(type: str) -> int: ... +def refl(name: str) -> '_refl': ... + +class _refl: + __name__: str + __size__: int class void_p: def __add__(self, i: int) -> 'void_p': ... @@ -10,20 +15,37 @@ class void_p: def __eq__(self, other: 'void_p') -> bool: ... def __ne__(self, other: 'void_p') -> bool: ... - def char(self) -> int: ... - def uchar(self) -> int: ... - def short(self) -> int: ... - def ushort(self) -> int: ... - def int(self) -> int: ... - def uint(self) -> int: ... - def long(self) -> int: ... - def ulong(self) -> int: ... - def longlong(self) -> int: ... - def ulonglong(self) -> int: ... - def float(self) -> float: ... - def double(self) -> float: ... - def bool(self) -> bool: ... - def void_p(self) -> 'void_p': ... + def read_char(self) -> int: ... + def read_uchar(self) -> int: ... + def read_short(self) -> int: ... + def read_ushort(self) -> int: ... + def read_int(self) -> int: ... + def read_uint(self) -> int: ... + def read_long(self) -> int: ... + def read_ulong(self) -> int: ... + def read_longlong(self) -> int: ... + def read_ulonglong(self) -> int: ... + def read_float(self) -> float: ... + def read_double(self) -> float: ... + def read_bool(self) -> bool: ... + def read_void_p(self) -> 'void_p': ... + def read_bytes(self, size: int) -> bytes: ... + + def write_char(self, value: int) -> None: ... + def write_uchar(self, value: int) -> None: ... + def write_short(self, value: int) -> None: ... + def write_ushort(self, value: int) -> None: ... + def write_int(self, value: int) -> None: ... + def write_uint(self, value: int) -> None: ... + def write_long(self, value: int) -> None: ... + def write_ulong(self, value: int) -> None: ... + def write_longlong(self, value: int) -> None: ... + def write_ulonglong(self, value: int) -> None: ... + def write_float(self, value: float) -> None: ... + def write_double(self, value: float) -> None: ... + def write_bool(self, value: bool) -> None: ... + def write_void_p(self, value: 'void_p') -> None: ... + def write_bytes(self, value: bytes) -> None: ... def get_base_offset(self) -> int: ... @overload diff --git a/src/cffi.h b/src/cffi.h index 3dcfe586..0ebd25da 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -113,11 +113,11 @@ struct VoidP{ }); #define BIND_SETGET(T, name) \ - vm->bind_method<0>(type, name, [](VM* vm, ArgsView args){ \ + vm->bind_method<0>(type, "read_" name, [](VM* vm, ArgsView args){ \ VoidP& self = _CAST(VoidP&, args[0]); \ return VAR(*(T*)self.ptr); \ }); \ - vm->bind_method<1>(type, "set_" name, [](VM* vm, ArgsView args){ \ + vm->bind_method<1>(type, "write_" name, [](VM* vm, ArgsView args){ \ VoidP& self = _CAST(VoidP&, args[0]); \ *(T*)self.ptr = CAST(T, args[1]); \ return vm->None; \ @@ -137,21 +137,36 @@ struct VoidP{ BIND_SETGET(double, "double") BIND_SETGET(bool, "bool") - vm->bind_method<0>(type, "void_p", [](VM* vm, ArgsView args){ + vm->bind_method<0>(type, "read_void_p", [](VM* vm, ArgsView args){ VoidP& self = _CAST(VoidP&, args[0]); return VAR_T(VoidP, *(void**)self.ptr); }); - vm->bind_method<1>(type, "set_void_p", [](VM* vm, ArgsView args){ + vm->bind_method<1>(type, "write_void_p", [](VM* vm, ArgsView args){ VoidP& self = _CAST(VoidP&, args[0]); VoidP& other = CAST(VoidP&, args[0]); self.ptr = other.ptr; return vm->None; }); + + vm->bind_method<1>(type, "read_bytes", [](VM* vm, ArgsView args){ + VoidP& self = _CAST(VoidP&, args[0]); + i64 size = CAST(i64, args[1]); + std::vector buffer(size); + memcpy(buffer.data(), self.ptr, size); + return VAR(Bytes(std::move(buffer))); + }); + + vm->bind_method<1>(type, "write_bytes", [](VM* vm, ArgsView args){ + VoidP& self = _CAST(VoidP&, args[0]); + Bytes& bytes = CAST(Bytes&, args[1]); + memcpy(self.ptr, bytes.data(), bytes.size()); + return vm->None; + }); } }; -struct Struct{ - PY_CLASS(Struct, c, struct) +struct C99Struct{ + PY_CLASS(C99Struct, c, struct) static constexpr int INLINE_SIZE = 32; @@ -159,7 +174,7 @@ struct Struct{ char* p; template - Struct(const T& data){ + C99Struct(const T& data){ static_assert(std::is_pod_v); if(sizeof(T) <= INLINE_SIZE){ memcpy(_inlined, &data, sizeof(T)); @@ -170,10 +185,10 @@ struct Struct{ } } - Struct() { p = _inlined; } - ~Struct(){ if(p!=_inlined) free(p); } + C99Struct() { p = _inlined; } + ~C99Struct(){ if(p!=_inlined) free(p); } - Struct(const Struct& other){ + C99Struct(const C99Struct& other){ if(other.p == other._inlined){ memcpy(_inlined, other._inlined, INLINE_SIZE); p = _inlined; @@ -184,21 +199,68 @@ struct Struct{ } static void _register(VM* vm, PyObject* mod, PyObject* type){ - vm->bind_default_constructor(type); + vm->bind_default_constructor(type); vm->bind_method<0>(type, "address", [](VM* vm, ArgsView args){ - Struct& self = _CAST(Struct&, args[0]); + C99Struct& self = _CAST(C99Struct&, args[0]); return VAR_T(VoidP, self.p); }); vm->bind_method<0>(type, "copy", [](VM* vm, ArgsView args){ - const Struct& self = _CAST(Struct&, args[0]); - return VAR_T(Struct, self); + const C99Struct& self = _CAST(C99Struct&, args[0]); + return VAR_T(C99Struct, self); + }); + + // patch void_p + // type = vm->_t(VoidP::_type(vm)); + + // vm->bind_method<1>(type, "read_struct", [](VM* vm, ArgsView args){ + // VoidP& self = _CAST(VoidP&, args[0]); + // Str& type = CAST(Str&, args[1]); + // return VAR_T(C99Struct) + // }); + + // vm->bind_method<1>(type, "write_struct", [](VM* vm, ArgsView args){ + // VoidP& self = _CAST(VoidP&, args[0]); + // Str& type = CAST(Str&, args[1]); + // VoidP& other = CAST(VoidP&, args[2]); + // c99_write_struct(vm, type, self.ptr, other.ptr); + // return vm->None; + // }); + } +}; + +struct ReflField{ + std::string_view name; + int offset; +}; + +struct ReflType{ + std::string_view name; + size_t size; + std::vector fields; +}; +inline static std::map _refl_types; + +template +inline void add_refl_type(std::string_view name, std::initializer_list fields){ + _refl_types[name] = {name, sizeof(T), fields}; +} + +struct C99ReflType{ + PY_CLASS(C99ReflType, c, "_refl") + Str repr; + static void _register(VM* vm, PyObject* mod, PyObject* type){ + vm->bind_constructor<-1>(type, CPP_NOT_IMPLEMENTED()); + + vm->bind_method<0>(type, "__repr__", [](VM* vm, ArgsView args){ + C99ReflType& self = _CAST(C99ReflType&, args[0]); + return VAR(self.repr); }); } }; -static_assert(sizeof(Py_) <= 64); +static_assert(sizeof(Py_) <= 64); inline PyObject* py_var(VM* vm, void* p){ return VAR_T(VoidP, p); @@ -218,13 +280,13 @@ T to_void_p(VM* vm, PyObject* var){ template T to_plain_old_data(VM* vm, PyObject* var){ static_assert(std::is_pod_v); - Struct& pod = CAST(Struct&, var); + C99Struct& pod = CAST(C99Struct&, var); return *reinterpret_cast(pod.p); } template std::enable_if_t && !std::is_pointer_v, PyObject*> py_var(VM* vm, const T& data){ - return VAR_T(Struct, data); + return VAR_T(C99Struct, data); } /*****************************************************************/ struct NativeProxyFuncCBase { @@ -297,8 +359,22 @@ inline void add_module_c(VM* vm){ return VAR(size); }); + vm->bind_func<1>(mod, "refl", [](VM* vm, ArgsView args){ + const Str& key = CAST(Str&, args[0]); + auto it = _refl_types.find(key.sv()); + if(it == _refl_types.end()) vm->ValueError("reflection type not found"); + const ReflType& rt = it->second; + PyObject* obj = VAR_T(C99ReflType); + obj->enable_instance_dict(); + obj->attr().set("__name__", VAR(rt.name)); + obj->attr().set("__size__", VAR(rt.size)); + for(auto [k,v]: rt.fields) obj->attr().set(StrName::get(k), VAR(v)); + return obj; + }); + VoidP::register_class(vm, mod); - Struct::register_class(vm, mod); + C99Struct::register_class(vm, mod); + C99ReflType::register_class(vm, mod); mod->attr().set("NULL", VAR_T(VoidP, nullptr)); } diff --git a/src/obj.h b/src/obj.h index c8a1f851..3e99d27b 100644 --- a/src/obj.h +++ b/src/obj.h @@ -229,7 +229,9 @@ template T to_plain_old_data(VM*, PyObject*); template __T py_cast(VM* vm, PyObject* obj) { using T = std::decay_t<__T>; - if constexpr(std::is_pointer_v){ + if constexpr(std::is_enum_v){ + return (__T)py_cast(vm, obj); + }else if constexpr(std::is_pointer_v){ return to_void_p(vm, obj); }else if constexpr(is_py_class::value){ T::_check_type(vm, obj); @@ -244,7 +246,9 @@ __T py_cast(VM* vm, PyObject* obj) { template __T _py_cast(VM* vm, PyObject* obj) { using T = std::decay_t<__T>; - if constexpr(std::is_pointer_v<__T>){ + if constexpr(std::is_enum_v){ + return (__T)_py_cast(vm, obj); + }else if constexpr(std::is_pointer_v<__T>){ return to_void_p<__T>(vm, obj); }else if constexpr(is_py_class::value){ return OBJ_GET(T, obj);