Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1696 lines
53 KiB
1696 lines
53 KiB
// 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 |
|
// net/proto2/public/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. |
|
|
|
// clang-format off |
|
#define PY_SSIZE_T_CLEAN |
|
// This inclusion must appear before all the others. |
|
#include <Python.h> |
|
|
|
#include <string> |
|
|
|
#include "google/protobuf/pyext/descriptor_containers.h" |
|
// clang-format on |
|
|
|
#include "google/protobuf/descriptor.h" |
|
#include "google/protobuf/pyext/descriptor.h" |
|
#include "google/protobuf/pyext/descriptor_pool.h" |
|
#include "google/protobuf/pyext/scoped_pyobject_ptr.h" |
|
#include "absl/strings/string_view.h" |
|
|
|
#define PyString_AsStringAndSize(ob, charpp, sizep) \ |
|
(PyUnicode_Check(ob) \ |
|
? ((*(charpp) = const_cast<char*>( \ |
|
PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \ |
|
? -1 \ |
|
: 0) \ |
|
: PyBytes_AsStringAndSize(ob, (charpp), (sizep))) |
|
|
|
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, |
|
absl::string_view name); |
|
typedef const void* (*GetByCamelcaseNameMethod)(PyContainer* self, |
|
absl::string_view name); |
|
typedef const void* (*GetByNumberMethod)(PyContainer* self, int index); |
|
typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor); |
|
typedef const std::string& (*GetItemNameMethod)(const void* descriptor); |
|
typedef const std::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 = nullptr; |
|
return true; |
|
} |
|
return false; |
|
} |
|
*item = self->container_def->get_by_name_fn( |
|
self, absl::string_view(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 = nullptr; |
|
return true; |
|
} |
|
return false; |
|
} |
|
*item = self->container_def->get_by_camelcase_name_fn( |
|
self, absl::string_view(camelcase_name, name_size)); |
|
return true; |
|
} |
|
case PyContainer::KIND_BYNUMBER: { |
|
Py_ssize_t number = PyNumber_AsSsize_t(key, nullptr); |
|
if (number == -1 && PyErr_Occurred()) { |
|
if (PyErr_ExceptionMatches(PyExc_TypeError)) { |
|
// Not a number, cannot be in the container. |
|
PyErr_Clear(); |
|
*item = nullptr; |
|
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 std::string& name(self->container_def->get_item_name_fn(item)); |
|
return PyUnicode_FromStringAndSize(name.c_str(), name.size()); |
|
} |
|
case PyContainer::KIND_BYCAMELCASENAME: { |
|
const std::string& name( |
|
self->container_def->get_item_camelcase_name_fn(item)); |
|
return PyUnicode_FromStringAndSize(name.c_str(), name.size()); |
|
} |
|
case PyContainer::KIND_BYNUMBER: { |
|
int value = self->container_def->get_item_number_fn(item); |
|
return PyLong_FromLong(value); |
|
} |
|
default: |
|
PyErr_SetNone(PyExc_NotImplementedError); |
|
return nullptr; |
|
} |
|
} |
|
|
|
// 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 = nullptr; |
|
if (!_GetItemByKey(self, key, &item)) { |
|
return nullptr; |
|
} |
|
if (!item) { |
|
PyErr_SetObject(PyExc_KeyError, key); |
|
return nullptr; |
|
} |
|
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 = nullptr; |
|
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 PyUnicode_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 == nullptr) { |
|
return -1; |
|
} |
|
PyObject* value2 = PyList_GetItem(other, index); |
|
if (value2 == nullptr) { |
|
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 == nullptr) { |
|
return -1; |
|
} |
|
ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index)); |
|
if (value1 == nullptr) { |
|
return -1; |
|
} |
|
PyObject* value2 = PyDict_GetItem(other, key.get()); |
|
if (value2 == nullptr) { |
|
// 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 nullptr; |
|
} |
|
if (result ^ (opid == Py_NE)) { |
|
Py_RETURN_TRUE; |
|
} else { |
|
Py_RETURN_FALSE; |
|
} |
|
} |
|
|
|
static PySequenceMethods MappingSequenceMethods = { |
|
nullptr, // sq_length |
|
nullptr, // sq_concat |
|
nullptr, // sq_repeat |
|
nullptr, // sq_item |
|
nullptr, // sq_slice |
|
nullptr, // sq_ass_item |
|
nullptr, // 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 nullptr; |
|
} |
|
|
|
const void* item; |
|
if (!_GetItemByKey(self, key, &item)) { |
|
return nullptr; |
|
} |
|
if (item == nullptr) { |
|
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 == nullptr) { |
|
return nullptr; |
|
} |
|
for (Py_ssize_t index = 0; index < count; ++index) { |
|
PyObject* key = _NewKey_ByIndex(self, index); |
|
if (key == nullptr) { |
|
return nullptr; |
|
} |
|
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 == nullptr) { |
|
return nullptr; |
|
} |
|
for (Py_ssize_t index = 0; index < count; ++index) { |
|
PyObject* value = _NewObj_ByIndex(self, index); |
|
if (value == nullptr) { |
|
return nullptr; |
|
} |
|
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 == nullptr) { |
|
return nullptr; |
|
} |
|
for (Py_ssize_t index = 0; index < count; ++index) { |
|
ScopedPyObjectPtr obj(PyTuple_New(2)); |
|
if (obj == nullptr) { |
|
return nullptr; |
|
} |
|
PyObject* key = _NewKey_ByIndex(self, index); |
|
if (key == nullptr) { |
|
return nullptr; |
|
} |
|
PyTuple_SET_ITEM(obj.get(), 0, key); |
|
PyObject* value = _NewObj_ByIndex(self, index); |
|
if (value == nullptr) { |
|
return nullptr; |
|
} |
|
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}, |
|
{nullptr}, |
|
}; |
|
|
|
PyTypeObject DescriptorMapping_Type = { |
|
PyVarObject_HEAD_INIT(&PyType_Type, 0) "DescriptorMapping", // tp_name |
|
sizeof(PyContainer), // tp_basicsize |
|
0, // tp_itemsize |
|
nullptr, // tp_dealloc |
|
#if PY_VERSION_HEX < 0x03080000 |
|
nullptr, // tp_print |
|
#else |
|
0, // tp_vectorcall_offset |
|
#endif |
|
nullptr, // tp_getattr |
|
nullptr, // tp_setattr |
|
nullptr, // tp_compare |
|
(reprfunc)ContainerRepr, // tp_repr |
|
nullptr, // tp_as_number |
|
&MappingSequenceMethods, // tp_as_sequence |
|
&MappingMappingMethods, // tp_as_mapping |
|
nullptr, // tp_hash |
|
nullptr, // tp_call |
|
nullptr, // tp_str |
|
nullptr, // tp_getattro |
|
nullptr, // tp_setattro |
|
nullptr, // tp_as_buffer |
|
Py_TPFLAGS_DEFAULT, // tp_flags |
|
nullptr, // tp_doc |
|
nullptr, // tp_traverse |
|
nullptr, // tp_clear |
|
(richcmpfunc)RichCompare, // tp_richcompare |
|
0, // tp_weaklistoffset |
|
(getiterfunc)Iter, // tp_iter |
|
nullptr, // tp_iternext |
|
MappingMethods, // tp_methods |
|
nullptr, // tp_members |
|
nullptr, // tp_getset |
|
nullptr, // tp_base |
|
nullptr, // tp_dict |
|
nullptr, // tp_descr_get |
|
nullptr, // tp_descr_set |
|
0, // tp_dictoffset |
|
nullptr, // tp_init |
|
nullptr, // tp_alloc |
|
nullptr, // tp_new |
|
nullptr, // 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 nullptr; |
|
} |
|
return _NewObj_ByIndex(self, index); |
|
} |
|
|
|
static PyObject * |
|
SeqSubscript(PyContainer* self, PyObject* item) { |
|
if (PyIndex_Check(item)) { |
|
Py_ssize_t index; |
|
index = PyNumber_AsSsize_t(item, PyExc_IndexError); |
|
if (index == -1 && PyErr_Occurred()) return nullptr; |
|
return GetItem(self, index); |
|
} |
|
// Materialize the list and delegate the operation to it. |
|
ScopedPyObjectPtr list(PyObject_CallFunctionObjArgs( |
|
reinterpret_cast<PyObject*>(&PyList_Type), self, nullptr)); |
|
if (list == nullptr) { |
|
return nullptr; |
|
} |
|
return Py_TYPE(list.get())->tp_as_mapping->mp_subscript(list.get(), item); |
|
} |
|
|
|
// 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 == nullptr) { |
|
PyErr_Clear(); |
|
// 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 nullptr; |
|
} else { |
|
return PyLong_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 PyLong_FromLong(0); |
|
} else { |
|
return PyLong_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 nullptr; |
|
} |
|
|
|
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}, |
|
{nullptr}, |
|
}; |
|
|
|
static PySequenceMethods SeqSequenceMethods = { |
|
(lenfunc)Length, // sq_length |
|
nullptr, // sq_concat |
|
nullptr, // sq_repeat |
|
(ssizeargfunc)GetItem, // sq_item |
|
nullptr, // sq_slice |
|
nullptr, // sq_ass_item |
|
nullptr, // sq_ass_slice |
|
(objobjproc)SeqContains, // sq_contains |
|
}; |
|
|
|
static PyMappingMethods SeqMappingMethods = { |
|
(lenfunc)Length, // mp_length |
|
(binaryfunc)SeqSubscript, // mp_subscript |
|
nullptr, // mp_ass_subscript |
|
}; |
|
|
|
PyTypeObject DescriptorSequence_Type = { |
|
PyVarObject_HEAD_INIT(&PyType_Type, 0) "DescriptorSequence", // tp_name |
|
sizeof(PyContainer), // tp_basicsize |
|
0, // tp_itemsize |
|
nullptr, // tp_dealloc |
|
#if PY_VERSION_HEX < 0x03080000 |
|
nullptr, // tp_print |
|
#else |
|
0, // tp_vectorcall_offset |
|
#endif |
|
nullptr, // tp_getattr |
|
nullptr, // tp_setattr |
|
nullptr, // tp_compare |
|
(reprfunc)ContainerRepr, // tp_repr |
|
nullptr, // tp_as_number |
|
&SeqSequenceMethods, // tp_as_sequence |
|
&SeqMappingMethods, // tp_as_mapping |
|
nullptr, // tp_hash |
|
nullptr, // tp_call |
|
nullptr, // tp_str |
|
nullptr, // tp_getattro |
|
nullptr, // tp_setattro |
|
nullptr, // tp_as_buffer |
|
Py_TPFLAGS_DEFAULT, // tp_flags |
|
nullptr, // tp_doc |
|
nullptr, // tp_traverse |
|
nullptr, // tp_clear |
|
(richcmpfunc)RichCompare, // tp_richcompare |
|
0, // tp_weaklistoffset |
|
nullptr, // tp_iter |
|
nullptr, // tp_iternext |
|
SeqMethods, // tp_methods |
|
nullptr, // tp_members |
|
nullptr, // tp_getset |
|
nullptr, // tp_base |
|
nullptr, // tp_dict |
|
nullptr, // tp_descr_get |
|
nullptr, // tp_descr_set |
|
0, // tp_dictoffset |
|
nullptr, // tp_init |
|
nullptr, // tp_alloc |
|
nullptr, // tp_new |
|
nullptr, // tp_free |
|
}; |
|
|
|
static PyObject* NewMappingByName( |
|
DescriptorContainerDef* container_def, const void* descriptor) { |
|
PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type); |
|
if (self == nullptr) { |
|
return nullptr; |
|
} |
|
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 == nullptr) { |
|
return nullptr; |
|
} |
|
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 == nullptr || |
|
container_def->get_item_number_fn == nullptr) { |
|
PyErr_SetNone(PyExc_NotImplementedError); |
|
return nullptr; |
|
} |
|
PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type); |
|
if (self == nullptr) { |
|
return nullptr; |
|
} |
|
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 == nullptr) { |
|
return nullptr; |
|
} |
|
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 nullptr; |
|
} |
|
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 == nullptr) { |
|
return nullptr; |
|
} |
|
PyObject* key = _NewKey_ByIndex(self->container, index); |
|
if (key == nullptr) { |
|
Py_DECREF(obj); |
|
return nullptr; |
|
} |
|
PyTuple_SET_ITEM(obj, 0, key); |
|
PyObject* value = _NewObj_ByIndex(self->container, index); |
|
if (value == nullptr) { |
|
Py_DECREF(obj); |
|
return nullptr; |
|
} |
|
PyTuple_SET_ITEM(obj, 1, value); |
|
return obj; |
|
} |
|
default: |
|
PyErr_SetNone(PyExc_NotImplementedError); |
|
return nullptr; |
|
} |
|
} |
|
|
|
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 |
|
#if PY_VERSION_HEX < 0x03080000 |
|
nullptr, // tp_print |
|
#else |
|
0, // tp_vectorcall_offset |
|
#endif |
|
nullptr, // tp_getattr |
|
nullptr, // tp_setattr |
|
nullptr, // tp_compare |
|
nullptr, // tp_repr |
|
nullptr, // tp_as_number |
|
nullptr, // tp_as_sequence |
|
nullptr, // tp_as_mapping |
|
nullptr, // tp_hash |
|
nullptr, // tp_call |
|
nullptr, // tp_str |
|
nullptr, // tp_getattro |
|
nullptr, // tp_setattro |
|
nullptr, // tp_as_buffer |
|
Py_TPFLAGS_DEFAULT, // tp_flags |
|
nullptr, // tp_doc |
|
nullptr, // tp_traverse |
|
nullptr, // tp_clear |
|
nullptr, // tp_richcompare |
|
0, // tp_weaklistoffset |
|
PyObject_SelfIter, // tp_iter |
|
(iternextfunc)Iterator_Next, // tp_iternext |
|
nullptr, // tp_methods |
|
nullptr, // tp_members |
|
nullptr, // tp_getset |
|
nullptr, // tp_base |
|
nullptr, // tp_dict |
|
nullptr, // tp_descr_get |
|
nullptr, // tp_descr_set |
|
0, // tp_dictoffset |
|
nullptr, // tp_init |
|
nullptr, // tp_alloc |
|
nullptr, // tp_new |
|
nullptr, // tp_free |
|
}; |
|
|
|
static PyObject* NewContainerIterator(PyContainer* container, |
|
PyContainerIterator::IterKind kind) { |
|
PyContainerIterator* self = PyObject_New(PyContainerIterator, |
|
&ContainerIterator_Type); |
|
if (self == nullptr) { |
|
return nullptr; |
|
} |
|
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 const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindFieldByName(name); |
|
} |
|
|
|
static const void* GetByCamelcaseName(PyContainer* self, |
|
absl::string_view name) { |
|
return GetDescriptor(self)->FindFieldByCamelcaseName(name); |
|
} |
|
|
|
static const void* GetByNumber(PyContainer* self, int number) { |
|
return GetDescriptor(self)->FindFieldByNumber(number); |
|
} |
|
|
|
static const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->field(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static const std::string& GetItemCamelcaseName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->camelcase_name(); |
|
} |
|
|
|
static int GetItemNumber(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->number(); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"MessageFields", Count, GetByIndex, GetByName, |
|
GetByCamelcaseName, GetByNumber, NewObjectFromItem, GetItemName, |
|
GetItemCamelcaseName, GetItemNumber, 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 const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindNestedTypeByName(name); |
|
} |
|
|
|
static const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->nested_type(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyMessageDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"MessageNestedTypes", |
|
Count, |
|
GetByIndex, |
|
GetByName, |
|
nullptr, |
|
nullptr, |
|
NewObjectFromItem, |
|
GetItemName, |
|
nullptr, |
|
nullptr, |
|
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 const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindEnumTypeByName(name); |
|
} |
|
|
|
static const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->enum_type(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyEnumDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"MessageNestedEnums", |
|
Count, |
|
GetByIndex, |
|
GetByName, |
|
nullptr, |
|
nullptr, |
|
NewObjectFromItem, |
|
GetItemName, |
|
nullptr, |
|
nullptr, |
|
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 const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindEnumValueByName(name); |
|
} |
|
|
|
static const void* 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 = nullptr; |
|
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(const void* item) { |
|
return PyEnumValueDescriptor_FromDescriptor( |
|
static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"MessageEnumValues", Count, GetByIndex, GetByName, nullptr, nullptr, |
|
NewObjectFromItem, GetItemName, nullptr, nullptr, nullptr, |
|
}; |
|
|
|
} // 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 const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindExtensionByName(name); |
|
} |
|
|
|
static const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->extension(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"MessageExtensions", |
|
Count, |
|
GetByIndex, |
|
GetByName, |
|
nullptr, |
|
nullptr, |
|
NewObjectFromItem, |
|
GetItemName, |
|
nullptr, |
|
nullptr, |
|
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 const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindOneofByName(name); |
|
} |
|
|
|
static const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->oneof_decl(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyOneofDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"MessageOneofs", Count, GetByIndex, GetByName, |
|
nullptr, nullptr, NewObjectFromItem, GetItemName, |
|
nullptr, nullptr, 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 const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->value(index); |
|
} |
|
|
|
static const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindValueByName(name); |
|
} |
|
|
|
static const void* GetByNumber(PyContainer* self, int number) { |
|
return GetDescriptor(self)->FindValueByNumber(number); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyEnumValueDescriptor_FromDescriptor( |
|
static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static int GetItemNumber(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->number(); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"EnumValues", Count, GetByIndex, GetByName, |
|
nullptr, GetByNumber, NewObjectFromItem, GetItemName, |
|
nullptr, GetItemNumber, 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 const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->field(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index_in_oneof(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"OneofFields", Count, GetByIndex, nullptr, nullptr, nullptr, |
|
NewObjectFromItem, nullptr, nullptr, nullptr, GetItemIndex, |
|
}; |
|
|
|
} // namespace fields |
|
|
|
PyObject* NewOneofFieldsSeq(ParentDescriptor descriptor) { |
|
return descriptor::NewSequence(&fields::ContainerDef, descriptor); |
|
} |
|
|
|
} // namespace oneof_descriptor |
|
|
|
namespace service_descriptor { |
|
|
|
typedef const ServiceDescriptor* ParentDescriptor; |
|
|
|
static ParentDescriptor GetDescriptor(PyContainer* self) { |
|
return reinterpret_cast<ParentDescriptor>(self->descriptor); |
|
} |
|
|
|
namespace methods { |
|
|
|
typedef const MethodDescriptor* ItemDescriptor; |
|
|
|
static int Count(PyContainer* self) { |
|
return GetDescriptor(self)->method_count(); |
|
} |
|
|
|
static const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindMethodByName(name); |
|
} |
|
|
|
static const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->method(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyMethodDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"ServiceMethods", Count, GetByIndex, GetByName, |
|
nullptr, nullptr, NewObjectFromItem, GetItemName, |
|
nullptr, nullptr, GetItemIndex, |
|
}; |
|
|
|
} // namespace methods |
|
|
|
PyObject* NewServiceMethodsSeq(ParentDescriptor descriptor) { |
|
return descriptor::NewSequence(&methods::ContainerDef, descriptor); |
|
} |
|
|
|
PyObject* NewServiceMethodsByName(ParentDescriptor descriptor) { |
|
return descriptor::NewMappingByName(&methods::ContainerDef, descriptor); |
|
} |
|
|
|
} // namespace service_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 const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindMessageTypeByName(name); |
|
} |
|
|
|
static const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->message_type(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyMessageDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"FileMessages", Count, GetByIndex, GetByName, |
|
nullptr, nullptr, NewObjectFromItem, GetItemName, |
|
nullptr, nullptr, GetItemIndex, |
|
}; |
|
|
|
} // namespace messages |
|
|
|
PyObject* NewFileMessageTypesByName(ParentDescriptor 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 const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindEnumTypeByName(name); |
|
} |
|
|
|
static const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->enum_type(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyEnumDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"FileEnums", Count, GetByIndex, GetByName, |
|
nullptr, nullptr, NewObjectFromItem, GetItemName, |
|
nullptr, nullptr, GetItemIndex, |
|
}; |
|
|
|
} // namespace enums |
|
|
|
PyObject* NewFileEnumTypesByName(ParentDescriptor descriptor) { |
|
return descriptor::NewMappingByName(&enums::ContainerDef, descriptor); |
|
} |
|
|
|
namespace extensions { |
|
|
|
typedef const FieldDescriptor* ItemDescriptor; |
|
|
|
static int Count(PyContainer* self) { |
|
return GetDescriptor(self)->extension_count(); |
|
} |
|
|
|
static const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindExtensionByName(name); |
|
} |
|
|
|
static const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->extension(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"FileExtensions", Count, GetByIndex, GetByName, |
|
nullptr, nullptr, NewObjectFromItem, GetItemName, |
|
nullptr, nullptr, GetItemIndex, |
|
}; |
|
|
|
} // namespace extensions |
|
|
|
PyObject* NewFileExtensionsByName(ParentDescriptor descriptor) { |
|
return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor); |
|
} |
|
|
|
namespace services { |
|
|
|
typedef const ServiceDescriptor* ItemDescriptor; |
|
|
|
static int Count(PyContainer* self) { |
|
return GetDescriptor(self)->service_count(); |
|
} |
|
|
|
static const void* GetByName(PyContainer* self, absl::string_view name) { |
|
return GetDescriptor(self)->FindServiceByName(name); |
|
} |
|
|
|
static const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->service(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyServiceDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static const std::string& GetItemName(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->name(); |
|
} |
|
|
|
static int GetItemIndex(const void* item) { |
|
return static_cast<ItemDescriptor>(item)->index(); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"FileServices", Count, GetByIndex, GetByName, |
|
nullptr, nullptr, NewObjectFromItem, GetItemName, |
|
nullptr, nullptr, GetItemIndex, |
|
}; |
|
|
|
} // namespace services |
|
|
|
PyObject* NewFileServicesByName(const FileDescriptor* descriptor) { |
|
return descriptor::NewMappingByName(&services::ContainerDef, descriptor); |
|
} |
|
|
|
namespace dependencies { |
|
|
|
typedef const FileDescriptor* ItemDescriptor; |
|
|
|
static int Count(PyContainer* self) { |
|
return GetDescriptor(self)->dependency_count(); |
|
} |
|
|
|
static const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->dependency(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyFileDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"FileDependencies", Count, GetByIndex, nullptr, nullptr, nullptr, |
|
NewObjectFromItem, nullptr, nullptr, nullptr, nullptr, |
|
}; |
|
|
|
} // 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 const void* GetByIndex(PyContainer* self, int index) { |
|
return GetDescriptor(self)->public_dependency(index); |
|
} |
|
|
|
static PyObject* NewObjectFromItem(const void* item) { |
|
return PyFileDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item)); |
|
} |
|
|
|
static DescriptorContainerDef ContainerDef = { |
|
"FilePublicDependencies", Count, GetByIndex, nullptr, nullptr, nullptr, |
|
NewObjectFromItem, nullptr, nullptr, nullptr, nullptr, |
|
}; |
|
|
|
} // 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
|
|
|