Initial version of code generating plugin
The plugin generates higher performance compiled versions of the structs
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
"""A python library wrapping the Cap'n Proto C++ library
|
"""A python library wrapping the Cap'n Proto C++ library
|
||||||
|
|
||||||
Example Usage::
|
Example Usage::
|
||||||
|
|
||||||
import capnp
|
import capnp
|
||||||
|
|
||||||
addressbook = capnp.load('addressbook.capnp')
|
addressbook = capnp.load('addressbook.capnp')
|
||||||
|
|||||||
37
capnp/_gen.py
Normal file
37
capnp/_gen.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import capnp
|
||||||
|
import schema_capnp
|
||||||
|
import sys
|
||||||
|
from jinja2 import Environment, PackageLoader
|
||||||
|
|
||||||
|
def main():
|
||||||
|
env = Environment(loader=PackageLoader('capnp', 'templates'))
|
||||||
|
env.filters['format_name'] = lambda name: name[name.find(':')+1:]
|
||||||
|
|
||||||
|
code = schema_capnp.CodeGeneratorRequest.read(sys.stdin)
|
||||||
|
code=code.to_dict()
|
||||||
|
code['nodes'] = [node for node in code['nodes'] if 'struct' in node]
|
||||||
|
for node in code['nodes']:
|
||||||
|
displayName = node['displayName']
|
||||||
|
parent, path = displayName.split(':')
|
||||||
|
node['module_path'] = parent.replace('.', '_') + '.' + '.'.join([x[0].upper() + x[1:] for x in path.split('.')])
|
||||||
|
node['module_name'] = path.replace('.', '_')
|
||||||
|
node['schema'] = '_{}_Schema'.format(node['module_name'])
|
||||||
|
is_union = False
|
||||||
|
for field in node['struct']['fields']:
|
||||||
|
if field['discriminantValue'] != 65535:
|
||||||
|
is_union = True
|
||||||
|
node['is_union'] = is_union
|
||||||
|
|
||||||
|
module = env.get_template('module.pyx')
|
||||||
|
filename = code['requestedFiles'][0]['filename'].replace('.', '_') + '_cython.pyx'
|
||||||
|
# TODO: handle multiple files
|
||||||
|
with open(filename, 'w') as out:
|
||||||
|
out.write(module.render(code=code))
|
||||||
|
|
||||||
|
setup = env.get_template('setup.py')
|
||||||
|
with open('setup_capnp.py', 'w') as out:
|
||||||
|
out.write(setup.render(code=code))
|
||||||
|
print('You now need to build the cython module by running `python setup_capnp.py build_ext --inplace`.')
|
||||||
|
print()
|
||||||
@@ -229,6 +229,7 @@ cdef extern from "capnp/dynamic.h" namespace " ::capnp":
|
|||||||
bint has(char *) except +reraise_kj_exception
|
bint has(char *) except +reraise_kj_exception
|
||||||
bint hasByField"has"(StructSchema.Field) except +reraise_kj_exception
|
bint hasByField"has"(StructSchema.Field) except +reraise_kj_exception
|
||||||
StructSchema getSchema()
|
StructSchema getSchema()
|
||||||
|
uint64_t getId"getSchema().getProto().getId"()
|
||||||
Maybe[StructSchema.Field] which()
|
Maybe[StructSchema.Field] which()
|
||||||
MessageSize totalSize()
|
MessageSize totalSize()
|
||||||
cppclass Pipeline:
|
cppclass Pipeline:
|
||||||
@@ -251,6 +252,7 @@ cdef extern from "capnp/dynamic.h" namespace " ::capnp":
|
|||||||
DynamicValueForward.Builder initByField"init"(StructSchema.Field, uint size) except +reraise_kj_exception
|
DynamicValueForward.Builder initByField"init"(StructSchema.Field, uint size) except +reraise_kj_exception
|
||||||
DynamicValueForward.Builder initByField"init"(StructSchema.Field) except +reraise_kj_exception
|
DynamicValueForward.Builder initByField"init"(StructSchema.Field) except +reraise_kj_exception
|
||||||
StructSchema getSchema()
|
StructSchema getSchema()
|
||||||
|
uint64_t getId"getSchema().getProto().getId"()
|
||||||
Maybe[StructSchema.Field] which()
|
Maybe[StructSchema.Field] which()
|
||||||
void adopt(char *, DynamicOrphan) except +reraise_kj_exception
|
void adopt(char *, DynamicOrphan) except +reraise_kj_exception
|
||||||
DynamicOrphan disown(char *)
|
DynamicOrphan disown(char *)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ cdef class _DynamicStructReader:
|
|||||||
cdef object _obj_to_pin
|
cdef object _obj_to_pin
|
||||||
cdef object _schema
|
cdef object _schema
|
||||||
|
|
||||||
cdef _init(self, C_DynamicStruct.Reader other, object parent, bint isRoot=?)
|
cdef _init(self, C_DynamicStruct.Reader other, object parent, bint isRoot=?, bint tryRegistry=?)
|
||||||
|
|
||||||
cpdef _get(self, field)
|
cpdef _get(self, field)
|
||||||
cpdef _has(self, field)
|
cpdef _has(self, field)
|
||||||
@@ -48,7 +48,7 @@ cdef class _DynamicStructBuilder:
|
|||||||
cdef bint _is_written
|
cdef bint _is_written
|
||||||
cdef object _schema
|
cdef object _schema
|
||||||
|
|
||||||
cdef _init(self, DynamicStruct_Builder other, object parent, bint isRoot=?)
|
cdef _init(self, DynamicStruct_Builder other, object parent, bint isRoot=?, bint tryRegistry=?)
|
||||||
|
|
||||||
cdef _check_write(self)
|
cdef _check_write(self)
|
||||||
cpdef to_bytes(_DynamicStructBuilder self)
|
cpdef to_bytes(_DynamicStructBuilder self)
|
||||||
@@ -82,3 +82,8 @@ cdef class _Schema:
|
|||||||
cpdef as_enum(self)
|
cpdef as_enum(self)
|
||||||
cpdef get_dependency(self, id)
|
cpdef get_dependency(self, id)
|
||||||
cpdef get_proto(self)
|
cpdef get_proto(self)
|
||||||
|
|
||||||
|
cdef to_python_reader(C_DynamicValue.Reader self, object parent)
|
||||||
|
cdef to_python_builder(C_DynamicValue.Builder self, object parent)
|
||||||
|
cdef _to_dict(msg, bint verbose)
|
||||||
|
cdef _setDynamicFieldWithField(DynamicStruct_Builder thisptr, _StructSchemaField field, value, parent)
|
||||||
|
|||||||
@@ -33,6 +33,14 @@ _CAPNP_VERSION_MINOR = capnp.CAPNP_VERSION_MINOR
|
|||||||
_CAPNP_VERSION_MICRO = capnp.CAPNP_VERSION_MICRO
|
_CAPNP_VERSION_MICRO = capnp.CAPNP_VERSION_MICRO
|
||||||
_CAPNP_VERSION = capnp.CAPNP_VERSION
|
_CAPNP_VERSION = capnp.CAPNP_VERSION
|
||||||
|
|
||||||
|
cdef dict _type_registry = {}
|
||||||
|
|
||||||
|
def register_type(id, klass):
|
||||||
|
_type_registry[id] = klass
|
||||||
|
|
||||||
|
def deregister_all_types():
|
||||||
|
_type_registry = {}
|
||||||
|
|
||||||
# By making it public, we'll be able to call it from capabilityHelper.h
|
# By making it public, we'll be able to call it from capabilityHelper.h
|
||||||
cdef public object wrap_dynamic_struct_reader(Response & r) with gil:
|
cdef public object wrap_dynamic_struct_reader(Response & r) with gil:
|
||||||
return _Response()._init_childptr(new Response(moveResponse(r)), None)
|
return _Response()._init_childptr(new Response(moveResponse(r)), None)
|
||||||
@@ -671,6 +679,17 @@ cdef _setBaseString(_DynamicSetterClasses thisptr, field, value):
|
|||||||
cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(temp_string)
|
cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(temp_string)
|
||||||
thisptr.set(field, temp)
|
thisptr.set(field, temp)
|
||||||
|
|
||||||
|
cdef _setBytesField(DynamicStruct_Builder thisptr, _StructSchemaField field, value):
|
||||||
|
cdef capnp.StringPtr temp_string = capnp.StringPtr(<char*>value, len(value))
|
||||||
|
cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(temp_string)
|
||||||
|
thisptr.setByField(field.thisptr, temp)
|
||||||
|
|
||||||
|
cdef _setBaseStringField(DynamicStruct_Builder thisptr, _StructSchemaField field, value):
|
||||||
|
encoded_value = value.encode()
|
||||||
|
cdef capnp.StringPtr temp_string = capnp.StringPtr(<char*>encoded_value, len(encoded_value))
|
||||||
|
cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(temp_string)
|
||||||
|
thisptr.setByField(field.thisptr, temp)
|
||||||
|
|
||||||
cdef _setDynamicField(_DynamicSetterClasses thisptr, field, value, parent):
|
cdef _setDynamicField(_DynamicSetterClasses thisptr, field, value, parent):
|
||||||
cdef C_DynamicValue.Reader temp
|
cdef C_DynamicValue.Reader temp
|
||||||
value_type = type(value)
|
value_type = type(value)
|
||||||
@@ -717,6 +736,48 @@ cdef _setDynamicField(_DynamicSetterClasses thisptr, field, value, parent):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("Tried to set field: '{}' with a value of: '{}' which is an unsupported type: '{}'".format(field, str(value), str(type(value))))
|
raise ValueError("Tried to set field: '{}' with a value of: '{}' which is an unsupported type: '{}'".format(field, str(value), str(type(value))))
|
||||||
|
|
||||||
|
cdef _setDynamicFieldWithField(DynamicStruct_Builder thisptr, _StructSchemaField field, value, parent):
|
||||||
|
cdef C_DynamicValue.Reader temp
|
||||||
|
value_type = type(value)
|
||||||
|
|
||||||
|
if value_type is int or value_type is long:
|
||||||
|
if value < 0:
|
||||||
|
temp = C_DynamicValue.Reader(<long long>value)
|
||||||
|
else:
|
||||||
|
temp = C_DynamicValue.Reader(<unsigned long long>value)
|
||||||
|
thisptr.setByField(field.thisptr, temp)
|
||||||
|
elif value_type is float:
|
||||||
|
temp = C_DynamicValue.Reader(<double>value)
|
||||||
|
thisptr.setByField(field.thisptr, temp)
|
||||||
|
elif value_type is bool:
|
||||||
|
temp = C_DynamicValue.Reader(<cbool>value)
|
||||||
|
thisptr.setByField(field.thisptr, temp)
|
||||||
|
elif value_type is bytes:
|
||||||
|
_setBytesField(thisptr, field, value)
|
||||||
|
elif isinstance(value, basestring):
|
||||||
|
_setBaseStringField(thisptr, field, value)
|
||||||
|
elif value_type is list:
|
||||||
|
builder = to_python_builder(thisptr.init(field.proto.name, len(value)), parent)
|
||||||
|
_from_list(builder, value)
|
||||||
|
elif value_type is dict:
|
||||||
|
builder = to_python_builder(thisptr.getByField(field.thisptr), parent)
|
||||||
|
_from_dict(builder, value)
|
||||||
|
elif value is None:
|
||||||
|
temp = C_DynamicValue.Reader(VOID)
|
||||||
|
thisptr.setByField(field.thisptr, temp)
|
||||||
|
elif value_type is _DynamicStructBuilder:
|
||||||
|
thisptr.setByField(field.thisptr, _extract_dynamic_struct_builder(value))
|
||||||
|
elif value_type is _DynamicStructReader:
|
||||||
|
thisptr.setByField(field.thisptr, _extract_dynamic_struct_reader(value))
|
||||||
|
elif value_type is _DynamicCapabilityClient:
|
||||||
|
thisptr.setByField(field.thisptr, _extract_dynamic_client(value))
|
||||||
|
elif value_type is _DynamicCapabilityServer or isinstance(value, _DynamicCapabilityServer):
|
||||||
|
thisptr.setByField(field.thisptr, _extract_dynamic_server(value))
|
||||||
|
elif value_type is _DynamicEnum:
|
||||||
|
thisptr.setByField(field.thisptr, _extract_dynamic_enum(value))
|
||||||
|
else:
|
||||||
|
raise ValueError("Tried to set field: '{}' with a value of: '{}' which is an unsupported type: '{}'".format(field, str(value), str(type(value))))
|
||||||
|
|
||||||
cdef _to_dict(msg, bint verbose):
|
cdef _to_dict(msg, bint verbose):
|
||||||
msg_type = type(msg)
|
msg_type = type(msg)
|
||||||
if msg_type is _DynamicListBuilder or msg_type is _DynamicListReader or msg_type is _DynamicResizableListBuilder:
|
if msg_type is _DynamicListBuilder or msg_type is _DynamicListReader or msg_type is _DynamicResizableListBuilder:
|
||||||
@@ -736,6 +797,9 @@ cdef _to_dict(msg, bint verbose):
|
|||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
if isinstance(msg, (_DynamicStructBuilder, _DynamicStructReader)):
|
||||||
|
return msg.to_dict()
|
||||||
|
|
||||||
if msg_type is _DynamicEnum:
|
if msg_type is _DynamicEnum:
|
||||||
return str(msg)
|
return str(msg)
|
||||||
|
|
||||||
@@ -864,11 +928,16 @@ cdef class _DynamicStructReader:
|
|||||||
print person.name # using . syntax
|
print person.name # using . syntax
|
||||||
print getattr(person, 'field-with-hyphens') # for names that are invalid for python, use getattr
|
print getattr(person, 'field-with-hyphens') # for names that are invalid for python, use getattr
|
||||||
"""
|
"""
|
||||||
cdef _init(self, C_DynamicStruct.Reader other, object parent, bint isRoot=False):
|
cdef _init(self, C_DynamicStruct.Reader other, object parent, bint isRoot=False, bint tryRegistry = True):
|
||||||
self.thisptr = other
|
self.thisptr = other
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
self.is_root = isRoot
|
self.is_root = isRoot
|
||||||
self._schema = None
|
self._schema = None
|
||||||
|
|
||||||
|
if tryRegistry and len(_type_registry) > 0:
|
||||||
|
registered_type = _type_registry.get(self.thisptr.getId(), None)
|
||||||
|
if registered_type:
|
||||||
|
return registered_type[0](self)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
cpdef _get(self, field):
|
cpdef _get(self, field):
|
||||||
@@ -966,12 +1035,17 @@ cdef class _DynamicStructBuilder:
|
|||||||
setattr(person, 'field-with-hyphens', 'foo') # for names that are invalid for python, use setattr
|
setattr(person, 'field-with-hyphens', 'foo') # for names that are invalid for python, use setattr
|
||||||
print getattr(person, 'field-with-hyphens') # for names that are invalid for python, use getattr
|
print getattr(person, 'field-with-hyphens') # for names that are invalid for python, use getattr
|
||||||
"""
|
"""
|
||||||
cdef _init(self, DynamicStruct_Builder other, object parent, bint isRoot = False):
|
cdef _init(self, DynamicStruct_Builder other, object parent, bint isRoot = False, bint tryRegistry = True):
|
||||||
self.thisptr = other
|
self.thisptr = other
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
self.is_root = isRoot
|
self.is_root = isRoot
|
||||||
self._is_written = False
|
self._is_written = False
|
||||||
self._schema = None
|
self._schema = None
|
||||||
|
|
||||||
|
if tryRegistry and len(_type_registry) > 0:
|
||||||
|
registered_type = _type_registry.get(self.thisptr.getId(), None)
|
||||||
|
if registered_type:
|
||||||
|
return registered_type[1](self)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
cdef _check_write(self):
|
cdef _check_write(self):
|
||||||
@@ -1067,8 +1141,7 @@ cdef class _DynamicStructBuilder:
|
|||||||
_setDynamicField(self.thisptr, field, value, self._parent)
|
_setDynamicField(self.thisptr, field, value, self._parent)
|
||||||
|
|
||||||
cpdef _set_by_field(self, _StructSchemaField field, value):
|
cpdef _set_by_field(self, _StructSchemaField field, value):
|
||||||
# TODO: make this faster
|
_setDynamicFieldWithField(self.thisptr, field, value, self._parent)
|
||||||
_setDynamicField(self.thisptr, field.proto.name, value, self._parent)
|
|
||||||
|
|
||||||
def __setattr__(self, field, value):
|
def __setattr__(self, field, value):
|
||||||
self._set(field, value)
|
self._set(field, value)
|
||||||
|
|||||||
383
capnp/schema.capnp
Normal file
383
capnp/schema.capnp
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
# Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
# list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
using Cxx = import "c++.capnp";
|
||||||
|
|
||||||
|
@0xa93fc509624c72d9;
|
||||||
|
$Cxx.namespace("capnp::schema");
|
||||||
|
|
||||||
|
using Id = UInt64;
|
||||||
|
# The globally-unique ID of a file, type, or annotation.
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
id @0 :Id;
|
||||||
|
|
||||||
|
displayName @1 :Text;
|
||||||
|
# Name to present to humans to identify this Node. You should not attempt to parse this. Its
|
||||||
|
# format could change. It is not guaranteed to be unique.
|
||||||
|
#
|
||||||
|
# (On Zooko's triangle, this is the node's nickname.)
|
||||||
|
|
||||||
|
displayNamePrefixLength @2 :UInt32;
|
||||||
|
# If you want a shorter version of `displayName` (just naming this node, without its surrounding
|
||||||
|
# scope), chop off this many characters from the beginning of `displayName`.
|
||||||
|
|
||||||
|
scopeId @3 :Id;
|
||||||
|
# ID of the lexical parent node. Typically, the scope node will have a NestedNode pointing back
|
||||||
|
# at this node, but robust code should avoid relying on this (and, in fact, group nodes are not
|
||||||
|
# listed in the outer struct's nestedNodes, since they are listed in the fields). `scopeId` is
|
||||||
|
# zero if the node has no parent, which is normally only the case with files, but should be
|
||||||
|
# allowed for any kind of node (in order to make runtime type generation easier).
|
||||||
|
|
||||||
|
nestedNodes @4 :List(NestedNode);
|
||||||
|
# List of nodes nested within this node, along with the names under which they were declared.
|
||||||
|
|
||||||
|
struct NestedNode {
|
||||||
|
name @0 :Text;
|
||||||
|
# Unqualified symbol name. Unlike Node.name, this *can* be used programmatically.
|
||||||
|
#
|
||||||
|
# (On Zooko's triangle, this is the node's petname according to its parent scope.)
|
||||||
|
|
||||||
|
id @1 :Id;
|
||||||
|
# ID of the nested node. Typically, the target node's scopeId points back to this node, but
|
||||||
|
# robust code should avoid relying on this.
|
||||||
|
}
|
||||||
|
|
||||||
|
annotations @5 :List(Annotation);
|
||||||
|
# Annotations applied to this node.
|
||||||
|
|
||||||
|
union {
|
||||||
|
# Info specific to each kind of node.
|
||||||
|
|
||||||
|
file @6 :Void;
|
||||||
|
|
||||||
|
struct :group {
|
||||||
|
dataWordCount @7 :UInt16;
|
||||||
|
# Size of the data section, in words.
|
||||||
|
|
||||||
|
pointerCount @8 :UInt16;
|
||||||
|
# Size of the pointer section, in pointers (which are one word each).
|
||||||
|
|
||||||
|
preferredListEncoding @9 :ElementSize;
|
||||||
|
# The preferred element size to use when encoding a list of this struct. If this is anything
|
||||||
|
# other than `inlineComposite` then the struct is one word or less in size and is a candidate
|
||||||
|
# for list packing optimization.
|
||||||
|
|
||||||
|
isGroup @10 :Bool;
|
||||||
|
# If true, then this "struct" node is actually not an independent node, but merely represents
|
||||||
|
# some named union or group within a particular parent struct. This node's scopeId refers
|
||||||
|
# to the parent struct, which may itself be a union/group in yet another struct.
|
||||||
|
#
|
||||||
|
# All group nodes share the same dataWordCount and pointerCount as the top-level
|
||||||
|
# struct, and their fields live in the same ordinal and offset spaces as all other fields in
|
||||||
|
# the struct.
|
||||||
|
#
|
||||||
|
# Note that a named union is considered a special kind of group -- in fact, a named union
|
||||||
|
# is exactly equivalent to a group that contains nothing but an unnamed union.
|
||||||
|
|
||||||
|
discriminantCount @11 :UInt16;
|
||||||
|
# Number of fields in this struct which are members of an anonymous union, and thus may
|
||||||
|
# overlap. If this is non-zero, then a 16-bit discriminant is present indicating which
|
||||||
|
# of the overlapping fields is active. This can never be 1 -- if it is non-zero, it must be
|
||||||
|
# two or more.
|
||||||
|
#
|
||||||
|
# Note that the fields of an unnamed union are considered fields of the scope containing the
|
||||||
|
# union -- an unnamed union is not its own group. So, a top-level struct may contain a
|
||||||
|
# non-zero discriminant count. Named unions, on the other hand, are equivalent to groups
|
||||||
|
# containing unnamed unions. So, a named union has its own independent schema node, with
|
||||||
|
# `isGroup` = true.
|
||||||
|
|
||||||
|
discriminantOffset @12 :UInt32;
|
||||||
|
# If `discriminantCount` is non-zero, this is the offset of the union discriminant, in
|
||||||
|
# multiples of 16 bits.
|
||||||
|
|
||||||
|
fields @13 :List(Field);
|
||||||
|
# Fields defined within this scope (either the struct's top-level fields, or the fields of
|
||||||
|
# a particular group; see `isGroup`).
|
||||||
|
#
|
||||||
|
# The fields are sorted by ordinal number, but note that because groups share the same
|
||||||
|
# ordinal space, the field's index in this list is not necessarily exactly its ordinal.
|
||||||
|
# On the other hand, the field's position in this list does remain the same even as the
|
||||||
|
# protocol evolves, since it is not possible to insert or remove an earlier ordinal.
|
||||||
|
# Therefore, for most use cases, if you want to identify a field by number, it may make the
|
||||||
|
# most sense to use the field's index in this list rather than its ordinal.
|
||||||
|
}
|
||||||
|
|
||||||
|
enum :group {
|
||||||
|
enumerants@14 :List(Enumerant);
|
||||||
|
# Enumerants ordered by numeric value (ordinal).
|
||||||
|
}
|
||||||
|
|
||||||
|
interface :group {
|
||||||
|
methods @15 :List(Method);
|
||||||
|
# Methods ordered by ordinal.
|
||||||
|
|
||||||
|
extends @31 :List(Id);
|
||||||
|
# Superclasses of this interface.
|
||||||
|
}
|
||||||
|
|
||||||
|
const :group {
|
||||||
|
type @16 :Type;
|
||||||
|
value @17 :Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
annotation :group {
|
||||||
|
type @18 :Type;
|
||||||
|
|
||||||
|
targetsFile @19 :Bool;
|
||||||
|
targetsConst @20 :Bool;
|
||||||
|
targetsEnum @21 :Bool;
|
||||||
|
targetsEnumerant @22 :Bool;
|
||||||
|
targetsStruct @23 :Bool;
|
||||||
|
targetsField @24 :Bool;
|
||||||
|
targetsUnion @25 :Bool;
|
||||||
|
targetsGroup @26 :Bool;
|
||||||
|
targetsInterface @27 :Bool;
|
||||||
|
targetsMethod @28 :Bool;
|
||||||
|
targetsParam @29 :Bool;
|
||||||
|
targetsAnnotation @30 :Bool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Field {
|
||||||
|
# Schema for a field of a struct.
|
||||||
|
|
||||||
|
name @0 :Text;
|
||||||
|
|
||||||
|
codeOrder @1 :UInt16;
|
||||||
|
# Indicates where this member appeared in the code, relative to other members.
|
||||||
|
# Code ordering may have semantic relevance -- programmers tend to place related fields
|
||||||
|
# together. So, using code ordering makes sense in human-readable formats where ordering is
|
||||||
|
# otherwise irrelevant, like JSON. The values of codeOrder are tightly-packed, so the maximum
|
||||||
|
# value is count(members) - 1. Fields that are members of a union are only ordered relative to
|
||||||
|
# the other members of that union, so the maximum value there is count(union.members).
|
||||||
|
|
||||||
|
annotations @2 :List(Annotation);
|
||||||
|
|
||||||
|
const noDiscriminant :UInt16 = 0xffff;
|
||||||
|
|
||||||
|
discriminantValue @3 :UInt16 = Field.noDiscriminant;
|
||||||
|
# If the field is in a union, this is the value which the union's discriminant should take when
|
||||||
|
# the field is active. If the field is not in a union, this is 0xffff.
|
||||||
|
|
||||||
|
union {
|
||||||
|
slot :group {
|
||||||
|
# A regular, non-group, non-fixed-list field.
|
||||||
|
|
||||||
|
offset @4 :UInt32;
|
||||||
|
# Offset, in units of the field's size, from the beginning of the section in which the field
|
||||||
|
# resides. E.g. for a UInt32 field, multiply this by 4 to get the byte offset from the
|
||||||
|
# beginning of the data section.
|
||||||
|
|
||||||
|
type @5 :Type;
|
||||||
|
defaultValue @6 :Value;
|
||||||
|
|
||||||
|
hadExplicitDefault @10 :Bool;
|
||||||
|
# Whether the default value was specified explicitly. Non-explicit default values are always
|
||||||
|
# zero or empty values. Usually, whether the default value was explicit shouldn't matter.
|
||||||
|
# The main use case for this flag is for structs representing method parameters:
|
||||||
|
# explicitly-defaulted parameters may be allowed to be omitted when calling the method.
|
||||||
|
}
|
||||||
|
|
||||||
|
group :group {
|
||||||
|
# A group.
|
||||||
|
|
||||||
|
typeId @7 :Id;
|
||||||
|
# The ID of the group's node.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ordinal :union {
|
||||||
|
implicit @8 :Void;
|
||||||
|
explicit @9 :UInt16;
|
||||||
|
# The original ordinal number given to the field. You probably should NOT use this; if you need
|
||||||
|
# a numeric identifier for a field, use its position within the field array for its scope.
|
||||||
|
# The ordinal is given here mainly just so that the original schema text can be reproduced given
|
||||||
|
# the compiled version -- i.e. so that `capnp compile -ocapnp` can do its job.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Enumerant {
|
||||||
|
# Schema for member of an enum.
|
||||||
|
|
||||||
|
name @0 :Text;
|
||||||
|
|
||||||
|
codeOrder @1 :UInt16;
|
||||||
|
# Specifies order in which the enumerants were declared in the code.
|
||||||
|
# Like Struct.Field.codeOrder.
|
||||||
|
|
||||||
|
annotations @2 :List(Annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Method {
|
||||||
|
# Schema for method of an interface.
|
||||||
|
|
||||||
|
name @0 :Text;
|
||||||
|
|
||||||
|
codeOrder @1 :UInt16;
|
||||||
|
# Specifies order in which the methods were declared in the code.
|
||||||
|
# Like Struct.Field.codeOrder.
|
||||||
|
|
||||||
|
paramStructType @2 :Id;
|
||||||
|
# ID of the parameter struct type. If a named parameter list was specified in the method
|
||||||
|
# declaration (rather than a single struct parameter type) then a corresponding struct type is
|
||||||
|
# auto-generated. Such an auto-generated type will not be listed in the interface's
|
||||||
|
# `nestedNodes` and its `scopeId` will be zero -- it is completely detached from the namespace.
|
||||||
|
|
||||||
|
resultStructType @3 :Id;
|
||||||
|
# ID of the return struct type; similar to `paramStructType`.
|
||||||
|
|
||||||
|
annotations @4 :List(Annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Type {
|
||||||
|
# Represents a type expression.
|
||||||
|
|
||||||
|
union {
|
||||||
|
# The ordinals intentionally match those of Value.
|
||||||
|
|
||||||
|
void @0 :Void;
|
||||||
|
bool @1 :Void;
|
||||||
|
int8 @2 :Void;
|
||||||
|
int16 @3 :Void;
|
||||||
|
int32 @4 :Void;
|
||||||
|
int64 @5 :Void;
|
||||||
|
uint8 @6 :Void;
|
||||||
|
uint16 @7 :Void;
|
||||||
|
uint32 @8 :Void;
|
||||||
|
uint64 @9 :Void;
|
||||||
|
float32 @10 :Void;
|
||||||
|
float64 @11 :Void;
|
||||||
|
text @12 :Void;
|
||||||
|
data @13 :Void;
|
||||||
|
|
||||||
|
list :group {
|
||||||
|
elementType @14 :Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum :group {
|
||||||
|
typeId @15 :Id;
|
||||||
|
}
|
||||||
|
struct :group {
|
||||||
|
typeId @16 :Id;
|
||||||
|
}
|
||||||
|
interface :group {
|
||||||
|
typeId @17 :Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
anyPointer @18 :Void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Value {
|
||||||
|
# Represents a value, e.g. a field default value, constant value, or annotation value.
|
||||||
|
|
||||||
|
union {
|
||||||
|
# The ordinals intentionally match those of Type.
|
||||||
|
|
||||||
|
void @0 :Void;
|
||||||
|
bool @1 :Bool;
|
||||||
|
int8 @2 :Int8;
|
||||||
|
int16 @3 :Int16;
|
||||||
|
int32 @4 :Int32;
|
||||||
|
int64 @5 :Int64;
|
||||||
|
uint8 @6 :UInt8;
|
||||||
|
uint16 @7 :UInt16;
|
||||||
|
uint32 @8 :UInt32;
|
||||||
|
uint64 @9 :UInt64;
|
||||||
|
float32 @10 :Float32;
|
||||||
|
float64 @11 :Float64;
|
||||||
|
text @12 :Text;
|
||||||
|
data @13 :Data;
|
||||||
|
|
||||||
|
list @14 :AnyPointer;
|
||||||
|
|
||||||
|
enum @15 :UInt16;
|
||||||
|
struct @16 :AnyPointer;
|
||||||
|
|
||||||
|
interface @17 :Void;
|
||||||
|
# The only interface value that can be represented statically is "null", whose methods always
|
||||||
|
# throw exceptions.
|
||||||
|
|
||||||
|
anyPointer @18 :AnyPointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Annotation {
|
||||||
|
# Describes an annotation applied to a declaration. Note AnnotationNode describes the
|
||||||
|
# annotation's declaration, while this describes a use of the annotation.
|
||||||
|
|
||||||
|
id @0 :Id;
|
||||||
|
# ID of the annotation node.
|
||||||
|
|
||||||
|
value @1 :Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ElementSize {
|
||||||
|
# Possible element sizes for encoded lists. These correspond exactly to the possible values of
|
||||||
|
# the 3-bit element size component of a list pointer.
|
||||||
|
|
||||||
|
empty @0; # aka "void", but that's a keyword.
|
||||||
|
bit @1;
|
||||||
|
byte @2;
|
||||||
|
twoBytes @3;
|
||||||
|
fourBytes @4;
|
||||||
|
eightBytes @5;
|
||||||
|
pointer @6;
|
||||||
|
inlineComposite @7;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CodeGeneratorRequest {
|
||||||
|
nodes @0 :List(Node);
|
||||||
|
# All nodes parsed by the compiler, including for the files on the command line and their
|
||||||
|
# imports.
|
||||||
|
|
||||||
|
requestedFiles @1 :List(RequestedFile);
|
||||||
|
# Files which were listed on the command line.
|
||||||
|
|
||||||
|
struct RequestedFile {
|
||||||
|
id @0 :Id;
|
||||||
|
# ID of the file.
|
||||||
|
|
||||||
|
filename @1 :Text;
|
||||||
|
# Name of the file as it appeared on the command-line (minus the src-prefix). You may use
|
||||||
|
# this to decide where to write the output.
|
||||||
|
|
||||||
|
imports @2 :List(Import);
|
||||||
|
# List of all imported paths seen in this file.
|
||||||
|
|
||||||
|
struct Import {
|
||||||
|
id @0 :Id;
|
||||||
|
# ID of the imported file.
|
||||||
|
|
||||||
|
name @1 :Text;
|
||||||
|
# Name which *this* file used to refer to the foreign file. This may be a relative name.
|
||||||
|
# This information is provided because it might be useful for code generation, e.g. to
|
||||||
|
# generate #include directives in C++. We don't put this in Node.file because this
|
||||||
|
# information is only meaningful at compile time anyway.
|
||||||
|
#
|
||||||
|
# (On Zooko's triangle, this is the import's petname according to the importing file.)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
capnp/templates/module.pyx
Normal file
74
capnp/templates/module.pyx
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# addressbook_fast.pyx
|
||||||
|
# distutils: language = c++
|
||||||
|
# distutils: extra_compile_args = --std=c++11
|
||||||
|
# distutils: include_dirs = /usr/local/lib/python2.7/site-packages
|
||||||
|
# cython: c_string_type = str
|
||||||
|
# cython: c_string_encoding = default
|
||||||
|
# cython: embedsignature = True
|
||||||
|
|
||||||
|
import capnp
|
||||||
|
{%- for file in code.requestedFiles %}
|
||||||
|
import {{file.filename | replace('.', '_')}}
|
||||||
|
{% endfor %}
|
||||||
|
from capnp.includes.capnp_cpp cimport DynamicValue
|
||||||
|
from capnp.lib.capnp cimport _DynamicStructReader, _DynamicStructBuilder, _StructSchemaField, to_python_builder, to_python_reader, _to_dict, _setDynamicFieldWithField
|
||||||
|
|
||||||
|
{%- for node in code.nodes %}
|
||||||
|
{{node.schema}} = {{node.module_path}}.schema
|
||||||
|
{%- for field in node.struct.fields %}
|
||||||
|
cdef _StructSchemaField {{node.module_name}}_{{field.name}} = {{node.schema}}.fields['{{field.name}}']
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
cdef class {{node.module_name}}_Reader(_DynamicStructReader):
|
||||||
|
def __init__(self, _DynamicStructReader struct):
|
||||||
|
self._init(struct.thisptr, struct._parent, struct.is_root, False)
|
||||||
|
{% for field in node.struct.fields %}
|
||||||
|
cpdef _get_{{field.name}}(self):
|
||||||
|
cdef DynamicValue.Reader temp = self.thisptr.getByField({{node.module_name}}_{{field.name}}.thisptr)
|
||||||
|
return to_python_reader(temp, self._parent)
|
||||||
|
property {{field.name}}:
|
||||||
|
def __get__(self):
|
||||||
|
return self._get_{{field.name}}()
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
def to_dict(self, verbose=False):
|
||||||
|
return {
|
||||||
|
{% for field in node.struct.fields %}
|
||||||
|
'{{field.name}}': _to_dict(self.{{field.name}}, verbose),
|
||||||
|
{%- endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
|
cdef class {{node.module_name}}_Builder(_DynamicStructBuilder):
|
||||||
|
def __init__(self, _DynamicStructBuilder struct):
|
||||||
|
self._init(struct.thisptr, struct._parent, struct.is_root, False)
|
||||||
|
{% for field in node.struct.fields %}
|
||||||
|
cpdef _get_{{field.name}}(self):
|
||||||
|
cdef DynamicValue.Builder temp = self.thisptr.getByField({{node.module_name}}_{{field.name}}.thisptr)
|
||||||
|
return to_python_builder(temp, self._parent)
|
||||||
|
cpdef _set_{{field.name}}(self, value):
|
||||||
|
_setDynamicFieldWithField(self.thisptr, {{node.module_name}}_{{field.name}}, value, self._parent)
|
||||||
|
property {{field.name}}:
|
||||||
|
def __get__(self):
|
||||||
|
return self._get_{{field.name}}()
|
||||||
|
def __set__(self, value):
|
||||||
|
self._set_{{field.name}}(value)
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
def to_dict(self, verbose=False):
|
||||||
|
ret = {
|
||||||
|
{% for field in node.struct.fields %}
|
||||||
|
{% if field.discriminantValue == 65535 %}
|
||||||
|
'{{field.name}}': _to_dict(self.{{field.name}}, verbose),
|
||||||
|
{% endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
|
{% if node.is_union %}
|
||||||
|
which = self.which()
|
||||||
|
ret[which] = getattr(self, which)
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
capnp.register_type({{node.id}}, ({{node.module_name}}_Reader, {{node.module_name}}_Builder))
|
||||||
|
{% endfor %}
|
||||||
9
capnp/templates/setup.py
Normal file
9
capnp/templates/setup.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
from distutils.core import setup
|
||||||
|
from Cython.Build import cythonize
|
||||||
|
import os
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="{{code.requestedFiles[0] | replace('.', '_')}}",
|
||||||
|
ext_modules=cythonize('*_capnp_cython.pyx', language="c++")
|
||||||
|
)
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
|
jinja2 >= 2.7.3
|
||||||
cython > 0.19
|
cython > 0.19
|
||||||
setuptools >= 0.8
|
setuptools >= 0.8
|
||||||
pytest
|
pytest
|
||||||
tox
|
tox
|
||||||
|
|||||||
6
setup.py
6
setup.py
@@ -53,11 +53,15 @@ setup(
|
|||||||
name="pycapnp",
|
name="pycapnp",
|
||||||
packages=["capnp"],
|
packages=["capnp"],
|
||||||
version=VERSION,
|
version=VERSION,
|
||||||
package_data={'capnp': ['*.pxd', '*.h', '*.capnp', 'helpers/*.pxd', 'helpers/*.h', 'includes/*.pxd', 'lib/*.pxd', 'lib/*.py', 'lib/*.pyx']},
|
package_data={'capnp': ['*.pxd', '*.h', '*.capnp', 'helpers/*.pxd', 'helpers/*.h', 'includes/*.pxd', 'lib/*.pxd', 'lib/*.py', 'lib/*.pyx', 'templates/*']},
|
||||||
ext_modules=cythonize('capnp/lib/*.pyx', language="c++"),
|
ext_modules=cythonize('capnp/lib/*.pyx', language="c++"),
|
||||||
install_requires=[
|
install_requires=[
|
||||||
|
'jinja2 >= 2.7.3',
|
||||||
'cython > 0.19',
|
'cython > 0.19',
|
||||||
'setuptools >= 0.8'],
|
'setuptools >= 0.8'],
|
||||||
|
entry_points={
|
||||||
|
'console_scripts' : ['capnpc-cython = capnp._gen:main']
|
||||||
|
},
|
||||||
# PyPi info
|
# PyPi info
|
||||||
description="A cython wrapping of the C++ Cap'n Proto library",
|
description="A cython wrapping of the C++ Cap'n Proto library",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
|
|||||||
Reference in New Issue
Block a user