#pragma once #include "capnp/dynamic.h" #include #include #include "Python.h" class GILAcquire { public: GILAcquire() : gstate(PyGILState_Ensure()) {} ~GILAcquire() { PyGILState_Release(gstate); } PyGILState_STATE gstate; }; class GILRelease { public: GILRelease() { Py_UNBLOCK_THREADS } ~GILRelease() { Py_BLOCK_THREADS } PyThreadState *_save; // The macros above read/write from this variable }; class PyRefCounter { public: PyObject * obj; PyRefCounter(PyObject * o) : obj(o) { GILAcquire gil; Py_INCREF(obj); } PyRefCounter(const PyRefCounter & ref) : obj(ref.obj) { GILAcquire gil; Py_INCREF(obj); } ~PyRefCounter() { GILAcquire gil; Py_DECREF(obj); } }; inline kj::Own stealPyRef(PyObject* o) { auto ret = kj::heap(o); Py_DECREF(o); return ret; } ::kj::Promise> convert_to_pypromise(kj::Own> promise); inline ::kj::Promise> convert_to_pypromise(kj::Own> promise) { return promise->then([]() { GILAcquire gil; return kj::heap(Py_None); }); } template ::kj::Promise convert_to_voidpromise(kj::Own> promise) { return promise->then([](T) { } ); } void reraise_kj_exception(); void check_py_error(); inline kj::Promise> wrapSizePromise(kj::Promise promise) { return promise.then([](size_t response) { return stealPyRef(PyLong_FromSize_t(response)); } ); } ::kj::Promise> then(kj::Own>> promise, kj::Own func, kj::Own error_func); ::kj::Promise> then(kj::Own<::capnp::RemotePromise< ::capnp::DynamicStruct>> promise, kj::Own func, kj::Own error_func); ::kj::Promise> then(kj::Own> promise, kj::Ownfunc, kj::Own error_func); ::kj::Promise> then(kj::Promise> > && promise); class PythonInterfaceDynamicImpl final: public capnp::DynamicCapability::Server { public: PyObject * py_server; PythonInterfaceDynamicImpl(capnp::InterfaceSchema & schema, PyObject * _py_server) : capnp::DynamicCapability::Server(schema), py_server(_py_server) { GILAcquire gil; Py_INCREF(_py_server); } ~PythonInterfaceDynamicImpl() { GILAcquire gil; Py_DECREF(py_server); } kj::Promise call(capnp::InterfaceSchema::Method method, capnp::CallContext< capnp::DynamicStruct, capnp::DynamicStruct> context); }; inline capnp::DynamicCapability::Client new_client(capnp::InterfaceSchema & schema, PyObject * server) { return capnp::DynamicCapability::Client(kj::heap(schema, server)); } inline capnp::DynamicValue::Reader new_server(capnp::InterfaceSchema & schema, PyObject * server) { return capnp::DynamicValue::Reader(kj::heap(schema, server)); } inline capnp::Capability::Client server_to_client(capnp::InterfaceSchema & schema, PyObject * server) { return kj::heap(schema, server); } class PyAsyncIoStream: public kj::AsyncIoStream { public: kj::Own protocol; PyAsyncIoStream(kj::Own protocol) : protocol(kj::mv(protocol)) {} ~PyAsyncIoStream(); kj::Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes); kj::Promise write(const void* buffer, size_t size); kj::Promise write(kj::ArrayPtr> pieces); kj::Promise whenWriteDisconnected(); void shutdownWrite(); }; template inline void rejectDisconnected(kj::PromiseFulfiller& fulfiller, kj::StringPtr message) { fulfiller.reject(KJ_EXCEPTION(DISCONNECTED, message)); } inline void rejectVoidDisconnected(kj::PromiseFulfiller& fulfiller, kj::StringPtr message) { fulfiller.reject(KJ_EXCEPTION(DISCONNECTED, message)); } void init_capnp_api();