diff --git a/capnp/async.h b/capnp/async.h new file mode 100644 index 0000000..9b28e5a --- /dev/null +++ b/capnp/async.h @@ -0,0 +1,25 @@ +#ifndef __PYX_HAVE__capnp__async +#define __PYX_HAVE__capnp__async + + +#ifndef __PYX_HAVE_API__capnp__async + +#ifndef __PYX_EXTERN_C + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +__PYX_EXTERN_C DL_IMPORT(PyObject) *wrap_kj_exception( ::kj::Exception &); + +#endif /* !__PYX_HAVE_API__capnp__async */ + +#if PY_MAJOR_VERSION < 3 +PyMODINIT_FUNC initasync(void); +#else +PyMODINIT_FUNC PyInit_async(void); +#endif + +#endif /* !__PYX_HAVE__capnp__async */ diff --git a/capnp/async.pyx b/capnp/async.pyx new file mode 100644 index 0000000..5c1b980 --- /dev/null +++ b/capnp/async.pyx @@ -0,0 +1,54 @@ +# capnp.pyx +# distutils: language = c++ +# distutils: extra_compile_args = --std=c++11 -fpermissive +# distutils: libraries = kj +# cython: c_string_type = str +# cython: c_string_encoding = default +# cython: embedsignature = True + +cimport cython +cimport async_cpp as async +from cpython.ref cimport PyObject, Py_INCREF, Py_DECREF +from cython.operator cimport dereference as deref + +cdef extern from "" namespace "std": + async.PyPromise movePromise"std::move"(async.PyPromise) + +# This is a really weird function. By making it public, we'll be able to call it from asyncHelper.h +cdef public object wrap_kj_exception(async.Exception & exception): + return None # TODO + +cdef class EventLoop: + cdef async.SimpleEventLoop thisptr + + cpdef evalLater(self, func): + Py_INCREF(func) + return Promise()._init(async.evalLater(self.thisptr, func)) + + cdef wait(self, async.PyPromise * promise): + return self.thisptr.wait(movePromise(deref(promise))) + + cdef there(self, async.PyPromise * promise, object func, object error_func): + Py_INCREF(func) + Py_INCREF(error_func) + return Promise()._init(async.there(self.thisptr, deref(promise), func, error_func)) + + +cdef EventLoop c_event_loop = EventLoop() +event_loop = c_event_loop + +cdef class Promise: + cdef async.PyPromise * thisptr + cdef _init(self, async.PyPromise other): + self.thisptr = new async.PyPromise(movePromise(other)) + return self + + def __dealloc__(self): + del self.thisptr + + def wait(self): + return c_event_loop.wait(self.thisptr) + + def then(self, func, error_func=None): + return c_event_loop.there(self.thisptr, func, error_func) + diff --git a/capnp/asyncHelper.h b/capnp/asyncHelper.h new file mode 100644 index 0000000..62d44c9 --- /dev/null +++ b/capnp/asyncHelper.h @@ -0,0 +1,25 @@ +#include "kj/async.h" +#include "Python.h" +#include +extern "C" { + PyObject * wrap_kj_exception(kj::Exception &); +} + +PyObject * wrapPyFunc(PyObject * func, PyObject * arg) { + PyObject * result = PyObject_CallFunctionObjArgs(func, arg, NULL); + Py_DECREF(func); + Py_DECREF(arg); + return result; +} + +::kj::Promise evalLater(kj::EventLoop & loop, PyObject * func) { + return loop.evalLater([func]() { return wrapPyFunc(func, NULL); } ); +} + +::kj::Promise there(kj::EventLoop & loop, kj::Promise & promise, PyObject * func, PyObject * error_func) { + if(error_func == Py_None) + return loop.there(kj::mv(promise), [func](PyObject * arg) { return wrapPyFunc(func, arg); } ); + else + return loop.there(kj::mv(promise), [func](PyObject * arg) { return wrapPyFunc(func, arg); } + , [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } ); +} \ No newline at end of file diff --git a/capnp/async_cpp.pxd b/capnp/async_cpp.pxd new file mode 100644 index 0000000..4e87530 --- /dev/null +++ b/capnp/async_cpp.pxd @@ -0,0 +1,31 @@ +# schema.capnp.cpp.pyx +# distutils: language = c++ +# distutils: extra_compile_args = --std=c++11 + +from cpython.ref cimport PyObject + +cdef extern from "kj/exception.h" namespace " ::kj": + cdef cppclass Exception: + pass + +cdef extern from "kj/async.h" namespace " ::kj": + cdef cppclass Promise[T]: + Promise(Promise) + T wait() + +ctypedef Promise[PyObject *] PyPromise + +cdef extern from "kj/async.h" namespace " ::kj": + cdef cppclass EventLoop: + EventLoop() + # Promise[void] yieldFrom'yield'() + object wait(PyPromise) + object there(PyPromise) + PyPromise evalLater(PyObject * func) + PyPromise there(PyPromise, PyObject * func) + cdef cppclass SimpleEventLoop(EventLoop): + pass + +cdef extern from "asyncHelper.h": + PyPromise evalLater(EventLoop &, PyObject * func) + PyPromise there(EventLoop & loop, PyPromise & promise, PyObject * func, PyObject * error_func) \ No newline at end of file