diff --git a/capnp/__init__.py b/capnp/__init__.py index 0482b03..aba313f 100644 --- a/capnp/__init__.py +++ b/capnp/__init__.py @@ -52,7 +52,6 @@ from .lib.capnp import ( _StructModule, _write_message_to_fd, _write_packed_message_to_fd, - _Promise as Promise, _AsyncIoStream as AsyncIoStream, _init_capnp_api, ) diff --git a/capnp/helpers/asyncHelper.h b/capnp/helpers/asyncHelper.h deleted file mode 100644 index f939b3f..0000000 --- a/capnp/helpers/asyncHelper.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "kj/async.h" -#include "capabilityHelper.h" - -void waitNeverDone(kj::WaitScope & scope) { - kj::NEVER_DONE.wait(scope); -} - -capnp::Response< ::capnp::DynamicStruct> * waitRemote(kj::Own> promise, - kj::WaitScope & scope) { - return new capnp::Response< ::capnp::DynamicStruct>(promise->wait(scope)); -} diff --git a/capnp/helpers/capabilityHelper.cpp b/capnp/helpers/capabilityHelper.cpp index 0c69755..30cfd29 100644 --- a/capnp/helpers/capabilityHelper.cpp +++ b/capnp/helpers/capabilityHelper.cpp @@ -1,8 +1,8 @@ #include "capnp/helpers/capabilityHelper.h" #include "capnp/lib/capnp_api.h" -::kj::Promise> convert_to_pypromise(kj::Own> promise) { - return promise->then([](capnp::Response&& response) { +::kj::Promise> convert_to_pypromise(capnp::RemotePromise promise) { + return promise.then([](capnp::Response&& response) { return stealPyRef(wrap_dynamic_struct_reader(response)); } ); } @@ -72,49 +72,19 @@ kj::Promise> wrapPyFuncNoArg(kj::Own func) { return stealPyRef(result); } -kj::Promise> wrapRemoteCall(kj::Own func, capnp::Response & arg) { - GILAcquire gil; - PyObject * result = wrap_remote_call(func->obj, arg); - check_py_error(); - return stealPyRef(result); -} - -::kj::Promise> then(kj::Own>> promise, +::kj::Promise> then(kj::Promise> promise, kj::Own func, kj::Own error_func) { if(error_func->obj == Py_None) - return promise->then(kj::mvCapture(func, [](auto func, kj::Own arg) { + return promise.then(kj::mvCapture(func, [](auto func, kj::Own arg) { return wrapPyFunc(kj::mv(func), kj::mv(arg)); } )); else - return promise->then + return promise.then (kj::mvCapture(func, [](auto func, kj::Own arg) { return wrapPyFunc(kj::mv(func), kj::mv(arg)); }), kj::mvCapture(error_func, [](auto error_func, kj::Exception arg) { return wrapPyFunc(kj::mv(error_func), stealPyRef(wrap_kj_exception(arg))); } )); } -::kj::Promise> then(kj::Own<::capnp::RemotePromise<::capnp::DynamicStruct>> promise, - kj::Own func, kj::Own error_func) { - if(error_func->obj == Py_None) - return promise->then(kj::mvCapture(func, [](auto func, capnp::Response&& arg) { - return wrapRemoteCall(kj::mv(func), arg); } )); - else - return promise->then - (kj::mvCapture(func, [](auto func, capnp::Response&& arg) { - return wrapRemoteCall(kj::mv(func), arg); }), - kj::mvCapture(error_func, [](auto error_func, kj::Exception arg) { - return wrapPyFunc(kj::mv(error_func), stealPyRef(wrap_kj_exception(arg))); } )); -} - -::kj::Promise> then(kj::Own> promise, - kj::Own func, kj::Own error_func) { - if(error_func->obj == Py_None) - return promise->then(kj::mvCapture(func, [](auto func) { return wrapPyFuncNoArg(kj::mv(func)); } )); - else - return promise->then(kj::mvCapture(func, [](auto func) { return wrapPyFuncNoArg(kj::mv(func)); }), - kj::mvCapture(error_func, [](auto error_func, kj::Exception arg) { - return wrapPyFunc(kj::mv(error_func), stealPyRef(wrap_kj_exception(arg))); } )); -} - kj::Promise PythonInterfaceDynamicImpl::call(capnp::InterfaceSchema::Method method, capnp::CallContext< capnp::DynamicStruct, capnp::DynamicStruct> context) { auto methodName = method.getProto().getName(); diff --git a/capnp/helpers/capabilityHelper.h b/capnp/helpers/capabilityHelper.h index 8dee07c..7113baa 100644 --- a/capnp/helpers/capabilityHelper.h +++ b/capnp/helpers/capabilityHelper.h @@ -54,35 +54,21 @@ inline kj::Own stealPyRef(PyObject* o) { return ret; } -::kj::Promise> convert_to_pypromise(kj::Own> promise); +::kj::Promise> convert_to_pypromise(capnp::RemotePromise promise); -inline ::kj::Promise> convert_to_pypromise(kj::Own> promise) { - return promise->then([]() { +inline ::kj::Promise> convert_to_pypromise(kj::Promise 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::Promise> then(kj::Promise> 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); class PythonInterfaceDynamicImpl final: public capnp::DynamicCapability::Server { public: diff --git a/capnp/helpers/helpers.pxd b/capnp/helpers/helpers.pxd index 5682d12..64ddcd0 100644 --- a/capnp/helpers/helpers.pxd +++ b/capnp/helpers/helpers.pxd @@ -1,9 +1,7 @@ from capnp.includes.capnp_cpp cimport ( - Maybe, ReaderOptions, DynamicStruct, Request, Response, Promise, PyPromise, VoidPromise, PyPromiseArray, - RemotePromise, DynamicCapability, InterfaceSchema, EnumSchema, StructSchema, DynamicValue, - Capability, RpcSystem, MessageBuilder, MessageReader, TwoPartyVatNetwork, AnyPointer, - DynamicStruct_Builder, WaitScope, AsyncIoContext, StringPtr, TaskSet, Timer, - LowLevelAsyncIoProvider, AsyncIoProvider, Own, PyRefCounter + Maybe, PyPromise, VoidPromise, RemotePromise, + DynamicCapability, InterfaceSchema, EnumSchema, StructSchema, DynamicValue, Capability, + RpcSystem, MessageBuilder, Own, PyRefCounter ) from capnp.includes.schema_cpp cimport ByteArray @@ -12,37 +10,23 @@ from non_circular cimport reraise_kj_exception from cpython.ref cimport PyObject -from libcpp cimport bool - cdef extern from "capnp/helpers/fixMaybe.h": EnumSchema.Enumerant fixMaybe(Maybe[EnumSchema.Enumerant]) except +reraise_kj_exception StructSchema.Field fixMaybe(Maybe[StructSchema.Field]) except +reraise_kj_exception cdef extern from "capnp/helpers/capabilityHelper.h": - # PyPromise evalLater(EventLoop &, PyObject * func) - # PyPromise there(EventLoop & loop, PyPromise & promise, PyObject * func, PyObject * error_func) - PyPromise then(Own[PyPromise] promise, Own[PyRefCounter] func, Own[PyRefCounter] error_func) - PyPromise then(Own[RemotePromise] promise, Own[PyRefCounter] func, Own[PyRefCounter] error_func) - PyPromise then(Own[VoidPromise] promise, Own[PyRefCounter] func, Own[PyRefCounter] error_func) - PyPromise then(PyPromiseArray & promise) + PyPromise then(PyPromise promise, Own[PyRefCounter] func, Own[PyRefCounter] error_func) DynamicCapability.Client new_client(InterfaceSchema&, PyObject *) DynamicValue.Reader new_server(InterfaceSchema&, PyObject *) Capability.Client server_to_client(InterfaceSchema&, PyObject *) - PyPromise convert_to_pypromise(Own[RemotePromise]) - PyPromise convert_to_pypromise(Own[VoidPromise]) - VoidPromise convert_to_voidpromise(Own[PyPromise]) - PyPromise wrapSizePromise(Promise[size_t]) + PyPromise convert_to_pypromise(RemotePromise) + PyPromise convert_to_pypromise(VoidPromise) VoidPromise taskToPromise(Own[PyRefCounter] coroutine, PyObject* callback) void init_capnp_api() cdef extern from "capnp/helpers/rpcHelper.h": Capability.Client bootstrapHelper(RpcSystem&) Capability.Client bootstrapHelperServer(RpcSystem&) - PyPromise connectServer(TaskSet &, Capability.Client, AsyncIoProvider *, StringPtr, ReaderOptions &) cdef extern from "capnp/helpers/serialize.h": ByteArray messageToPackedBytes(MessageBuilder &, size_t wordCount) - -cdef extern from "capnp/helpers/asyncHelper.h": - void waitNeverDone(WaitScope&) except +reraise_kj_exception nogil - Response * waitRemote(Own[RemotePromise], WaitScope&) except +reraise_kj_exception nogil diff --git a/capnp/helpers/non_circular.pxd b/capnp/helpers/non_circular.pxd index a6246b3..a14e910 100644 --- a/capnp/helpers/non_circular.pxd +++ b/capnp/helpers/non_circular.pxd @@ -4,13 +4,7 @@ from libcpp cimport bool cdef extern from "capnp/helpers/capabilityHelper.h": cppclass PythonInterfaceDynamicImpl: PythonInterfaceDynamicImpl(PyObject *) - -cdef extern from "capnp/helpers/capabilityHelper.h": void reraise_kj_exception() cdef cppclass PyRefCounter: PyRefCounter(PyObject *) PyObject * obj - -cdef extern from "capnp/helpers/rpcHelper.h": - cdef cppclass ErrorHandler: - pass diff --git a/capnp/includes/capnp_cpp.pxd b/capnp/includes/capnp_cpp.pxd index 350a0a6..e3a822d 100644 --- a/capnp/includes/capnp_cpp.pxd +++ b/capnp/includes/capnp_cpp.pxd @@ -5,7 +5,7 @@ cdef extern from "capnp/helpers/checkCompiler.h": from libcpp cimport bool from capnp.helpers.non_circular cimport ( - PythonInterfaceDynamicImpl, reraise_kj_exception, PyRefCounter, ErrorHandler, + PythonInterfaceDynamicImpl, reraise_kj_exception, PyRefCounter, ) from capnp.includes.schema_cpp cimport ( Node, Data, StructNode, EnumNode, InterfaceNode, MessageBuilder, MessageReader, ReaderOptions, @@ -52,8 +52,6 @@ cdef extern from "kj/memory.h" namespace " ::kj": T& operator*() T* get() Own[T] heap[T](...) - Own[TwoPartyVatNetwork] makeTwoPartyVatNetwork" ::kj::heap< ::capnp::TwoPartyVatNetwork>"( - AsyncIoStream& stream, Side, ReaderOptions) cdef extern from "kj/async.h" namespace " ::kj": cdef cppclass Promise[T] nogil: @@ -108,72 +106,12 @@ cdef extern from "kj/array.h" namespace " ::kj": T& add(T&) Array[T] finish() - ArrayBuilder[PyPromise] heapArrayBuilderPyPromise"::kj::heapArrayBuilder< ::kj::Promise> >"(size_t) nogil - - ctypedef Array[Own[PyRefCounter]] PyArray' ::kj::Array>' - -ctypedef Promise[PyArray] PyPromiseArray - -cdef extern from "kj/time.h" namespace " ::kj": - cdef cppclass Duration nogil: - Duration operator*(int64_t) - Duration NANOSECONDS - Duration MICROSECONDS - Duration MILLISECONDS - Duration SECONDS - Duration MINUTES - Duration HOURS - Duration DAYS - cdef cppclass TimePoint: - TimePoint(Duration) - cdef cppclass MonotonicClock nogil: - MonotonicClock(MonotonicClock&) - TimePoint now() - MonotonicClock systemPreciseMonotonicClock() - -cdef extern from "kj/timer.h" namespace " ::kj": - cdef cppclass Timer nogil: - # int64_t now() - # VoidPromise atTime(TimePoint time) - VoidPromise afterDelay(Duration delay) - cdef cppclass TimerImpl(Timer) nogil: - TimerImpl(TimePoint startTime) - Maybe[TimePoint] nextEvent() - Maybe[uint64_t] timeoutToNextEvent(TimePoint start, Duration unit, uint64_t max) - void advanceTo(TimePoint newTime) - -cdef inline Duration Nanoseconds(int64_t nanos): - return NANOSECONDS * nanos cdef extern from "kj/async-io.h" namespace " ::kj": cdef cppclass AsyncIoStream nogil: Promise[size_t] read(void*, size_t, size_t) Promise[void] write(const void*, size_t) - cdef cppclass LowLevelAsyncIoProvider: - # Own[AsyncInputStream] wrapInputFd(int) - # Own[AsyncOutputStream] wrapOutputFd(int) - Own[AsyncIoStream] wrapSocketFd(int) - Timer& getTimer() except +reraise_kj_exception - - cdef cppclass AsyncIoProvider nogil: - TwoWayPipe newTwoWayPipe() - - cdef cppclass AsyncIoContext nogil: - AsyncIoContext(AsyncIoContext&) - Own[LowLevelAsyncIoProvider] lowLevelProvider - Own[AsyncIoProvider] provider - WaitScope waitScope - - cdef cppclass TaskSet nogil: - TaskSet(ErrorHandler &) - - cdef cppclass TwoWayPipe nogil: - Own[AsyncIoStream] ends[2] - - AsyncIoContext setupAsyncIo() nogil - Own[AsyncIoProvider] newAsyncIoProvider(LowLevelAsyncIoProvider& lowLevel); - cdef extern from "capnp/schema.capnp.h" namespace " ::capnp": enum TypeWhich" ::capnp::schema::Type::Which": TypeWhichVOID " ::capnp::schema::Type::Which::VOID" @@ -551,7 +489,6 @@ cdef extern from "kj/async.h" namespace " ::kj": cdef cppclass VoidPromiseFulfiller"::kj::PromiseFulfiller" nogil: void fulfill() void reject(Exception&& exception) - PyPromiseArray joinPromises(Array[PyPromise]) nogil cdef extern from "capnp/helpers/capabilityHelper.h": cdef cppclass PyAsyncIoStream(AsyncIoStream): diff --git a/capnp/lib/capnp.pxd b/capnp/lib/capnp.pxd index 3350f14..d131a66 100644 --- a/capnp/lib/capnp.pxd +++ b/capnp/lib/capnp.pxd @@ -10,8 +10,8 @@ from capnp.includes.capnp_cpp cimport ( String, StringTree, DynamicOrphan as C_DynamicOrphan, AnyPointer as C_DynamicObject, DynamicCapability as C_DynamicCapability, Request, Response, RemotePromise, Promise, CallContext, RpcSystem, makeRpcServerBootstrap, makeRpcClient, Capability as C_Capability, - TwoPartyVatNetwork as C_TwoPartyVatNetwork, Side, AsyncIoStream, Own, makeTwoPartyVatNetwork, - PyArray, DynamicStruct_Builder, TwoWayPipe, PyRefCounter, PyAsyncIoStream + TwoPartyVatNetwork as C_TwoPartyVatNetwork, Side, AsyncIoStream, Own, + DynamicStruct_Builder, PyRefCounter, PyAsyncIoStream ) from capnp.includes.schema_cpp cimport Node as C_Node, EnumNode as C_EnumNode from capnp.includes.types cimport * diff --git a/capnp/lib/capnp.pyx b/capnp/lib/capnp.pyx index f6efc0b..e47113f 100644 --- a/capnp/lib/capnp.pyx +++ b/capnp/lib/capnp.pyx @@ -10,7 +10,7 @@ cimport cython # noqa: E402 from capnp.helpers.helpers cimport init_capnp_api -from capnp.includes.capnp_cpp cimport AsyncIoStream, WaitScope, PyPromise, VoidPromise, EventPort, EventLoop, WaitScope, LowLevelAsyncIoProvider, AsyncIoProvider, newAsyncIoProvider, Canceler, PyAsyncIoStream, PromiseFulfiller, VoidPromiseFulfiller, tryReadMessage, writeMessage, makeException +from capnp.includes.capnp_cpp cimport AsyncIoStream, WaitScope, PyPromise, VoidPromise, EventPort, EventLoop, Canceler, PyAsyncIoStream, PromiseFulfiller, VoidPromiseFulfiller, tryReadMessage, writeMessage, makeException from capnp.includes.schema_cpp cimport (MessageReader,) from cpython cimport array, Py_buffer, PyObject_CheckBuffer, memoryview, buffer @@ -60,12 +60,7 @@ def deregister_all_types(): # By making it public, we'll be able to call it from capabilityHelper.h cdef api object wrap_dynamic_struct_reader(Response & r) with gil: - return _Response()._init_childptr(new Response(moveResponse(r)), None) - - -cdef api object wrap_remote_call(object func, Response & r): - response = _Response()._init_childptr(new Response(moveResponse(r)), None) - return func(response) + return _Response()._init_childptr(new Response(move(r)), None) cdef _find_field_order(struct_node): return [f.name for f in sorted(struct_node.fields, key=_attrgetter('codeOrder'))] @@ -185,7 +180,7 @@ cdef class _KjExceptionWrapper: cdef capnp.Exception * thisptr cdef _init(self, capnp.Exception & other): - self.thisptr = new capnp.Exception(moveException(other)) + self.thisptr = new capnp.Exception(move(other)) return self def __dealloc__(self): @@ -306,12 +301,6 @@ ctypedef fused _DynamicSetterClasses: DynamicStruct_Builder -ctypedef fused PromiseTypes: - _Promise - _RemotePromise - _VoidPromise - - cdef extern from "Python.h": cdef int PyObject_GetBuffer(object, Py_buffer *view, int flags) cdef void PyBuffer_Release(Py_buffer *view) @@ -327,20 +316,6 @@ cdef extern from "capnp/list.h" namespace " ::capnp": uint size() -cdef extern from "" namespace "std": - C_DynamicStruct.Pipeline moveStructPipeline"std::move"(C_DynamicStruct.Pipeline) - C_DynamicOrphan moveOrphan"std::move"(C_DynamicOrphan) - Request moveRequest"std::move"(Request) - Response moveResponse"std::move"(Response) - PyPromise movePromise"std::move"(PyPromise) - VoidPromise moveVoidPromise"std::move"(VoidPromise) - RemotePromise moveRemotePromise"std::move"(RemotePromise) - CallContext moveCallContext"std::move"(CallContext) - Own[AsyncIoStream] moveOwnAsyncIOStream"std::move"(Own[AsyncIoStream]) - capnp.Exception moveException"std::move"(capnp.Exception) - capnp.AsyncIoContext moveAsyncContext"std::move"(capnp.AsyncIoContext) - - cdef extern from "" namespace " ::capnp": StringTree printStructReader" ::capnp::prettyPrint"(C_DynamicStruct.Reader) except +reraise_kj_exception StringTree printStructBuilder" ::capnp::prettyPrint"(DynamicStruct_Builder) except +reraise_kj_exception @@ -1289,7 +1264,8 @@ cdef class _DynamicStructBuilder: :Raises: :exc:`KjException` if this isn't the message's root struct. """ self._check_write() - await _VoidPromise()._init(writeMessage(deref(stream.thisptr.get()), deref((<_MessageBuilder>self._parent).thisptr))) + await _voidpromise_to_asyncio( + writeMessage(deref(stream.thisptr.get()), deref((<_MessageBuilder>self._parent).thisptr))) self._is_written = True def write_packed(self, file): @@ -1657,12 +1633,12 @@ cdef class _DynamicStructPipeline: cdef class _DynamicOrphan: cdef _init(self, C_DynamicOrphan other, object parent): - self.thisptr = moveOrphan(other) + self.thisptr = move(other) self._parent = parent return self cdef C_DynamicOrphan move(self): - return moveOrphan(self.thisptr) + return move(self.thisptr) cpdef get(self): """Returns a python object corresponding to the DynamicValue owned by this orphan @@ -1831,11 +1807,8 @@ def _asyncio_close_patch(loop, oldclose, _EventLoop kjloop): cdef class _EventLoop: cdef object __weakref__ # Needed to make this class weak-referenceable - cdef Own[LowLevelAsyncIoProvider] lowLevelProvider - cdef Own[AsyncIoProvider] provider - cdef WaitScope * waitScope - - cdef AsyncIoEventPort *customPort + cdef WaitScope* waitScope + cdef AsyncIoEventPort* customPort def __init__(self): self._init() @@ -1848,10 +1821,8 @@ cdef class _EventLoop: loop.close = _partial(_asyncio_close_patch, loop, loop.close, self) def __dealloc__(self): - if not self.customPort == NULL: - # If we have a custom port, the waitscope is not owned by provider, we have to delete it manually - del self.waitScope - del self.customPort + del self.waitScope + del self.customPort _C_DEFAULT_EVENT_LOOP_LOCAL = _threading.local() @@ -1882,7 +1853,7 @@ cdef class _CallContext: cdef CallContext * thisptr cdef _init(self, CallContext other): - self.thisptr = new CallContext(moveCallContext(other)) + self.thisptr = new CallContext(move(other)) return self def __dealloc__(self): @@ -1906,121 +1877,52 @@ cdef class _CallContext: self.thisptr.allowCancellation() cpdef tail_call(self, _Request tailRequest): - promise = _VoidPromise()._init(self.thisptr.tailCall(moveRequest(deref(tailRequest.thisptr_child)))) - return promise + return _voidpromise_to_asyncio(self.thisptr.tailCall(move(deref(tailRequest.thisptr_child)))) -cdef void _promise_check_consumed(PromiseTypes promise) except*: - if promise.thisptr.get() == NULL: - raise KjException( - "Promise was already used in a consuming operation. You can no longer use this Promise object") - -cdef _promise_then(PromiseTypes self, func, error_func, num_args, attach=None) except +reraise_kj_exception: - _promise_check_consumed(self) - - argspec = None - try: - argspec = _inspect.getfullargspec(func) - except (TypeError, ValueError): - pass - if argspec: - args_length = len(argspec.args) if argspec.args else 0 - defaults_length = len(argspec.defaults) if argspec.defaults else 0 - if args_length - defaults_length != num_args: - raise KjException(f'Function passed to `then` call must take exactly {num_args} arguments') - - return _Promise()._init( - helpers.then(move(self.thisptr), capnp.heap[PyRefCounter](func), - capnp.heap[PyRefCounter](error_func)) - .attach(capnp.heap[PyRefCounter]( attach))) - -cdef _promise_to_asyncio(PromiseTypes promise): - _promise_check_consumed(promise) +cdef _promise_to_asyncio(PyPromise promise): fut = asyncio.get_running_loop().create_future() + def success(res): return fut.set_result(res) if not fut.cancelled() else None + def exception(err): return fut.set_exception(err) if not fut.cancelled() else None + def done(fut): return fut.kjpromise.cancel() if fut.cancelled() else None # Attach the promise to the future, so that it doesn't get destroyed - fut.kjpromise = _promise_then( - promise, - lambda res: fut.set_result(res) if not fut.cancelled() else None, - lambda err: fut.set_exception(err) if not fut.cancelled() else None, - 1) - del promise - fut.add_done_callback( - lambda fut: fut.kjpromise.cancel() if fut.cancelled() else None) + fut.kjpromise = _Promise()._init(helpers.then( + move(promise), + capnp.heap[PyRefCounter](success), + capnp.heap[PyRefCounter](exception))) + fut.add_done_callback(done) return fut +cdef _voidpromise_to_asyncio(VoidPromise promise): + return _promise_to_asyncio(helpers.convert_to_pypromise(move(promise))) + cdef class _Promise: cdef Own[PyPromise] thisptr - def __init__(self, obj=None): - C_DEFAULT_EVENT_LOOP_GETTER() - if obj is not None: - self.thisptr = capnp.heap[PyPromise](capnp.heap[PyRefCounter](obj)) - cdef _init(self, PyPromise other): - self.thisptr = capnp.heap[PyPromise](movePromise(other)) + self.thisptr = capnp.heap[PyPromise](move(other)) return self - async def a_wait(self): - """ - Asyncio version of wait(). - Required when using asyncio for socket communication. - - Will still work with non-asyncio socket communication, but requires async handling of the function call. - """ - return await _promise_to_asyncio(self) - - def __await__(self): - return _promise_to_asyncio(self).__await__() - cpdef cancel(self) except +reraise_kj_exception: self.thisptr = Own[PyPromise]() -cdef class _VoidPromise: - cdef Own[VoidPromise] thisptr - - - cdef _init(self, VoidPromise other): - C_DEFAULT_EVENT_LOOP_GETTER() - self.thisptr = capnp.heap[VoidPromise](moveVoidPromise(other)) - return self - - async def a_wait(self): - """ - Asyncio version of wait(). - Required when using asyncio for socket communication. - - Will still work with non-asyncio socket communication, but requires async handling of the function call. - """ - # TODO: Is keeping a separate _VoidPromise class really worth it? Does it make things faster? - return await _promise_to_asyncio[_Promise](self.as_pypromise()) - - def __await__(self): - return _promise_to_asyncio[_Promise](self.as_pypromise()).__await__() - - cpdef as_pypromise(self) except +reraise_kj_exception: - _promise_check_consumed(self) - return _Promise()._init(helpers.convert_to_pypromise(move(self.thisptr))) - - cpdef cancel(self) except +reraise_kj_exception: - self.thisptr = Own[VoidPromise]() - - - cdef class _RemotePromise: cdef object _parent - """A pointer to a parent object that needs to be kept alive for this promise to function. - Note that _Promise and _VoidPromise don't have such pointer. The reason is that in _RemotePromise - the parent pointer needs to be passed around through _RemotePromise._get. If an object needs to - be kept alive in _Promise or _VoidPromise, it can be attached to the underlying C++ promise.""" + """A pointer to a parent object that needs to be kept alive for this promise to function.""" cdef Own[RemotePromise] thisptr cdef _init(self, RemotePromise other, object parent=None): - self.thisptr = capnp.heap[RemotePromise](moveRemotePromise(other)) + self.thisptr = capnp.heap[RemotePromise](move(other)) self._parent = parent return self + cdef void _check_consumed(self) except*: + if self.thisptr.get() == NULL: + raise KjException( + "Promise was already used in a consuming operation. You can no longer use this Promise object") + async def a_wait(self): """ Asyncio version of wait(). @@ -2028,20 +1930,17 @@ cdef class _RemotePromise: Will still work with non-asyncio socket communication, but requires async handling of the function call. """ - return await _promise_to_asyncio(self) + self._check_consumed() + cdef Own[RemotePromise] thisptr = move(self.thisptr) + return await _promise_to_asyncio(helpers.convert_to_pypromise(move(deref(thisptr)))) def __await__(self): - return _promise_to_asyncio(self).__await__() - - cpdef as_pypromise(self) except +reraise_kj_exception: - _promise_check_consumed(self) - parent = self._parent - self._parent = None # We don't need parent anymore. Setting to none allows quicker garbage collection - return _Promise()._init(helpers.convert_to_pypromise(move(self.thisptr)) - .attach(capnp.heap[PyRefCounter](parent))) + self._check_consumed() + cdef Own[RemotePromise] thisptr = move(self.thisptr) + return _promise_to_asyncio(helpers.convert_to_pypromise(move(deref(thisptr)))).__await__() cpdef _get(self, field) except +reraise_kj_exception: - _promise_check_consumed(self) + self._check_consumed() cdef int type = (self.thisptr.get().get(field)).getType() if type == capnp.TYPE_CAPABILITY: return _DynamicCapabilityClient()._init( @@ -2064,7 +1963,7 @@ cdef class _RemotePromise: property schema: """A property that returns the _StructSchema object matching this reader""" def __get__(self): - _promise_check_consumed(self) + self._check_consumed() return _StructSchema()._init_child(self.thisptr.get().getSchema()) def __dir__(self): @@ -2083,7 +1982,7 @@ cdef class _Request(_DynamicStructBuilder): cdef public bint is_consumed cdef _init_child(self, Request other, parent): - self.thisptr_child = new Request(moveRequest(other)) + self.thisptr_child = new Request(move(other)) self._init(deref(self.thisptr_child), parent) self.is_consumed = False return self @@ -2102,7 +2001,7 @@ cdef class _Response(_DynamicStructReader): cdef Response * thisptr_child cdef _init_child(self, Response other, parent): - self.thisptr_child = new Response(moveResponse(other)) + self.thisptr_child = new Response(move(other)) self._init(deref(self.thisptr_child), parent) return self @@ -2276,11 +2175,11 @@ cdef class _TwoPartyVatNetwork: cdef _init(self, _AsyncIoStream stream, Side side, schema_cpp.ReaderOptions opts): self.stream = stream - self.thisptr = makeTwoPartyVatNetwork(deref(stream.thisptr), side, opts) + self.thisptr = capnp.heap[C_TwoPartyVatNetwork](deref(stream.thisptr), side, opts) return self cpdef on_disconnect(self) except +reraise_kj_exception: - return _VoidPromise()._init(deref(self.thisptr).onDisconnect()) + return _voidpromise_to_asyncio(deref(self.thisptr).onDisconnect()) cdef class TwoPartyClient: @@ -2291,7 +2190,7 @@ cdef class TwoPartyClient: :param traversal_limit_in_words: Pointer derefence limit (see https://capnproto.org/cxx.html). :param nesting_limit: Recursive limit when reading types (see https://capnproto.org/cxx.html). """ - cdef RpcSystem * thisptr + cdef Own[RpcSystem] thisptr cdef _TwoPartyVatNetwork _network def __init__(self, socket=None, traversal_limit_in_words=None, nesting_limit=None): @@ -2303,17 +2202,13 @@ cdef class TwoPartyClient: else: raise ValueError(f"Argument socket should be a AsyncIoStream, was {type(socket)}") - self.thisptr = new RpcSystem(makeRpcClient(deref(self._network.thisptr))) - - def __dealloc__(self): - if not self.thisptr == NULL: - del self.thisptr + self.thisptr = capnp.heap[RpcSystem](makeRpcClient(deref(self._network.thisptr))) cpdef bootstrap(self) except +reraise_kj_exception: return _CapabilityClient()._init(helpers.bootstrapHelper(deref(self.thisptr)), self) cpdef on_disconnect(self) except +reraise_kj_exception: - return _VoidPromise()._init(deref(self._network.thisptr).onDisconnect()) + return self._network.on_disconnect() cdef class TwoPartyServer: @@ -2325,7 +2220,7 @@ cdef class TwoPartyServer: :param traversal_limit_in_words: Pointer derefence limit (see https://capnproto.org/cxx.html). :param nesting_limit: Recursive limit when reading types (see https://capnproto.org/cxx.html). """ - cdef RpcSystem * thisptr + cdef Own[RpcSystem] thisptr cdef _TwoPartyVatNetwork _network def __init__(self, socket=None, bootstrap=None, traversal_limit_in_words=None, nesting_limit=None): @@ -2339,18 +2234,15 @@ cdef class TwoPartyServer: raise ValueError(f"Argument socket should be a AsyncIoStream, was {type(socket)}") cdef _InterfaceSchema schema = bootstrap.schema - self.thisptr = new RpcSystem(makeRpcServerBootstrap( + self.thisptr = capnp.heap[RpcSystem](makeRpcServerBootstrap( deref(self._network.thisptr), helpers.server_to_client(schema.thisptr, bootstrap))) - def __dealloc__(self): - del self.thisptr - - cpdef on_disconnect(self) except +reraise_kj_exception: - return _VoidPromise()._init(deref(self._network.thisptr).onDisconnect()) - cpdef bootstrap(self) except +reraise_kj_exception: return _CapabilityClient()._init(helpers.bootstrapHelperServer(deref(self.thisptr)), self) + cpdef on_disconnect(self) except +reraise_kj_exception: + return self._network.on_disconnect() + cdef class _AsyncIoStream: cdef Own[AsyncIoStream] thisptr @@ -3119,7 +3011,7 @@ class _StructModule(object): :rtype: :class:`_DynamicStructReader`""" cdef schema_cpp.ReaderOptions opts = make_reader_opts(traversal_limit_in_words, nesting_limit) - reader = await _Promise()._init(tryReadMessage(deref(stream.thisptr.get()), opts)) + reader = await _promise_to_asyncio(tryReadMessage(deref(stream.thisptr.get()), opts)) if reader is None: return return reader.get_root(self.schema)