| Index: third_party/protobuf/python/google/protobuf/pyext/descriptor_containers.cc
|
| diff --git a/third_party/protobuf/python/google/protobuf/pyext/descriptor_containers.cc b/third_party/protobuf/python/google/protobuf/pyext/descriptor_containers.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..92e11e31220109675b4aa9b7601340da0df4f056
|
| --- /dev/null
|
| +++ b/third_party/protobuf/python/google/protobuf/pyext/descriptor_containers.cc
|
| @@ -0,0 +1,1564 @@
|
| +// 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* (*GetByNumberMethod)(PyContainer* self, int index);
|
| +typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor);
|
| +typedef const string& (*GetItemNameMethod)(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 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 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_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_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_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_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, 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);
|
| + if (value2 == NULL) {
|
| + // Not found in the other dictionary
|
| + return 0;
|
| + }
|
| + int cmp = PyObject_RichCompareBool(value1, 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* 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 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 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,
|
| + (GetByNumberMethod)GetByNumber,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)GetItemName,
|
| + (GetItemNumberMethod)GetItemNumber,
|
| + (GetItemIndexMethod)GetItemIndex,
|
| +};
|
| +
|
| +} // namespace fields
|
| +
|
| +PyObject* NewMessageFieldsByName(ParentDescriptor descriptor) {
|
| + return descriptor::NewMappingByName(&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,
|
| + (GetByNumberMethod)NULL,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)GetItemName,
|
| + (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,
|
| + (GetByNumberMethod)NULL,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)GetItemName,
|
| + (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,
|
| + (GetByNumberMethod)NULL,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)GetItemName,
|
| + (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,
|
| + (GetByNumberMethod)NULL,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)GetItemName,
|
| + (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,
|
| + (GetByNumberMethod)NULL,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)GetItemName,
|
| + (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,
|
| + (GetByNumberMethod)GetByNumber,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)GetItemName,
|
| + (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,
|
| + (GetByNumberMethod)NULL,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)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,
|
| + (GetByNumberMethod)NULL,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)GetItemName,
|
| + (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,
|
| + (GetByNumberMethod)NULL,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)GetItemName,
|
| + (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,
|
| + (GetByNumberMethod)NULL,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)GetItemName,
|
| + (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,
|
| + (GetByNumberMethod)NULL,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)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,
|
| + (GetByNumberMethod)NULL,
|
| + (NewObjectFromItemMethod)NewObjectFromItem,
|
| + (GetItemNameMethod)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
|
|
|