| // Protocol Buffers - Google's data interchange format |
| // Copyright 2008 Google Inc. All rights reserved. |
| // https://developers.google.com/protocol-buffers/ |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * 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. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // 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. |
| |
| // Mappings and Sequences of descriptors. |
| // Used by Descriptor.fields_by_name, EnumDescriptor.values... |
| // |
| // They avoid the allocation of a full dictionary or a full list: they simply |
| // store a pointer to the parent descriptor, use the C++ Descriptor methods (see |
| // google/protobuf/descriptor.h) to retrieve other descriptors, and create |
| // Python objects on the fly. |
| // |
| // The containers fully conform to abc.Mapping and abc.Sequence, and behave just |
| // like read-only dictionaries and lists. |
| // |
| // Because the interface of C++ Descriptors is quite regular, this file actually |
| // defines only three types, the exact behavior of a container is controlled by |
| // a DescriptorContainerDef structure, which contains functions that uses the |
| // public Descriptor API. |
| // |
| // Note: This DescriptorContainerDef is similar to the "virtual methods table" |
| // that a C++ compiler generates for a class. We have to make it explicit |
| // because the Python API is based on C, and does not play well with C++ |
| // inheritance. |
| |
| #include <Python.h> |
| |
| #include <google/protobuf/descriptor.h> |
| #include <google/protobuf/pyext/descriptor_containers.h> |
| #include <google/protobuf/pyext/descriptor_pool.h> |
| #include <google/protobuf/pyext/descriptor.h> |
| #include <google/protobuf/pyext/scoped_pyobject_ptr.h> |
| |
| #if PY_MAJOR_VERSION >= 3 |
| #define PyString_FromStringAndSize PyUnicode_FromStringAndSize |
| #define PyString_FromFormat PyUnicode_FromFormat |
| #define PyInt_FromLong PyLong_FromLong |
| #if PY_VERSION_HEX < 0x03030000 |
| #error "Python 3.0 - 3.2 are not supported." |
| #endif |
| #define PyString_AsStringAndSize(ob, charpp, sizep) \ |
| (PyUnicode_Check(ob)? \ |
| ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \ |
| PyBytes_AsStringAndSize(ob, (charpp), (sizep))) |
| #endif |
| |
| namespace google { |
| namespace protobuf { |
| namespace python { |
| |
| struct PyContainer; |
| |
| typedef int (*CountMethod)(PyContainer* self); |
| typedef const void* (*GetByIndexMethod)(PyContainer* self, int index); |
| typedef const void* (*GetByNameMethod)(PyContainer* self, const string& name); |
| typedef const void* (*GetByCamelcaseNameMethod)(PyContainer* self, |
| const string& name); |
| typedef const void* (*GetByNumberMethod)(PyContainer* self, int index); |
| typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor); |
| typedef const string& (*GetItemNameMethod)(const void* descriptor); |
| typedef const string& (*GetItemCamelcaseNameMethod)(const void* descriptor); |
| typedef int (*GetItemNumberMethod)(const void* descriptor); |
| typedef int (*GetItemIndexMethod)(const void* descriptor); |
| |
| struct DescriptorContainerDef { |
| const char* mapping_name; |
| // Returns the number of items in the container. |
| CountMethod count_fn; |
| // Retrieve item by index (usually the order of declaration in the proto file) |
| // Used by sequences, but also iterators. 0 <= index < Count(). |
| GetByIndexMethod get_by_index_fn; |
| // Retrieve item by name (usually a call to some 'FindByName' method). |
| // Used by "by_name" mappings. |
| GetByNameMethod get_by_name_fn; |
| // Retrieve item by camelcase name (usually a call to some |
| // 'FindByCamelcaseName' method). Used by "by_camelcase_name" mappings. |
| GetByCamelcaseNameMethod get_by_camelcase_name_fn; |
| // Retrieve item by declared number (field tag, or enum value). |
| // Used by "by_number" mappings. |
| GetByNumberMethod get_by_number_fn; |
| // Converts a item C++ descriptor to a Python object. Returns a new reference. |
| NewObjectFromItemMethod new_object_from_item_fn; |
| // Retrieve the name of an item. Used by iterators on "by_name" mappings. |
| GetItemNameMethod get_item_name_fn; |
| // Retrieve the camelcase name of an item. Used by iterators on |
| // "by_camelcase_name" mappings. |
| GetItemCamelcaseNameMethod get_item_camelcase_name_fn; |
| // Retrieve the number of an item. Used by iterators on "by_number" mappings. |
| GetItemNumberMethod get_item_number_fn; |
| // Retrieve the index of an item for the container type. |
| // Used by "__contains__". |
| // If not set, "x in sequence" will do a linear search. |
| GetItemIndexMethod get_item_index_fn; |
| }; |
| |
| struct PyContainer { |
| PyObject_HEAD |
| |
| // The proto2 descriptor this container belongs to the global DescriptorPool. |
| const void* descriptor; |
| |
| // A pointer to a static structure with function pointers that control the |
| // behavior of the container. Very similar to the table of virtual functions |
| // of a C++ class. |
| const DescriptorContainerDef* container_def; |
| |
| // The kind of container: list, or dict by name or value. |
| enum ContainerKind { |
| KIND_SEQUENCE, |
| KIND_BYNAME, |
| KIND_BYCAMELCASENAME, |
| KIND_BYNUMBER, |
| } kind; |
| }; |
| |
| struct PyContainerIterator { |
| PyObject_HEAD |
| |
| // The container we are iterating over. Own a reference. |
| PyContainer* container; |
| |
| // The current index in the iterator. |
| int index; |
| |
| // The kind of container: list, or dict by name or value. |
| enum IterKind { |
| KIND_ITERKEY, |
| KIND_ITERVALUE, |
| KIND_ITERITEM, |
| KIND_ITERVALUE_REVERSED, // For sequences |
| } kind; |
| }; |
| |
| namespace descriptor { |
| |
| // Returns the C++ item descriptor for a given Python key. |
| // When the descriptor is found, return true and set *item. |
| // When the descriptor is not found, return true, but set *item to NULL. |
| // On error, returns false with an exception set. |
| static bool _GetItemByKey(PyContainer* self, PyObject* key, const void** item) { |
| switch (self->kind) { |
| case PyContainer::KIND_BYNAME: |
| { |
| char* name; |
| Py_ssize_t name_size; |
| if (PyString_AsStringAndSize(key, &name, &name_size) < 0) { |
| if (PyErr_ExceptionMatches(PyExc_TypeError)) { |
| // Not a string, cannot be in the container. |
| PyErr_Clear(); |
| *item = NULL; |
| return true; |
| } |
| return false; |
| } |
| *item = self->container_def->get_by_name_fn( |
| self, string(name, name_size)); |
| return true; |
| } |
| case PyContainer::KIND_BYCAMELCASENAME: |
| { |
| char* camelcase_name; |
| Py_ssize_t name_size; |
| if (PyString_AsStringAndSize(key, &camelcase_name, &name_size) < 0) { |
| if (PyErr_ExceptionMatches(PyExc_TypeError)) { |
| // Not a string, cannot be in the container. |
| PyErr_Clear(); |
| *item = NULL; |
| return true; |
| } |
| return false; |
| } |
| *item = self->container_def->get_by_camelcase_name_fn( |
| self, string(camelcase_name, name_size)); |
| return true; |
| } |
| case PyContainer::KIND_BYNUMBER: |
| { |
| Py_ssize_t number = PyNumber_AsSsize_t(key, NULL); |
| if (number == -1 && PyErr_Occurred()) { |
| if (PyErr_ExceptionMatches(PyExc_TypeError)) { |
| // Not a number, cannot be in the container. |
| PyErr_Clear(); |
| *item = NULL; |
| return true; |
| } |
| return false; |
| } |
| *item = self->container_def->get_by_number_fn(self, number); |
| return true; |
| } |
| default: |
| PyErr_SetNone(PyExc_NotImplementedError); |
| return false; |
| } |
| } |
| |
| // Returns the key of the object at the given index. |
| // Used when iterating over mappings. |
| static PyObject* _NewKey_ByIndex(PyContainer* self, Py_ssize_t index) { |
| const void* item = self->container_def->get_by_index_fn(self, index); |
| switch (self->kind) { |
| case PyContainer::KIND_BYNAME: |
| { |
| const string& name(self->container_def->get_item_name_fn(item)); |
| return PyString_FromStringAndSize(name.c_str(), name.size()); |
| } |
| case PyContainer::KIND_BYCAMELCASENAME: |
| { |
| const string& name( |
| self->container_def->get_item_camelcase_name_fn(item)); |
| return PyString_FromStringAndSize(name.c_str(), name.size()); |
| } |
| case PyContainer::KIND_BYNUMBER: |
| { |
| int value = self->container_def->get_item_number_fn(item); |
| return PyInt_FromLong(value); |
| } |
| default: |
| PyErr_SetNone(PyExc_NotImplementedError); |
| return NULL; |
| } |
| } |
| |
| // Returns the object at the given index. |
| // Also used when iterating over mappings. |
| static PyObject* _NewObj_ByIndex(PyContainer* self, Py_ssize_t index) { |
| return self->container_def->new_object_from_item_fn( |
| self->container_def->get_by_index_fn(self, index)); |
| } |
| |
| static Py_ssize_t Length(PyContainer* self) { |
| return self->container_def->count_fn(self); |
| } |
| |
| // The DescriptorMapping type. |
| |
| static PyObject* Subscript(PyContainer* self, PyObject* key) { |
| const void* item = NULL; |
| if (!_GetItemByKey(self, key, &item)) { |
| return NULL; |
| } |
| if (!item) { |
| PyErr_SetObject(PyExc_KeyError, key); |
| return NULL; |
| } |
| return self->container_def->new_object_from_item_fn(item); |
| } |
| |
| static int AssSubscript(PyContainer* self, PyObject* key, PyObject* value) { |
| if (_CalledFromGeneratedFile(0)) { |
| return 0; |
| } |
| PyErr_Format(PyExc_TypeError, |
| "'%.200s' object does not support item assignment", |
| Py_TYPE(self)->tp_name); |
| return -1; |
| } |
| |
| static PyMappingMethods MappingMappingMethods = { |
| (lenfunc)Length, // mp_length |
| (binaryfunc)Subscript, // mp_subscript |
| (objobjargproc)AssSubscript, // mp_ass_subscript |
| }; |
| |
| static int Contains(PyContainer* self, PyObject* key) { |
| const void* item = NULL; |
| if (!_GetItemByKey(self, key, &item)) { |
| return -1; |
| } |
| if (item) { |
| return 1; |
| } else { |
| return 0; |
| } |
| } |
| |
| static PyObject* ContainerRepr(PyContainer* self) { |
| const char* kind = ""; |
| switch (self->kind) { |
| case PyContainer::KIND_SEQUENCE: |
| kind = "sequence"; |
| break; |
| case PyContainer::KIND_BYNAME: |
| kind = "mapping by name"; |
| break; |
| case PyContainer::KIND_BYCAMELCASENAME: |
| kind = "mapping by camelCase name"; |
| break; |
| case PyContainer::KIND_BYNUMBER: |
| kind = "mapping by number"; |
| break; |
| } |
| return PyString_FromFormat( |
| "<%s %s>", self->container_def->mapping_name, kind); |
| } |
| |
| extern PyTypeObject DescriptorMapping_Type; |
| extern PyTypeObject DescriptorSequence_Type; |
| |
| // A sequence container can only be equal to another sequence container, or (for |
| // backward compatibility) to a list containing the same items. |
| // Returns 1 if equal, 0 if unequal, -1 on error. |
| static int DescriptorSequence_Equal(PyContainer* self, PyObject* other) { |
| // Check the identity of C++ pointers. |
| if (PyObject_TypeCheck(other, &DescriptorSequence_Type)) { |
| PyContainer* other_container = reinterpret_cast<PyContainer*>(other); |
| if (self->descriptor == other_container->descriptor && |
| self->container_def == other_container->container_def && |
| self->kind == other_container->kind) { |
| return 1; |
| } else { |
| return 0; |
| } |
| } |
| |
| // If other is a list |
| if (PyList_Check(other)) { |
| // return list(self) == other |
| int size = Length(self); |
| if (size != PyList_Size(other)) { |
| return false; |
| } |
| for (int index = 0; index < size; index++) { |
| ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index)); |
| if (value1 == NULL) { |
| return -1; |
| } |
| PyObject* value2 = PyList_GetItem(other, index); |
| if (value2 == NULL) { |
| return -1; |
| } |
| int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ); |
| if (cmp != 1) // error or not equal |
| return cmp; |
| } |
| // All items were found and equal |
| return 1; |
| } |
| |
| // Any other object is different. |
| return 0; |
| } |
| |
| // A mapping container can only be equal to another mapping container, or (for |
| // backward compatibility) to a dict containing the same items. |
| // Returns 1 if equal, 0 if unequal, -1 on error. |
| static int DescriptorMapping_Equal(PyContainer* self, PyObject* other) { |
| // Check the identity of C++ pointers. |
| if (PyObject_TypeCheck(other, &DescriptorMapping_Type)) { |
| PyContainer* other_container = reinterpret_cast<PyContainer*>(other); |
| if (self->descriptor == other_container->descriptor && |
| self->container_def == other_container->container_def && |
| self->kind == other_container->kind) { |
| return 1; |
| } else { |
| return 0; |
| } |
| } |
| |
| // If other is a dict |
| if (PyDict_Check(other)) { |
| // equivalent to dict(self.items()) == other |
| int size = Length(self); |
| if (size != PyDict_Size(other)) { |
| return false; |
| } |
| for (int index = 0; index < size; index++) { |
| ScopedPyObjectPtr key(_NewKey_ByIndex(self, index)); |
| if (key == NULL) { |
| return -1; |
| } |
| ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index)); |
| if (value1 == NULL) { |
| return -1; |
| } |
| PyObject* value2 = PyDict_GetItem(other, key.get()); |
| if (value2 == NULL) { |
| // Not found in the other dictionary |
| return 0; |
| } |
| int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ); |
| if (cmp != 1) // error or not equal |
| return cmp; |
| } |
| // All items were found and equal |
| return 1; |
| } |
| |
| // Any other object is different. |
| return 0; |
| } |
| |
| static PyObject* RichCompare(PyContainer* self, PyObject* other, int opid) { |
| if (opid != Py_EQ && opid != Py_NE) { |
| Py_INCREF(Py_NotImplemented); |
| return Py_NotImplemented; |
| } |
| |
| int result; |
| |
| if (self->kind == PyContainer::KIND_SEQUENCE) { |
| result = DescriptorSequence_Equal(self, other); |
| } else { |
| result = DescriptorMapping_Equal(self, other); |
| } |
| if (result < 0) { |
| return NULL; |
| } |
| if (result ^ (opid == Py_NE)) { |
| Py_RETURN_TRUE; |
| } else { |
| Py_RETURN_FALSE; |
| } |
| } |
| |
| static PySequenceMethods MappingSequenceMethods = { |
| 0, // sq_length |
| 0, // sq_concat |
| 0, // sq_repeat |
| 0, // sq_item |
| 0, // sq_slice |
| 0, // sq_ass_item |
| 0, // sq_ass_slice |
| (objobjproc)Contains, // sq_contains |
| }; |
| |
| static PyObject* Get(PyContainer* self, PyObject* args) { |
| PyObject* key; |
| PyObject* default_value = Py_None; |
| if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_value)) { |
| return NULL; |
| } |
| |
| const void* item; |
| if (!_GetItemByKey(self, key, &item)) { |
| return NULL; |
| } |
| if (item == NULL) { |
| Py_INCREF(default_value); |
| return default_value; |
| } |
| return self->container_def->new_object_from_item_fn(item); |
| } |
| |
| static PyObject* Keys(PyContainer* self, PyObject* args) { |
| Py_ssize_t count = Length(self); |
| ScopedPyObjectPtr list(PyList_New(count)); |
| if (list == NULL) { |
| return NULL; |
| } |
| for (Py_ssize_t index = 0; index < count; ++index) { |
| PyObject* key = _NewKey_ByIndex(self, index); |
| if (key == NULL) { |
| return NULL; |
| } |
| PyList_SET_ITEM(list.get(), index, key); |
| } |
| return list.release(); |
| } |
| |
| static PyObject* Values(PyContainer* self, PyObject* args) { |
| Py_ssize_t count = Length(self); |
| ScopedPyObjectPtr list(PyList_New(count)); |
| if (list == NULL) { |
| return NULL; |
| } |
| for (Py_ssize_t index = 0; index < count; ++index) { |
| PyObject* value = _NewObj_ByIndex(self, index); |
| if (value == NULL) { |
| return NULL; |
| } |
| PyList_SET_ITEM(list.get(), index, value); |
| } |
| return list.release(); |
| } |
| |
| static PyObject* Items(PyContainer* self, PyObject* args) { |
| Py_ssize_t count = Length(self); |
| ScopedPyObjectPtr list(PyList_New(count)); |
| if (list == NULL) { |
| return NULL; |
| } |
| for (Py_ssize_t index = 0; index < count; ++index) { |
| ScopedPyObjectPtr obj(PyTuple_New(2)); |
| if (obj == NULL) { |
| return NULL; |
| } |
| PyObject* key = _NewKey_ByIndex(self, index); |
| if (key == NULL) { |
| return NULL; |
| } |
| PyTuple_SET_ITEM(obj.get(), 0, key); |
| PyObject* value = _NewObj_ByIndex(self, index); |
| if (value == NULL) { |
| return NULL; |
| } |
| PyTuple_SET_ITEM(obj.get(), 1, value); |
| PyList_SET_ITEM(list.get(), index, obj.release()); |
| } |
| return list.release(); |
| } |
| |
| static PyObject* NewContainerIterator(PyContainer* mapping, |
| PyContainerIterator::IterKind kind); |
| |
| static PyObject* Iter(PyContainer* self) { |
| return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY); |
| } |
| static PyObject* IterKeys(PyContainer* self, PyObject* args) { |
| return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY); |
| } |
| static PyObject* IterValues(PyContainer* self, PyObject* args) { |
| return NewContainerIterator(self, PyContainerIterator::KIND_ITERVALUE); |
| } |
| static PyObject* IterItems(PyContainer* self, PyObject* args) { |
| return NewContainerIterator(self, PyContainerIterator::KIND_ITERITEM); |
| } |
| |
| static PyMethodDef MappingMethods[] = { |
| { "get", (PyCFunction)Get, METH_VARARGS, }, |
| { "keys", (PyCFunction)Keys, METH_NOARGS, }, |
| { "values", (PyCFunction)Values, METH_NOARGS, }, |
| { "items", (PyCFunction)Items, METH_NOARGS, }, |
| { "iterkeys", (PyCFunction)IterKeys, METH_NOARGS, }, |
| { "itervalues", (PyCFunction)IterValues, METH_NOARGS, }, |
| { "iteritems", (PyCFunction)IterItems, METH_NOARGS, }, |
| {NULL} |
| }; |
| |
| PyTypeObject DescriptorMapping_Type = { |
| PyVarObject_HEAD_INIT(&PyType_Type, 0) |
| "DescriptorMapping", // tp_name |
| sizeof(PyContainer), // tp_basicsize |
| 0, // tp_itemsize |
| 0, // tp_dealloc |
| 0, // tp_print |
| 0, // tp_getattr |
| 0, // tp_setattr |
| 0, // tp_compare |
| (reprfunc)ContainerRepr, // tp_repr |
| 0, // tp_as_number |
| &MappingSequenceMethods, // tp_as_sequence |
| &MappingMappingMethods, // tp_as_mapping |
| 0, // tp_hash |
| 0, // tp_call |
| 0, // tp_str |
| 0, // tp_getattro |
| 0, // tp_setattro |
| 0, // tp_as_buffer |
| Py_TPFLAGS_DEFAULT, // tp_flags |
| 0, // tp_doc |
| 0, // tp_traverse |
| 0, // tp_clear |
| (richcmpfunc)RichCompare, // tp_richcompare |
| 0, // tp_weaklistoffset |
| (getiterfunc)Iter, // tp_iter |
| 0, // tp_iternext |
| MappingMethods, // tp_methods |
| 0, // tp_members |
| 0, // tp_getset |
| 0, // tp_base |
| 0, // tp_dict |
| 0, // tp_descr_get |
| 0, // tp_descr_set |
| 0, // tp_dictoffset |
| 0, // tp_init |
| 0, // tp_alloc |
| 0, // tp_new |
| 0, // tp_free |
| }; |
| |
| // The DescriptorSequence type. |
| |
| static PyObject* GetItem(PyContainer* self, Py_ssize_t index) { |
| if (index < 0) { |
| index += Length(self); |
| } |
| if (index < 0 || index >= Length(self)) { |
| PyErr_SetString(PyExc_IndexError, "index out of range"); |
| return NULL; |
| } |
| return _NewObj_ByIndex(self, index); |
| } |
| |
| // Returns the position of the item in the sequence, of -1 if not found. |
| // This function never fails. |
| int Find(PyContainer* self, PyObject* item) { |
| // The item can only be in one position: item.index. |
| // Check that self[item.index] == item, it's faster than a linear search. |
| // |
| // This assumes that sequences are only defined by syntax of the .proto file: |
| // a specific item belongs to only one sequence, depending on its position in |
| // the .proto file definition. |
| const void* descriptor_ptr = PyDescriptor_AsVoidPtr(item); |
| if (descriptor_ptr == NULL) { |
| // Not a descriptor, it cannot be in the list. |
| return -1; |
| } |
| if (self->container_def->get_item_index_fn) { |
| int index = self->container_def->get_item_index_fn(descriptor_ptr); |
| if (index < 0 || index >= Length(self)) { |
| // This index is not from this collection. |
| return -1; |
| } |
| if (self->container_def->get_by_index_fn(self, index) != descriptor_ptr) { |
| // The descriptor at this index is not the same. |
| return -1; |
| } |
| // self[item.index] == item, so return the index. |
| return index; |
| } else { |
| // Fall back to linear search. |
| int length = Length(self); |
| for (int index=0; index < length; index++) { |
| if (self->container_def->get_by_index_fn(self, index) == descriptor_ptr) { |
| return index; |
| } |
| } |
| // Not found |
| return -1; |
| } |
| } |
| |
| // Implements list.index(): the position of the item is in the sequence. |
| static PyObject* Index(PyContainer* self, PyObject* item) { |
| int position = Find(self, item); |
| if (position < 0) { |
| // Not found |
| PyErr_SetNone(PyExc_ValueError); |
| return NULL; |
| } else { |
| return PyInt_FromLong(position); |
| } |
| } |
| // Implements "list.__contains__()": is the object in the sequence. |
| static int SeqContains(PyContainer* self, PyObject* item) { |
| int position = Find(self, item); |
| if (position < 0) { |
| return 0; |
| } else { |
| return 1; |
| } |
| } |
| |
| // Implements list.count(): number of occurrences of the item in the sequence. |
| // An item can only appear once in a sequence. If it exists, return 1. |
| static PyObject* Count(PyContainer* self, PyObject* item) { |
| int position = Find(self, item); |
| if (position < 0) { |
| return PyInt_FromLong(0); |
| } else { |
| return PyInt_FromLong(1); |
| } |
| } |
| |
| static PyObject* Append(PyContainer* self, PyObject* args) { |
| if (_CalledFromGeneratedFile(0)) { |
| Py_RETURN_NONE; |
| } |
| PyErr_Format(PyExc_TypeError, |
| "'%.200s' object is not a mutable sequence", |
| Py_TYPE(self)->tp_name); |
| return NULL; |
| } |
| |
| static PyObject* Reversed(PyContainer* self, PyObject* args) { |
| return NewContainerIterator(self, |
| PyContainerIterator::KIND_ITERVALUE_REVERSED); |
| } |
| |
| static PyMethodDef SeqMethods[] = { |
| { "index", (PyCFunction)Index, METH_O, }, |
| { "count", (PyCFunction)Count, METH_O, }, |
| { "append", (PyCFunction)Append, METH_O, }, |
| { "__reversed__", (PyCFunction)Reversed, METH_NOARGS, }, |
| {NULL} |
| }; |
| |
| static PySequenceMethods SeqSequenceMethods = { |
| (lenfunc)Length, // sq_length |
| 0, // sq_concat |
| 0, // sq_repeat |
| (ssizeargfunc)GetItem, // sq_item |
| 0, // sq_slice |
| 0, // sq_ass_item |
| 0, // sq_ass_slice |
| (objobjproc)SeqContains, // sq_contains |
| }; |
| |
| PyTypeObject DescriptorSequence_Type = { |
| PyVarObject_HEAD_INIT(&PyType_Type, 0) |
| "DescriptorSequence", // tp_name |
| sizeof(PyContainer), // tp_basicsize |
| 0, // tp_itemsize |
| 0, // tp_dealloc |
| 0, // tp_print |
| 0, // tp_getattr |
| 0, // tp_setattr |
| 0, // tp_compare |
| (reprfunc)ContainerRepr, // tp_repr |
| 0, // tp_as_number |
| &SeqSequenceMethods, // tp_as_sequence |
| 0, // tp_as_mapping |
| 0, // tp_hash |
| 0, // tp_call |
| 0, // tp_str |
| 0, // tp_getattro |
| 0, // tp_setattro |
| 0, // tp_as_buffer |
| Py_TPFLAGS_DEFAULT, // tp_flags |
| 0, // tp_doc |
| 0, // tp_traverse |
| 0, // tp_clear |
| (richcmpfunc)RichCompare, // tp_richcompare |
| 0, // tp_weaklistoffset |
| 0, // tp_iter |
| 0, // tp_iternext |
| SeqMethods, // tp_methods |
| 0, // tp_members |
| 0, // tp_getset |
| 0, // tp_base |
| 0, // tp_dict |
| 0, // tp_descr_get |
| 0, // tp_descr_set |
| 0, // tp_dictoffset |
| 0, // tp_init |
| 0, // tp_alloc |
| 0, // tp_new |
| 0, // tp_free |
| }; |
| |
| static PyObject* NewMappingByName( |
| DescriptorContainerDef* container_def, const void* descriptor) { |
| PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type); |
| if (self == NULL) { |
| return NULL; |
| } |
| self->descriptor = descriptor; |
| self->container_def = container_def; |
| self->kind = PyContainer::KIND_BYNAME; |
| return reinterpret_cast<PyObject*>(self); |
| } |
| |
| static PyObject* NewMappingByCamelcaseName( |
| DescriptorContainerDef* container_def, const void* descriptor) { |
| PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type); |
| if (self == NULL) { |
| return NULL; |
| } |
| self->descriptor = descriptor; |
| self->container_def = container_def; |
| self->kind = PyContainer::KIND_BYCAMELCASENAME; |
| return reinterpret_cast<PyObject*>(self); |
| } |
| |
| static PyObject* NewMappingByNumber( |
| DescriptorContainerDef* container_def, const void* descriptor) { |
| if (container_def->get_by_number_fn == NULL || |
| container_def->get_item_number_fn == NULL) { |
| PyErr_SetNone(PyExc_NotImplementedError); |
| return NULL; |
| } |
| PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type); |
| if (self == NULL) { |
| return NULL; |
| } |
| self->descriptor = descriptor; |
| self->container_def = container_def; |
| self->kind = PyContainer::KIND_BYNUMBER; |
| return reinterpret_cast<PyObject*>(self); |
| } |
| |
| static PyObject* NewSequence( |
| DescriptorContainerDef* container_def, const void* descriptor) { |
| PyContainer* self = PyObject_New(PyContainer, &DescriptorSequence_Type); |
| if (self == NULL) { |
| return NULL; |
| } |
| self->descriptor = descriptor; |
| self->container_def = container_def; |
| self->kind = PyContainer::KIND_SEQUENCE; |
| return reinterpret_cast<PyObject*>(self); |
| } |
| |
| // Implement iterators over PyContainers. |
| |
| static void Iterator_Dealloc(PyContainerIterator* self) { |
| Py_CLEAR(self->container); |
| Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); |
| } |
| |
| static PyObject* Iterator_Next(PyContainerIterator* self) { |
| int count = self->container->container_def->count_fn(self->container); |
| if (self->index >= count) { |
| // Return NULL with no exception to indicate the end. |
| return NULL; |
| } |
| int index = self->index; |
| self->index += 1; |
| switch (self->kind) { |
| case PyContainerIterator::KIND_ITERKEY: |
| return _NewKey_ByIndex(self->container, index); |
| case PyContainerIterator::KIND_ITERVALUE: |
| return _NewObj_ByIndex(self->container, index); |
| case PyContainerIterator::KIND_ITERVALUE_REVERSED: |
| return _NewObj_ByIndex(self->container, count - index - 1); |
| case PyContainerIterator::KIND_ITERITEM: |
| { |
| PyObject* obj = PyTuple_New(2); |
| if (obj == NULL) { |
| return NULL; |
| } |
| PyObject* key = _NewKey_ByIndex(self->container, index); |
| if (key == NULL) { |
| Py_DECREF(obj); |
| return NULL; |
| } |
| PyTuple_SET_ITEM(obj, 0, key); |
| PyObject* value = _NewObj_ByIndex(self->container, index); |
| if (value == NULL) { |
| Py_DECREF(obj); |
| return NULL; |
| } |
| PyTuple_SET_ITEM(obj, 1, value); |
| return obj; |
| } |
| default: |
| PyErr_SetNone(PyExc_NotImplementedError); |
| return NULL; |
| } |
| } |
| |
| static PyTypeObject ContainerIterator_Type = { |
| PyVarObject_HEAD_INIT(&PyType_Type, 0) |
| "DescriptorContainerIterator", // tp_name |
| sizeof(PyContainerIterator), // tp_basicsize |
| 0, // tp_itemsize |
| (destructor)Iterator_Dealloc, // tp_dealloc |
| 0, // tp_print |
| 0, // tp_getattr |
| 0, // tp_setattr |
| 0, // tp_compare |
| 0, // tp_repr |
| 0, // tp_as_number |
| 0, // tp_as_sequence |
| 0, // tp_as_mapping |
| 0, // tp_hash |
| 0, // tp_call |
| 0, // tp_str |
| 0, // tp_getattro |
| 0, // tp_setattro |
| 0, // tp_as_buffer |
| Py_TPFLAGS_DEFAULT, // tp_flags |
| 0, // tp_doc |
| 0, // tp_traverse |
| 0, // tp_clear |
| 0, // tp_richcompare |
| 0, // tp_weaklistoffset |
| PyObject_SelfIter, // tp_iter |
| (iternextfunc)Iterator_Next, // tp_iternext |
| 0, // tp_methods |
| 0, // tp_members |
| 0, // tp_getset |
| 0, // tp_base |
| 0, // tp_dict |
| 0, // tp_descr_get |
| 0, // tp_descr_set |
| 0, // tp_dictoffset |
| 0, // tp_init |
| 0, // tp_alloc |
| 0, // tp_new |
| 0, // tp_free |
| }; |
| |
| static PyObject* NewContainerIterator(PyContainer* container, |
| PyContainerIterator::IterKind kind) { |
| PyContainerIterator* self = PyObject_New(PyContainerIterator, |
| &ContainerIterator_Type); |
| if (self == NULL) { |
| return NULL; |
| } |
| Py_INCREF(container); |
| self->container = container; |
| self->kind = kind; |
| self->index = 0; |
| |
| return reinterpret_cast<PyObject*>(self); |
| } |
| |
| } // namespace descriptor |
| |
| // Now define the real collections! |
| |
| namespace message_descriptor { |
| |
| typedef const Descriptor* ParentDescriptor; |
| |
| static ParentDescriptor GetDescriptor(PyContainer* self) { |
| return reinterpret_cast<ParentDescriptor>(self->descriptor); |
| } |
| |
| namespace fields { |
| |
| typedef const FieldDescriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->field_count(); |
| } |
| |
| static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| return GetDescriptor(self)->FindFieldByName(name); |
| } |
| |
| static ItemDescriptor GetByCamelcaseName(PyContainer* self, |
| const string& name) { |
| return GetDescriptor(self)->FindFieldByCamelcaseName(name); |
| } |
| |
| static ItemDescriptor GetByNumber(PyContainer* self, int number) { |
| return GetDescriptor(self)->FindFieldByNumber(number); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->field(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyFieldDescriptor_FromDescriptor(item); |
| } |
| |
| static const string& GetItemName(ItemDescriptor item) { |
| return item->name(); |
| } |
| |
| static const string& GetItemCamelcaseName(ItemDescriptor item) { |
| return item->camelcase_name(); |
| } |
| |
| static int GetItemNumber(ItemDescriptor item) { |
| return item->number(); |
| } |
| |
| static int GetItemIndex(ItemDescriptor item) { |
| return item->index(); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "MessageFields", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)GetByName, |
| (GetByCamelcaseNameMethod)GetByCamelcaseName, |
| (GetByNumberMethod)GetByNumber, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)GetItemName, |
| (GetItemCamelcaseNameMethod)GetItemCamelcaseName, |
| (GetItemNumberMethod)GetItemNumber, |
| (GetItemIndexMethod)GetItemIndex, |
| }; |
| |
| } // namespace fields |
| |
| PyObject* NewMessageFieldsByName(ParentDescriptor descriptor) { |
| return descriptor::NewMappingByName(&fields::ContainerDef, descriptor); |
| } |
| |
| PyObject* NewMessageFieldsByCamelcaseName(ParentDescriptor descriptor) { |
| return descriptor::NewMappingByCamelcaseName(&fields::ContainerDef, |
| descriptor); |
| } |
| |
| PyObject* NewMessageFieldsByNumber(ParentDescriptor descriptor) { |
| return descriptor::NewMappingByNumber(&fields::ContainerDef, descriptor); |
| } |
| |
| PyObject* NewMessageFieldsSeq(ParentDescriptor descriptor) { |
| return descriptor::NewSequence(&fields::ContainerDef, descriptor); |
| } |
| |
| namespace nested_types { |
| |
| typedef const Descriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->nested_type_count(); |
| } |
| |
| static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| return GetDescriptor(self)->FindNestedTypeByName(name); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->nested_type(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyMessageDescriptor_FromDescriptor(item); |
| } |
| |
| static const string& GetItemName(ItemDescriptor item) { |
| return item->name(); |
| } |
| |
| static int GetItemIndex(ItemDescriptor item) { |
| return item->index(); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "MessageNestedTypes", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)GetByName, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)NULL, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)GetItemName, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)NULL, |
| (GetItemIndexMethod)GetItemIndex, |
| }; |
| |
| } // namespace nested_types |
| |
| PyObject* NewMessageNestedTypesSeq(ParentDescriptor descriptor) { |
| return descriptor::NewSequence(&nested_types::ContainerDef, descriptor); |
| } |
| |
| PyObject* NewMessageNestedTypesByName(ParentDescriptor descriptor) { |
| return descriptor::NewMappingByName(&nested_types::ContainerDef, descriptor); |
| } |
| |
| namespace enums { |
| |
| typedef const EnumDescriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->enum_type_count(); |
| } |
| |
| static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| return GetDescriptor(self)->FindEnumTypeByName(name); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->enum_type(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyEnumDescriptor_FromDescriptor(item); |
| } |
| |
| static const string& GetItemName(ItemDescriptor item) { |
| return item->name(); |
| } |
| |
| static int GetItemIndex(ItemDescriptor item) { |
| return item->index(); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "MessageNestedEnums", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)GetByName, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)NULL, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)GetItemName, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)NULL, |
| (GetItemIndexMethod)GetItemIndex, |
| }; |
| |
| } // namespace enums |
| |
| PyObject* NewMessageEnumsByName(ParentDescriptor descriptor) { |
| return descriptor::NewMappingByName(&enums::ContainerDef, descriptor); |
| } |
| |
| PyObject* NewMessageEnumsSeq(ParentDescriptor descriptor) { |
| return descriptor::NewSequence(&enums::ContainerDef, descriptor); |
| } |
| |
| namespace enumvalues { |
| |
| // This is the "enum_values_by_name" mapping, which collects values from all |
| // enum types in a message. |
| // |
| // Note that the behavior of the C++ descriptor is different: it will search and |
| // return the first value that matches the name, whereas the Python |
| // implementation retrieves the last one. |
| |
| typedef const EnumValueDescriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| int count = 0; |
| for (int i = 0; i < GetDescriptor(self)->enum_type_count(); ++i) { |
| count += GetDescriptor(self)->enum_type(i)->value_count(); |
| } |
| return count; |
| } |
| |
| static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| return GetDescriptor(self)->FindEnumValueByName(name); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| // This is not optimal, but the number of enums *types* in a given message |
| // is small. This function is only used when iterating over the mapping. |
| const EnumDescriptor* enum_type = NULL; |
| int enum_type_count = GetDescriptor(self)->enum_type_count(); |
| for (int i = 0; i < enum_type_count; ++i) { |
| enum_type = GetDescriptor(self)->enum_type(i); |
| int enum_value_count = enum_type->value_count(); |
| if (index < enum_value_count) { |
| // Found it! |
| break; |
| } |
| index -= enum_value_count; |
| } |
| // The next statement cannot overflow, because this function is only called by |
| // internal iterators which ensure that 0 <= index < Count(). |
| return enum_type->value(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyEnumValueDescriptor_FromDescriptor(item); |
| } |
| |
| static const string& GetItemName(ItemDescriptor item) { |
| return item->name(); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "MessageEnumValues", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)GetByName, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)NULL, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)GetItemName, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)NULL, |
| (GetItemIndexMethod)NULL, |
| }; |
| |
| } // namespace enumvalues |
| |
| PyObject* NewMessageEnumValuesByName(ParentDescriptor descriptor) { |
| return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor); |
| } |
| |
| namespace extensions { |
| |
| typedef const FieldDescriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->extension_count(); |
| } |
| |
| static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| return GetDescriptor(self)->FindExtensionByName(name); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->extension(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyFieldDescriptor_FromDescriptor(item); |
| } |
| |
| static const string& GetItemName(ItemDescriptor item) { |
| return item->name(); |
| } |
| |
| static int GetItemIndex(ItemDescriptor item) { |
| return item->index(); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "MessageExtensions", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)GetByName, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)NULL, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)GetItemName, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)NULL, |
| (GetItemIndexMethod)GetItemIndex, |
| }; |
| |
| } // namespace extensions |
| |
| PyObject* NewMessageExtensionsByName(ParentDescriptor descriptor) { |
| return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor); |
| } |
| |
| PyObject* NewMessageExtensionsSeq(ParentDescriptor descriptor) { |
| return descriptor::NewSequence(&extensions::ContainerDef, descriptor); |
| } |
| |
| namespace oneofs { |
| |
| typedef const OneofDescriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->oneof_decl_count(); |
| } |
| |
| static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| return GetDescriptor(self)->FindOneofByName(name); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->oneof_decl(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyOneofDescriptor_FromDescriptor(item); |
| } |
| |
| static const string& GetItemName(ItemDescriptor item) { |
| return item->name(); |
| } |
| |
| static int GetItemIndex(ItemDescriptor item) { |
| return item->index(); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "MessageOneofs", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)GetByName, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)NULL, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)GetItemName, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)NULL, |
| (GetItemIndexMethod)GetItemIndex, |
| }; |
| |
| } // namespace oneofs |
| |
| PyObject* NewMessageOneofsByName(ParentDescriptor descriptor) { |
| return descriptor::NewMappingByName(&oneofs::ContainerDef, descriptor); |
| } |
| |
| PyObject* NewMessageOneofsSeq(ParentDescriptor descriptor) { |
| return descriptor::NewSequence(&oneofs::ContainerDef, descriptor); |
| } |
| |
| } // namespace message_descriptor |
| |
| namespace enum_descriptor { |
| |
| typedef const EnumDescriptor* ParentDescriptor; |
| |
| static ParentDescriptor GetDescriptor(PyContainer* self) { |
| return reinterpret_cast<ParentDescriptor>(self->descriptor); |
| } |
| |
| namespace enumvalues { |
| |
| typedef const EnumValueDescriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->value_count(); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->value(index); |
| } |
| |
| static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| return GetDescriptor(self)->FindValueByName(name); |
| } |
| |
| static ItemDescriptor GetByNumber(PyContainer* self, int number) { |
| return GetDescriptor(self)->FindValueByNumber(number); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyEnumValueDescriptor_FromDescriptor(item); |
| } |
| |
| static const string& GetItemName(ItemDescriptor item) { |
| return item->name(); |
| } |
| |
| static int GetItemNumber(ItemDescriptor item) { |
| return item->number(); |
| } |
| |
| static int GetItemIndex(ItemDescriptor item) { |
| return item->index(); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "EnumValues", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)GetByName, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)GetByNumber, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)GetItemName, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)GetItemNumber, |
| (GetItemIndexMethod)GetItemIndex, |
| }; |
| |
| } // namespace enumvalues |
| |
| PyObject* NewEnumValuesByName(ParentDescriptor descriptor) { |
| return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor); |
| } |
| |
| PyObject* NewEnumValuesByNumber(ParentDescriptor descriptor) { |
| return descriptor::NewMappingByNumber(&enumvalues::ContainerDef, descriptor); |
| } |
| |
| PyObject* NewEnumValuesSeq(ParentDescriptor descriptor) { |
| return descriptor::NewSequence(&enumvalues::ContainerDef, descriptor); |
| } |
| |
| } // namespace enum_descriptor |
| |
| namespace oneof_descriptor { |
| |
| typedef const OneofDescriptor* ParentDescriptor; |
| |
| static ParentDescriptor GetDescriptor(PyContainer* self) { |
| return reinterpret_cast<ParentDescriptor>(self->descriptor); |
| } |
| |
| namespace fields { |
| |
| typedef const FieldDescriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->field_count(); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->field(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyFieldDescriptor_FromDescriptor(item); |
| } |
| |
| static int GetItemIndex(ItemDescriptor item) { |
| return item->index_in_oneof(); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "OneofFields", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)NULL, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)NULL, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)NULL, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)NULL, |
| (GetItemIndexMethod)GetItemIndex, |
| }; |
| |
| } // namespace fields |
| |
| PyObject* NewOneofFieldsSeq(ParentDescriptor descriptor) { |
| return descriptor::NewSequence(&fields::ContainerDef, descriptor); |
| } |
| |
| } // namespace oneof_descriptor |
| |
| namespace file_descriptor { |
| |
| typedef const FileDescriptor* ParentDescriptor; |
| |
| static ParentDescriptor GetDescriptor(PyContainer* self) { |
| return reinterpret_cast<ParentDescriptor>(self->descriptor); |
| } |
| |
| namespace messages { |
| |
| typedef const Descriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->message_type_count(); |
| } |
| |
| static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| return GetDescriptor(self)->FindMessageTypeByName(name); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->message_type(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyMessageDescriptor_FromDescriptor(item); |
| } |
| |
| static const string& GetItemName(ItemDescriptor item) { |
| return item->name(); |
| } |
| |
| static int GetItemIndex(ItemDescriptor item) { |
| return item->index(); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "FileMessages", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)GetByName, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)NULL, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)GetItemName, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)NULL, |
| (GetItemIndexMethod)GetItemIndex, |
| }; |
| |
| } // namespace messages |
| |
| PyObject* NewFileMessageTypesByName(const FileDescriptor* descriptor) { |
| return descriptor::NewMappingByName(&messages::ContainerDef, descriptor); |
| } |
| |
| namespace enums { |
| |
| typedef const EnumDescriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->enum_type_count(); |
| } |
| |
| static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| return GetDescriptor(self)->FindEnumTypeByName(name); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->enum_type(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyEnumDescriptor_FromDescriptor(item); |
| } |
| |
| static const string& GetItemName(ItemDescriptor item) { |
| return item->name(); |
| } |
| |
| static int GetItemIndex(ItemDescriptor item) { |
| return item->index(); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "FileEnums", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)GetByName, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)NULL, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)GetItemName, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)NULL, |
| (GetItemIndexMethod)GetItemIndex, |
| }; |
| |
| } // namespace enums |
| |
| PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor) { |
| return descriptor::NewMappingByName(&enums::ContainerDef, descriptor); |
| } |
| |
| namespace extensions { |
| |
| typedef const FieldDescriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->extension_count(); |
| } |
| |
| static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| return GetDescriptor(self)->FindExtensionByName(name); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->extension(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyFieldDescriptor_FromDescriptor(item); |
| } |
| |
| static const string& GetItemName(ItemDescriptor item) { |
| return item->name(); |
| } |
| |
| static int GetItemIndex(ItemDescriptor item) { |
| return item->index(); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "FileExtensions", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)GetByName, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)NULL, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)GetItemName, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)NULL, |
| (GetItemIndexMethod)GetItemIndex, |
| }; |
| |
| } // namespace extensions |
| |
| PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor) { |
| return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor); |
| } |
| |
| namespace dependencies { |
| |
| typedef const FileDescriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->dependency_count(); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->dependency(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyFileDescriptor_FromDescriptor(item); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "FileDependencies", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)NULL, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)NULL, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)NULL, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)NULL, |
| (GetItemIndexMethod)NULL, |
| }; |
| |
| } // namespace dependencies |
| |
| PyObject* NewFileDependencies(const FileDescriptor* descriptor) { |
| return descriptor::NewSequence(&dependencies::ContainerDef, descriptor); |
| } |
| |
| namespace public_dependencies { |
| |
| typedef const FileDescriptor* ItemDescriptor; |
| |
| static int Count(PyContainer* self) { |
| return GetDescriptor(self)->public_dependency_count(); |
| } |
| |
| static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| return GetDescriptor(self)->public_dependency(index); |
| } |
| |
| static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| return PyFileDescriptor_FromDescriptor(item); |
| } |
| |
| static DescriptorContainerDef ContainerDef = { |
| "FilePublicDependencies", |
| (CountMethod)Count, |
| (GetByIndexMethod)GetByIndex, |
| (GetByNameMethod)NULL, |
| (GetByCamelcaseNameMethod)NULL, |
| (GetByNumberMethod)NULL, |
| (NewObjectFromItemMethod)NewObjectFromItem, |
| (GetItemNameMethod)NULL, |
| (GetItemCamelcaseNameMethod)NULL, |
| (GetItemNumberMethod)NULL, |
| (GetItemIndexMethod)NULL, |
| }; |
| |
| } // namespace public_dependencies |
| |
| PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor) { |
| return descriptor::NewSequence(&public_dependencies::ContainerDef, |
| descriptor); |
| } |
| |
| } // namespace file_descriptor |
| |
| |
| // Register all implementations |
| |
| bool InitDescriptorMappingTypes() { |
| if (PyType_Ready(&descriptor::DescriptorMapping_Type) < 0) |
| return false; |
| if (PyType_Ready(&descriptor::DescriptorSequence_Type) < 0) |
| return false; |
| if (PyType_Ready(&descriptor::ContainerIterator_Type) < 0) |
| return false; |
| return true; |
| } |
| |
| } // namespace python |
| } // namespace protobuf |
| } // namespace google |