From 6dad2d612ef72353bc54ddd5a962de0afe9a8cdc Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Mon, 9 Oct 2023 00:03:23 +0800 Subject: [PATCH] ... --- build.sh | 2 +- docs/bindings.md | 6 ++++++ include/typings/c.pyi | 5 ++++- src/cffi.cpp | 16 ++++++++++++++++ tests/80_c.py | 14 +++++++++++++- 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index 0a2303f4..12648298 100644 --- a/build.sh +++ b/build.sh @@ -14,7 +14,7 @@ if ! type -P clang++ >/dev/null 2>&1; then exit 1 fi -echo "Requirements satisfied: python3 and clang++ are installed." +echo "Requirements satisfied: python3 and clang are installed." echo "It takes a moment to finish building." echo "" echo "> Running prebuild.py... " diff --git a/docs/bindings.md b/docs/bindings.md index 7ace3cf7..98ad9742 100644 --- a/docs/bindings.md +++ b/docs/bindings.md @@ -227,6 +227,12 @@ struct Container{ } ``` +For global objects, use the callback in `vm->heap`. +```cpp +void (*_gc_marker_ex)(VM*) = nullptr; +``` +It will be invoked before a GC starts. So you can mark objects inside the callback to keep them alive. + ### Others You may see somewhere in the code that `vm->bind_method<>` or `vm->bind_func<>` is used. diff --git a/include/typings/c.pyi b/include/typings/c.pyi index 1ab69684..06b1345f 100644 --- a/include/typings/c.pyi +++ b/include/typings/c.pyi @@ -32,7 +32,10 @@ class Pointer(Generic[T], void_p): def __getitem__(self, index: int) -> T: ... def __setitem__(self, index: int, value: T) -> None: ... -class char_p(Pointer[int]): pass +class char_p(Pointer[int]): + def read_string(self) -> str: ... + def write_string(self, value: str) -> None: ... + class uchar_p(Pointer[int]): pass class short_p(Pointer[int]): pass class ushort_p(Pointer[int]): pass diff --git a/src/cffi.cpp b/src/cffi.cpp index 2d23bdb1..7bdf6023 100644 --- a/src/cffi.cpp +++ b/src/cffi.cpp @@ -226,6 +226,22 @@ void add_module_c(VM* vm){ BIND_PRIMITIVE(bool, "bool") #undef BIND_PRIMITIVE + + PyObject* char_p_t = mod->attr("char_p"); + vm->bind(char_p_t, "read_string(self) -> str", [](VM* vm, ArgsView args){ + VoidP& voidp = PK_OBJ_GET(VoidP, args[0]); + const char* target = (const char*)voidp.ptr; + return VAR(target); + }); + + vm->bind(char_p_t, "write_string(self, value: str)", [](VM* vm, ArgsView args){ + VoidP& voidp = PK_OBJ_GET(VoidP, args[0]); + std::string_view sv = CAST(Str&, args[1]).sv(); + char* target = (char*)voidp.ptr; + memcpy(target, sv.data(), sv.size()); + target[sv.size()] = '\0'; + return vm->None; + }); } } // namespace pkpy \ No newline at end of file diff --git a/tests/80_c.py b/tests/80_c.py index f61484c6..55d4d854 100644 --- a/tests/80_c.py +++ b/tests/80_c.py @@ -49,4 +49,16 @@ class Vec2(c.struct): a = Vec2(1, 2) assert isinstance(a, c.struct) assert type(a) is Vec2 -assert repr(a) == "Vec2(1.0, 2.0)" \ No newline at end of file +assert repr(a) == "Vec2(1.0, 2.0)" + +a = c.struct(10) +p = c.p_cast(a.addr(), c.char_p) +p.write_string("Hello!") +assert p[0] == ord("H") +assert p[1] == ord("e") +assert p[2] == ord("l") +assert p[3] == ord("l") +assert p[4] == ord("o") +assert p[5] == ord("!") +assert p[6] == 0 +assert p.read_string() == "Hello!"