mirror of
https://github.com/hanzoai/plugin.git
synced 2026-10-30 18:23:48 +00:00
The contract was written down twice — zip declares Module and Loader, and the loader beside base's runners declared its own copy. Structural typing was the only thing keeping them equal, which is a property nobody can see and a compiler will not check. This implements zip's. The loader, the manifest and the runners live here so cloud can stop carrying a second goja runtime of its own — a shim, a bundler and a third registry that answered the same question this one does. native, goja, wazero and pyvm. wazero is the reason this is not a list of four languages: anything compiled to WebAssembly ahead of time arrives without a new runner, and Rust walks through that door rather than getting one built for it. pyvm is real CPython through cgo with PEP 684 sub-interpreters, behind a build tag, because embedding the language beats reimplementing a subset of it. Its one dependency on base was a single call for an unguessable string, which crypto/rand says directly. Co-authored-by: Hanzo Dev <[email protected]>
51 lines
2.0 KiB
C
51 lines
2.0 KiB
C
// Package pyvm — C bridge declarations shared across pyvm cgo files.
|
|
// Implementation lives in pyvm_bridge.c so multiple .go files can call
|
|
// the same helpers without cgo dropping duplicate-symbol errors.
|
|
|
|
#ifndef PYVM_BRIDGE_H
|
|
#define PYVM_BRIDGE_H
|
|
|
|
#include <Python.h>
|
|
|
|
// pyvm_init initializes CPython (idempotent). Returns the saved main
|
|
// thread state, leaves the GIL released. Sets the global GIL-disabled
|
|
// flag retrievable via pyvm_gil_disabled.
|
|
PyThreadState* pyvm_init(void);
|
|
|
|
// pyvm_gil_disabled returns 1 if CPython was built with --disable-gil
|
|
// (free-threading PEP 703), 0 otherwise.
|
|
int pyvm_gil_disabled(void);
|
|
|
|
// pyvm_new_sub creates an OWN_GIL sub-interpreter (PEP 684). On
|
|
// success returns its thread state and leaves the caller thread
|
|
// without holding any GIL. On failure returns NULL and writes a heap-
|
|
// allocated error string to *err_out (caller frees).
|
|
PyThreadState* pyvm_new_sub(char **err_out);
|
|
|
|
// pyvm_end_sub destroys a sub-interpreter. Caller must NOT hold GIL.
|
|
// Safe to pass NULL.
|
|
void pyvm_end_sub(PyThreadState *ts);
|
|
|
|
// pyvm_enter / pyvm_leave swap the calling OS thread to/from the
|
|
// given sub-interpreter. Must be paired and called from the same OS
|
|
// thread.
|
|
void pyvm_enter(PyThreadState *ts);
|
|
void pyvm_leave(void);
|
|
|
|
// pyvm_load_source runs source as __main__ of the current
|
|
// sub-interpreter. Caller must hold the GIL. Returns 0 on success;
|
|
// on failure writes a heap-allocated error string to *err_out.
|
|
int pyvm_load_source(const char *src, char **err_out);
|
|
|
|
// pyvm_invoke calls __main__.fn(json.loads(payload_json)) and returns
|
|
// json.dumps(result) as a heap-allocated C string (caller frees).
|
|
// Caller must hold the GIL of the target sub-interpreter.
|
|
//
|
|
// On error returns NULL and writes the error to *err_out. If the
|
|
// failure is "function not found / not callable", *was_unknown is
|
|
// set to 1 — the Go layer maps that to ErrUnknownFn.
|
|
char* pyvm_invoke(const char *fn, const char *payload_json,
|
|
int *was_unknown, char **err_out);
|
|
|
|
#endif // PYVM_BRIDGE_H
|