diff --git a/capnp.pyx b/capnp.pyx index 2acf398..205f10d 100644 --- a/capnp.pyx +++ b/capnp.pyx @@ -3,9 +3,10 @@ # distutils: extra_compile_args = --std=c++11 # distutils: libraries = capnp +cimport cython cimport capnp_cpp as capnp cimport schema_cpp -from capnp_cpp cimport SchemaLoader as C_SchemaLoader, Schema as C_Schema, StructSchema as C_StructSchema, DynamicStruct as C_DynamicStruct, DynamicValue as C_DynamicValue +from capnp_cpp cimport SchemaLoader as C_SchemaLoader, Schema as C_Schema, StructSchema as C_StructSchema, DynamicStruct as C_DynamicStruct, DynamicValue as C_DynamicValue, Type as C_Type, DynamicList as C_DynamicList, DynamicUnion as C_DynamicUnion, fixMaybe from schema_cpp cimport CodeGeneratorRequest as C_CodeGeneratorRequest, Node as C_Node from cython.operator cimport dereference as deref @@ -25,6 +26,35 @@ ctypedef bint Bool ctypedef float Float32 ctypedef double Float64 +ctypedef fused valid_values: + int + long + float + double + bint + +def _make_enum(enum_name, *sequential, **named): + enums = dict(zip(sequential, range(len(sequential))), **named) + reverse = dict((value, key) for key, value in enums.iteritems()) + enums['reverse_mapping'] = reverse + return type(enum_name, (), enums) + +_Type = _make_enum('DynamicValue.Type', + UNKNOWN = capnp.TYPE_UNKNOWN, + VOID = capnp.TYPE_VOID, + BOOL = capnp.TYPE_BOOL, + INT = capnp.TYPE_INT, + UINT = capnp.TYPE_UINT, + FLOAT = capnp.TYPE_FLOAT, + TEXT = capnp.TYPE_TEXT, + DATA = capnp.TYPE_DATA, + LIST = capnp.TYPE_LIST, + ENUM = capnp.TYPE_ENUM, + STRUCT = capnp.TYPE_STRUCT, + UNION = capnp.TYPE_UNION, + INTERFACE = capnp.TYPE_INTERFACE, + OBJECT = capnp.TYPE_OBJECT) + cdef extern from "capnp/list.h" namespace "::capnp": cdef cppclass List[T]: cppclass Reader: @@ -34,6 +64,57 @@ cdef extern from "capnp/list.h" namespace "::capnp": T operator[](uint) except +ValueError uint size() +cdef class _DynamicListReader: + cdef C_DynamicList.Reader thisptr + cdef init(self, C_DynamicList.Reader other): + self.thisptr = other + return self + + cpdef _get(self, index): + size = self.thisptr.size() + if index >= size: + raise IndexError('Out of bounds') + index = index % size + return _DynamicValueReader().init(self.thisptr[index]) + + def __getitem__(self, index): + return self._get(index).toPython() + + def __len__(self): + return self.thisptr.size() + +cdef class _DynamicListBuilder: + cdef C_DynamicList.Builder thisptr + cdef init(self, C_DynamicList.Builder other): + self.thisptr = other + return self + + #def init(self, size): + # self.thisptr.init(size) + # return self + + def __getitem__(self, index): + size = self.thisptr.size() + if index >= size: + raise IndexError('Out of bounds') + index = index % size + temp = self.thisptr[index] + return toPython(temp) + + def _setitem(self, index, valid_values value): + cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(value) + self.thisptr.set(index, temp) + + def __setitem__(self, index, value): + size = self.thisptr.size() + if index >= size: + raise IndexError('Out of bounds') + index = index % size + self._setitem(index, value) + + def __len__(self): + return self.thisptr.size() + cdef class _List_UInt64_Reader: cdef List[UInt64].Reader thisptr cdef init(self, List[UInt64].Reader other): @@ -69,7 +150,73 @@ cdef class _DynamicValueReader: cdef init(self, C_DynamicValue.Reader other): self.thisptr = other return self - + + cpdef int getType(self): + return self.thisptr.getType() + + cpdef toPython(self): + cdef int type = self.getType() + if type == capnp.TYPE_BOOL: + return self.thisptr.asBool() + elif type == capnp.TYPE_INT: + return self.thisptr.asInt() + elif type == capnp.TYPE_UINT: + return self.thisptr.asUint() + elif type == capnp.TYPE_FLOAT: + return self.thisptr.asDouble() + elif type == capnp.TYPE_TEXT: + return self.thisptr.asText()[:] + elif type == capnp.TYPE_DATA: + temp = self.thisptr.asData() + return (temp.begin())[:temp.size()] + elif type == capnp.TYPE_LIST: + return list(_DynamicListReader().init(self.thisptr.asList())) + elif type == capnp.TYPE_STRUCT: + return _DynamicStructReader().init(self.thisptr.asStruct()) + elif type == capnp.TYPE_UNION: + return _DynamicUnionReader().init(self.thisptr.asUnion()) + elif type == capnp.TYPE_ENUM: + return self.thisptr.asEnum().getRaw() + elif type == capnp.TYPE_VOID: + return None + elif type == capnp.TYPE_UNKOWN: + raise ValueError("Cannot convert type to Python. Type is unknown by capnproto library") + else: + raise ValueError("Cannot convert type to Python. Type is unhandled by capnproto library") + + +cdef int getType(C_DynamicValue.Builder & self): + return self.getType() + +cdef toPython(C_DynamicValue.Builder & self): + cdef int type = getType(self) + if type == capnp.TYPE_BOOL: + return self.asBool() + elif type == capnp.TYPE_INT: + return self.asInt() + elif type == capnp.TYPE_UINT: + return self.asUint() + elif type == capnp.TYPE_FLOAT: + return self.asDouble() + elif type == capnp.TYPE_TEXT: + return self.asText()[:] + elif type == capnp.TYPE_DATA: + temp = self.asData() + return (temp.begin())[:temp.size()] + elif type == capnp.TYPE_LIST: + return list(_DynamicListBuilder().init(self.asList())) + elif type == capnp.TYPE_STRUCT: + return _DynamicStructBuilder().init(self.asStruct()) + elif type == capnp.TYPE_UNION: + return _DynamicUnionBuilder().init(self.asUnion()) + elif type == capnp.TYPE_ENUM: + return self.asEnum().getRaw() + elif type == capnp.TYPE_VOID: + return None + elif type == capnp.TYPE_UNKOWN: + raise ValueError("Cannot convert type to Python. Type is unknown by capnproto library") + else: + raise ValueError("Cannot convert type to Python. Type is unhandled by capnproto library") cdef class _DynamicStructReader: cdef C_DynamicStruct.Reader thisptr @@ -77,12 +224,68 @@ cdef class _DynamicStructReader: self.thisptr = other return self - def get(self, field): + cpdef _get(self, field): return _DynamicValueReader().init(self.thisptr.get(field)) - def has(self, field): + def __getattr__(self, field): + return self._get(field).toPython() + + def _has(self, field): return self.thisptr.has(field) +cdef class _DynamicStructBuilder: + cdef C_DynamicStruct.Builder thisptr + cdef init(self, C_DynamicStruct.Builder other): + self.thisptr = other + return self + + def __getattr__(self, field): + return toPython(self.thisptr.get(field)) + + def _setattr(self, field, valid_values value): + cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(value) + self.thisptr.set(field, temp) + + def __setattr__(self, field, value): + self._setattr(field, value) + + def _has(self, field): + return self.thisptr.has(field) + +cdef class _DynamicUnionReader: + cdef C_DynamicUnion.Reader thisptr + cdef init(self, C_DynamicUnion.Reader other): + self.thisptr = other + return self + + cpdef _get(self): + return _DynamicValueReader().init(self.thisptr.get()).toPython() + + def __getattr__(self, field): + return self._get().toPython() + + cpdef which(self): + return fixMaybe(self.thisptr.which()).getProto().getOrdinal() + +cdef class _DynamicUnionBuilder: + cdef C_DynamicUnion.Builder thisptr + cdef init(self, C_DynamicUnion.Builder other): + self.thisptr = other + return self + + def __getattr__(self, field): + return toPython(self.thisptr.get()) + + def _setattr(self, field, valid_values value): + cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(value) + self.thisptr.set(field, temp) + + def __setattr__(self, field, value): + self._setattr(field, value) + + cpdef which(self): + return fixMaybe(self.thisptr.which()).getProto().getOrdinal() + cdef class _CodeGeneratorRequestReader: cdef C_CodeGeneratorRequest.Reader thisptr cdef init(self, C_CodeGeneratorRequest.Reader other): @@ -145,6 +348,10 @@ cdef class MessageBuilder: cdef class MallocMessageBuilder(MessageBuilder): def __cinit__(self): self.thisptr = new schema_cpp.MallocMessageBuilder() + cpdef initRootDynamicStruct(self, StructSchema schema): + return _DynamicStructBuilder().init(self.thisptr.initRootDynamicStruct(schema.thisptr)) + cpdef getRootDynamicStruct(self, StructSchema schema): + return _DynamicStructBuilder().init(self.thisptr.getRootDynamicStruct(schema.thisptr)) cdef class MessageReader: cdef schema_cpp.MessageReader * thisptr diff --git a/capnp_cpp.pxd b/capnp_cpp.pxd index 28d1f61..d61cab4 100644 --- a/capnp_cpp.pxd +++ b/capnp_cpp.pxd @@ -2,25 +2,128 @@ # distutils: language = c++ # distutils: extra_compile_args = --std=c++11 # distutils: libraries = capnp -from schema_cpp cimport Node +from schema_cpp cimport Node, Data, StructNode -cdef extern from "capnp/dynamic.h" namespace "::capnp": - cdef cppclass DynamicValue: - cppclass Reader: - pass - cdef cppclass DynamicStruct: - cppclass Reader: - DynamicValue.Reader get(char *) except +ValueError - bint has(char *) +from libc.stdint cimport * +ctypedef unsigned int uint + +cdef extern from "kj/common.h" namespace "::kj": + cdef cppclass Maybe[T]: + pass cdef extern from "capnp/schema.h" namespace "::capnp": cdef cppclass Schema: Node.Reader getProto() StructSchema asStruct() cdef cppclass StructSchema(Schema): - pass + cppclass Member: + StructNode.Member.Reader getProto() + StructNode.Reader getProto() cdef extern from "capnp/schema-loader.h" namespace "::capnp": cdef cppclass SchemaLoader: SchemaLoader() - Schema load(Node.Reader &) except + \ No newline at end of file + Schema load(Node.Reader &) except + + +cdef extern from "capnp/dynamic.h" namespace "::capnp": + cdef cppclass DynamicValueForward"::capnp::DynamicValue": + cppclass Reader: + pass + cppclass Builder: + pass + + enum Type: + TYPE_UNKNOWN "::capnp::DynamicValue::UNKNOWN" + TYPE_VOID "::capnp::DynamicValue::VOID" + TYPE_BOOL "::capnp::DynamicValue::BOOL" + TYPE_INT "::capnp::DynamicValue::INT" + TYPE_UINT "::capnp::DynamicValue::UINT" + TYPE_FLOAT "::capnp::DynamicValue::FLOAT" + TYPE_TEXT "::capnp::DynamicValue::TEXT" + TYPE_DATA "::capnp::DynamicValue::DATA" + TYPE_LIST "::capnp::DynamicValue::LIST" + TYPE_ENUM "::capnp::DynamicValue::ENUM" + TYPE_STRUCT "::capnp::DynamicValue::STRUCT" + TYPE_UNION "::capnp::DynamicValue::UNION" + TYPE_INTERFACE "::capnp::DynamicValue::INTERFACE" + TYPE_OBJECT "::capnp::DynamicValue::OBJECT" + + cdef cppclass DynamicStruct: + cppclass Reader: + DynamicValueForward.Reader get(char *) except +ValueError + bint has(char *) except +ValueError + cppclass Builder: + DynamicValueForward.Builder get(char *) except +ValueError + bint has(char *) except +ValueError + void set(char *, DynamicValueForward.Reader&) except +ValueError + +cdef extern from "fixMaybe.h": + StructSchema.Member fixMaybe(Maybe[StructSchema.Member]) except+ + +cdef extern from "capnp/dynamic.h" namespace "::capnp": + cdef cppclass DynamicEnum: + uint16_t getRaw() + + cdef cppclass DynamicUnion: + cppclass Reader: + DynamicValueForward.Reader get() except +ValueError + Maybe[StructSchema.Member] which() + cppclass Builder: + DynamicValueForward.Builder get() except +ValueError + Maybe[StructSchema.Member] which() + void set(char *, DynamicValueForward.Reader&) except +ValueError + + cdef cppclass DynamicList: + cppclass Reader: + DynamicValueForward.Reader operator[](uint) except +ValueError + uint size() + cppclass Builder: + DynamicValueForward.Builder operator[](uint) except +ValueError + uint size() + void set(uint index, DynamicValueForward.Reader& value) + DynamicValueForward.Builder init(uint index, uint size) + + cdef cppclass DynamicValue: + cppclass Reader: + Reader() + Reader(bint value) + Reader(char value) + Reader(short value) + Reader(int value) + Reader(long value) + Reader(long long value) + Reader(unsigned char value) + Reader(unsigned short value) + Reader(unsigned int value) + Reader(unsigned long value) + Reader(unsigned long long value) + Reader(float value) + Reader(double value) + Reader(char* value) + Reader(DynamicList.Reader& value) + Reader(DynamicEnum value) + Reader(DynamicStruct.Reader& value) + Reader(DynamicUnion.Reader& value) + Type getType() + int64_t asInt"as"() + uint64_t asUint"as"() + bint asBool"as"() + double asDouble"as"() + char * asText"as<::capnp::Text>().cStr"() + DynamicList.Reader asList"as<::capnp::DynamicList>"() + DynamicStruct.Reader asStruct"as<::capnp::DynamicStruct>"() + DynamicUnion.Reader asUnion"as<::capnp::DynamicUnion>"() + DynamicEnum asEnum"as<::capnp::DynamicEnum>"() + Data.Reader asData"as<::capnp::Data>"() + cppclass Builder: + Type getType() + int64_t asInt"as"() + uint64_t asUint"as"() + bint asBool"as"() + double asDouble"as"() + char * asText"as<::capnp::Text>().cStr"() + DynamicList.Builder asList"as<::capnp::DynamicList>"() + DynamicStruct.Builder asStruct"as<::capnp::DynamicStruct>"() + DynamicUnion.Builder asUnion"as<::capnp::DynamicUnion>"() + DynamicEnum asEnum"as<::capnp::DynamicEnum>"() + Data.Builder asData"as<::capnp::Data>"() \ No newline at end of file diff --git a/fixMaybe.h b/fixMaybe.h new file mode 100644 index 0000000..be56680 --- /dev/null +++ b/fixMaybe.h @@ -0,0 +1,11 @@ +#include "kj/common.h" +#include + +template +T fixMaybe(::kj::Maybe val) { + KJ_IF_MAYBE(new_val, val) { + return *new_val; + } else { + throw std::invalid_argument("member was null"); + } +} \ No newline at end of file diff --git a/schema_cpp.pxd b/schema_cpp.pxd index 2d9f236..7fc8c85 100644 --- a/schema_cpp.pxd +++ b/schema_cpp.pxd @@ -23,9 +23,13 @@ cdef extern from "capnp/dynamic.h" namespace "::capnp": cdef cppclass DynamicValue: cppclass Reader: pass + cppclass Builder: + pass cdef cppclass DynamicStruct: cppclass Reader: pass + cppclass Builder: + pass cdef extern from "capnp/schema.h" namespace "::capnp": cdef cppclass Schema: @@ -644,6 +648,9 @@ cdef extern from "capnp/message.h" namespace "::capnp": StructNode.Builder initRootStructNode'initRoot<::capnp::schema::StructNode>'() Annotation.Builder getRootAnnotation'getRoot<::capnp::schema::Annotation>'() Annotation.Builder initRootAnnotation'initRoot<::capnp::schema::Annotation>'() + + DynamicStruct.Builder getRootDynamicStruct'getRoot<::capnp::DynamicStruct>'(StructSchema) + DynamicStruct.Builder initRootDynamicStruct'initRoot<::capnp::DynamicStruct>'(StructSchema) cdef cppclass MessageReader: CodeGeneratorRequest.Reader getRootCodeGeneratorRequest'getRoot<::capnp::schema::CodeGeneratorRequest>'()