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..e505d8122c454202f92c95b457806b9514bd6f7d |
--- /dev/null |
+++ b/third_party/protobuf/python/google/protobuf/pyext/descriptor_containers.cc |
@@ -0,0 +1,1652 @@ |
+// 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 |