diff options
Diffstat (limited to 'python/google/protobuf/pyext')
26 files changed, 0 insertions, 12048 deletions
diff --git a/python/google/protobuf/pyext/README b/python/google/protobuf/pyext/README deleted file mode 100644 index 6d61cb45..00000000 --- a/python/google/protobuf/pyext/README +++ /dev/null @@ -1,6 +0,0 @@ -This is the 'v2' C++ implementation for python proto2. - -It is active when: - -PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp -PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=2 diff --git a/python/google/protobuf/pyext/__init__.py b/python/google/protobuf/pyext/__init__.py deleted file mode 100644 index 55856141..00000000 --- a/python/google/protobuf/pyext/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: - __path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/python/google/protobuf/pyext/cpp_message.py b/python/google/protobuf/pyext/cpp_message.py deleted file mode 100644 index b215211e..00000000 --- a/python/google/protobuf/pyext/cpp_message.py +++ /dev/null @@ -1,65 +0,0 @@ -# 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. - -"""Protocol message implementation hooks for C++ implementation. - -Contains helper functions used to create protocol message classes from -Descriptor objects at runtime backed by the protocol buffer C++ API. -""" - -__author__ = 'tibell@google.com (Johan Tibell)' - -from google.protobuf.pyext import _message - - -class GeneratedProtocolMessageType(_message.MessageMeta): - - """Metaclass for protocol message classes created at runtime from Descriptors. - - The protocol compiler currently uses this metaclass to create protocol - message classes at runtime. Clients can also manually create their own - classes at runtime, as in this example: - - mydescriptor = Descriptor(.....) - class MyProtoClass(Message): - __metaclass__ = GeneratedProtocolMessageType - DESCRIPTOR = mydescriptor - myproto_instance = MyProtoClass() - myproto.foo_field = 23 - ... - - The above example will not work for nested types. If you wish to include them, - use reflection.MakeClass() instead of manually instantiating the class in - order to create the appropriate class structure. - """ - - # Must be consistent with the protocol-compiler code in - # proto2/compiler/internal/generator.*. - _DESCRIPTOR_KEY = 'DESCRIPTOR' diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc deleted file mode 100644 index e6ef5ef5..00000000 --- a/python/google/protobuf/pyext/descriptor.cc +++ /dev/null @@ -1,1845 +0,0 @@ -// 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. - -// Author: petar@google.com (Petar Petrov) - -#include <Python.h> -#include <frameobject.h> -#include <string> - -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/dynamic_message.h> -#include <google/protobuf/pyext/descriptor.h> -#include <google/protobuf/pyext/descriptor_containers.h> -#include <google/protobuf/pyext/descriptor_pool.h> -#include <google/protobuf/pyext/message.h> -#include <google/protobuf/pyext/scoped_pyobject_ptr.h> - -#if PY_MAJOR_VERSION >= 3 - #define PyString_FromStringAndSize PyUnicode_FromStringAndSize - #define PyString_Check PyUnicode_Check - #define PyString_InternFromString PyUnicode_InternFromString - #define PyInt_FromLong PyLong_FromLong - #define PyInt_FromSize_t PyLong_FromSize_t - #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 { - -// Store interned descriptors, so that the same C++ descriptor yields the same -// Python object. Objects are not immortal: this map does not own the -// references, and items are deleted when the last reference to the object is -// released. -// This is enough to support the "is" operator on live objects. -// All descriptors are stored here. -hash_map<const void*, PyObject*> interned_descriptors; - -PyObject* PyString_FromCppString(const string& str) { - return PyString_FromStringAndSize(str.c_str(), str.size()); -} - -// Check that the calling Python code is the global scope of a _pb2.py module. -// This function is used to support the current code generated by the proto -// compiler, which creates descriptors, then update some properties. -// For example: -// message_descriptor = Descriptor( -// name='Message', -// fields = [FieldDescriptor(name='field')] -// message_descriptor.fields[0].containing_type = message_descriptor -// -// This code is still executed, but the descriptors now have no other storage -// than the (const) C++ pointer, and are immutable. -// So we let this code pass, by simply ignoring the new value. -// -// From user code, descriptors still look immutable. -// -// TODO(amauryfa): Change the proto2 compiler to remove the assignments, and -// remove this hack. -bool _CalledFromGeneratedFile(int stacklevel) { -#ifndef PYPY_VERSION - // This check is not critical and is somewhat difficult to implement correctly - // in PyPy. - PyFrameObject* frame = PyEval_GetFrame(); - if (frame == NULL) { - return false; - } - while (stacklevel-- > 0) { - frame = frame->f_back; - if (frame == NULL) { - return false; - } - } - if (frame->f_globals != frame->f_locals) { - // Not at global module scope - return false; - } - - if (frame->f_code->co_filename == NULL) { - return false; - } - char* filename; - Py_ssize_t filename_size; - if (PyString_AsStringAndSize(frame->f_code->co_filename, - &filename, &filename_size) < 0) { - // filename is not a string. - PyErr_Clear(); - return false; - } - if (filename_size < 7) { - // filename is too short. - return false; - } - if (strcmp(&filename[filename_size - 7], "_pb2.py") != 0) { - // Filename is not ending with _pb2. - return false; - } -#endif - return true; -} - -// If the calling code is not a _pb2.py file, raise AttributeError. -// To be used in attribute setters. -static int CheckCalledFromGeneratedFile(const char* attr_name) { - if (_CalledFromGeneratedFile(0)) { - return 0; - } - PyErr_Format(PyExc_AttributeError, - "attribute is not writable: %s", attr_name); - return -1; -} - - -#ifndef PyVarObject_HEAD_INIT -#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, -#endif -#ifndef Py_TYPE -#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) -#endif - - -// Helper functions for descriptor objects. - -// A set of templates to retrieve the C++ FileDescriptor of any descriptor. -template<class DescriptorClass> -const FileDescriptor* GetFileDescriptor(const DescriptorClass* descriptor) { - return descriptor->file(); -} -template<> -const FileDescriptor* GetFileDescriptor(const FileDescriptor* descriptor) { - return descriptor; -} -template<> -const FileDescriptor* GetFileDescriptor(const EnumValueDescriptor* descriptor) { - return descriptor->type()->file(); -} -template<> -const FileDescriptor* GetFileDescriptor(const OneofDescriptor* descriptor) { - return descriptor->containing_type()->file(); -} -template<> -const FileDescriptor* GetFileDescriptor(const MethodDescriptor* descriptor) { - return descriptor->service()->file(); -} - -// Converts options into a Python protobuf, and cache the result. -// -// This is a bit tricky because options can contain extension fields defined in -// the same proto file. In this case the options parsed from the serialized_pb -// have unknown fields, and we need to parse them again. -// -// Always returns a new reference. -template<class DescriptorClass> -static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) { - // Options (and their extensions) are completely resolved in the proto file - // containing the descriptor. - PyDescriptorPool* pool = GetDescriptorPool_FromPool( - GetFileDescriptor(descriptor)->pool()); - - hash_map<const void*, PyObject*>* descriptor_options = - pool->descriptor_options; - // First search in the cache. - if (descriptor_options->find(descriptor) != descriptor_options->end()) { - PyObject *value = (*descriptor_options)[descriptor]; - Py_INCREF(value); - return value; - } - - // Build the Options object: get its Python class, and make a copy of the C++ - // read-only instance. - const Message& options(descriptor->options()); - const Descriptor *message_type = options.GetDescriptor(); - CMessageClass* message_class( - cdescriptor_pool::GetMessageClass(pool, message_type)); - if (message_class == NULL) { - // The Options message was not found in the current DescriptorPool. - // This means that the pool cannot contain any extensions to the Options - // message either, so falling back to the basic pool we can only increase - // the chances of successfully parsing the options. - PyErr_Clear(); - pool = GetDefaultDescriptorPool(); - message_class = cdescriptor_pool::GetMessageClass(pool, message_type); - } - if (message_class == NULL) { - PyErr_Format(PyExc_TypeError, "Could not retrieve class for Options: %s", - message_type->full_name().c_str()); - return NULL; - } - ScopedPyObjectPtr value( - PyEval_CallObject(message_class->AsPyObject(), NULL)); - if (value == NULL) { - return NULL; - } - if (!PyObject_TypeCheck(value.get(), &CMessage_Type)) { - PyErr_Format(PyExc_TypeError, "Invalid class for %s: %s", - message_type->full_name().c_str(), - Py_TYPE(value.get())->tp_name); - return NULL; - } - CMessage* cmsg = reinterpret_cast<CMessage*>(value.get()); - - const Reflection* reflection = options.GetReflection(); - const UnknownFieldSet& unknown_fields(reflection->GetUnknownFields(options)); - if (unknown_fields.empty()) { - cmsg->message->CopyFrom(options); - } else { - // Reparse options string! XXX call cmessage::MergeFromString - string serialized; - options.SerializeToString(&serialized); - io::CodedInputStream input( - reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size()); - input.SetExtensionRegistry(pool->pool, pool->message_factory); - bool success = cmsg->message->MergePartialFromCodedStream(&input); - if (!success) { - PyErr_Format(PyExc_ValueError, "Error parsing Options message"); - return NULL; - } - } - - // Cache the result. - Py_INCREF(value.get()); - (*descriptor_options)[descriptor] = value.get(); - - return value.release(); -} - -// Copy the C++ descriptor to a Python message. -// The Python message is an instance of descriptor_pb2.DescriptorProto -// or similar. -template<class DescriptorProtoClass, class DescriptorClass> -static PyObject* CopyToPythonProto(const DescriptorClass *descriptor, - PyObject *target) { - const Descriptor* self_descriptor = - DescriptorProtoClass::default_instance().GetDescriptor(); - CMessage* message = reinterpret_cast<CMessage*>(target); - if (!PyObject_TypeCheck(target, &CMessage_Type) || - message->message->GetDescriptor() != self_descriptor) { - PyErr_Format(PyExc_TypeError, "Not a %s message", - self_descriptor->full_name().c_str()); - return NULL; - } - cmessage::AssureWritable(message); - DescriptorProtoClass* descriptor_message = - static_cast<DescriptorProtoClass*>(message->message); - descriptor->CopyTo(descriptor_message); - Py_RETURN_NONE; -} - -// All Descriptors classes share the same memory layout. -typedef struct PyBaseDescriptor { - PyObject_HEAD - - // Pointer to the C++ proto2 descriptor. - // Like all descriptors, it is owned by the global DescriptorPool. - const void* descriptor; - - // Owned reference to the DescriptorPool, to ensure it is kept alive. - PyDescriptorPool* pool; -} PyBaseDescriptor; - - -// FileDescriptor structure "inherits" from the base descriptor. -typedef struct PyFileDescriptor { - PyBaseDescriptor base; - - // The cached version of serialized pb. Either NULL, or a Bytes string. - // We own the reference. - PyObject *serialized_pb; -} PyFileDescriptor; - - -namespace descriptor { - -// Creates or retrieve a Python descriptor of the specified type. -// Objects are interned: the same descriptor will return the same object if it -// was kept alive. -// 'was_created' is an optional pointer to a bool, and is set to true if a new -// object was allocated. -// Always return a new reference. -template<class DescriptorClass> -PyObject* NewInternedDescriptor(PyTypeObject* type, - const DescriptorClass* descriptor, - bool* was_created) { - if (was_created) { - *was_created = false; - } - if (descriptor == NULL) { - PyErr_BadInternalCall(); - return NULL; - } - - // See if the object is in the map of interned descriptors - hash_map<const void*, PyObject*>::iterator it = - interned_descriptors.find(descriptor); - if (it != interned_descriptors.end()) { - GOOGLE_DCHECK(Py_TYPE(it->second) == type); - Py_INCREF(it->second); - return it->second; - } - // Create a new descriptor object - PyBaseDescriptor* py_descriptor = PyObject_New( - PyBaseDescriptor, type); - if (py_descriptor == NULL) { - return NULL; - } - py_descriptor->descriptor = descriptor; - - // and cache it. - interned_descriptors.insert( - std::make_pair(descriptor, reinterpret_cast<PyObject*>(py_descriptor))); - - // Ensures that the DescriptorPool stays alive. - PyDescriptorPool* pool = GetDescriptorPool_FromPool( - GetFileDescriptor(descriptor)->pool()); - if (pool == NULL) { - // Don't DECREF, the object is not fully initialized. - PyObject_Del(py_descriptor); - return NULL; - } - Py_INCREF(pool); - py_descriptor->pool = pool; - - if (was_created) { - *was_created = true; - } - return reinterpret_cast<PyObject*>(py_descriptor); -} - -static void Dealloc(PyBaseDescriptor* self) { - // Remove from interned dictionary - interned_descriptors.erase(self->descriptor); - Py_CLEAR(self->pool); - Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); -} - -static PyGetSetDef Getters[] = { - {NULL} -}; - -PyTypeObject PyBaseDescriptor_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".DescriptorBase", // tp_name - sizeof(PyBaseDescriptor), // tp_basicsize - 0, // tp_itemsize - (destructor)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 - "Descriptors base class", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - 0, // tp_methods - 0, // tp_members - Getters, // tp_getset -}; - -} // namespace descriptor - -const void* PyDescriptor_AsVoidPtr(PyObject* obj) { - if (!PyObject_TypeCheck(obj, &descriptor::PyBaseDescriptor_Type)) { - PyErr_SetString(PyExc_TypeError, "Not a BaseDescriptor"); - return NULL; - } - return reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor; -} - -namespace message_descriptor { - -// Unchecked accessor to the C++ pointer. -static const Descriptor* _GetDescriptor(PyBaseDescriptor* self) { - return reinterpret_cast<const Descriptor*>(self->descriptor); -} - -static PyObject* GetName(PyBaseDescriptor* self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->name()); -} - -static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->full_name()); -} - -static PyObject* GetFile(PyBaseDescriptor *self, void *closure) { - return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file()); -} - -static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) { - // Retuns the canonical class for the given descriptor. - // This is the class that was registered with the primary descriptor pool - // which contains this descriptor. - // This might not be the one you expect! For example the returned object does - // not know about extensions defined in a custom pool. - CMessageClass* concrete_class(cdescriptor_pool::GetMessageClass( - GetDescriptorPool_FromPool(_GetDescriptor(self)->file()->pool()), - _GetDescriptor(self))); - Py_XINCREF(concrete_class); - return concrete_class->AsPyObject(); -} - -static PyObject* GetFieldsByName(PyBaseDescriptor* self, void *closure) { - return NewMessageFieldsByName(_GetDescriptor(self)); -} - -static PyObject* GetFieldsByCamelcaseName(PyBaseDescriptor* self, - void *closure) { - return NewMessageFieldsByCamelcaseName(_GetDescriptor(self)); -} - -static PyObject* GetFieldsByNumber(PyBaseDescriptor* self, void *closure) { - return NewMessageFieldsByNumber(_GetDescriptor(self)); -} - -static PyObject* GetFieldsSeq(PyBaseDescriptor* self, void *closure) { - return NewMessageFieldsSeq(_GetDescriptor(self)); -} - -static PyObject* GetNestedTypesByName(PyBaseDescriptor* self, void *closure) { - return NewMessageNestedTypesByName(_GetDescriptor(self)); -} - -static PyObject* GetNestedTypesSeq(PyBaseDescriptor* self, void *closure) { - return NewMessageNestedTypesSeq(_GetDescriptor(self)); -} - -static PyObject* GetExtensionsByName(PyBaseDescriptor* self, void *closure) { - return NewMessageExtensionsByName(_GetDescriptor(self)); -} - -static PyObject* GetExtensions(PyBaseDescriptor* self, void *closure) { - return NewMessageExtensionsSeq(_GetDescriptor(self)); -} - -static PyObject* GetEnumsSeq(PyBaseDescriptor* self, void *closure) { - return NewMessageEnumsSeq(_GetDescriptor(self)); -} - -static PyObject* GetEnumTypesByName(PyBaseDescriptor* self, void *closure) { - return NewMessageEnumsByName(_GetDescriptor(self)); -} - -static PyObject* GetEnumValuesByName(PyBaseDescriptor* self, void *closure) { - return NewMessageEnumValuesByName(_GetDescriptor(self)); -} - -static PyObject* GetOneofsByName(PyBaseDescriptor* self, void *closure) { - return NewMessageOneofsByName(_GetDescriptor(self)); -} - -static PyObject* GetOneofsSeq(PyBaseDescriptor* self, void *closure) { - return NewMessageOneofsSeq(_GetDescriptor(self)); -} - -static PyObject* IsExtendable(PyBaseDescriptor *self, void *closure) { - if (_GetDescriptor(self)->extension_range_count() > 0) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} - -static PyObject* GetExtensionRanges(PyBaseDescriptor *self, void *closure) { - const Descriptor* descriptor = _GetDescriptor(self); - PyObject* range_list = PyList_New(descriptor->extension_range_count()); - - for (int i = 0; i < descriptor->extension_range_count(); i++) { - const Descriptor::ExtensionRange* range = descriptor->extension_range(i); - PyObject* start = PyInt_FromLong(range->start); - PyObject* end = PyInt_FromLong(range->end); - PyList_SetItem(range_list, i, PyTuple_Pack(2, start, end)); - } - - return range_list; -} - -static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) { - const Descriptor* containing_type = - _GetDescriptor(self)->containing_type(); - if (containing_type) { - return PyMessageDescriptor_FromDescriptor(containing_type); - } else { - Py_RETURN_NONE; - } -} - -static int SetContainingType(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("containing_type"); -} - -static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) { - const MessageOptions& options(_GetDescriptor(self)->options()); - if (&options != &MessageOptions::default_instance()) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} -static int SetHasOptions(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("has_options"); -} - -static PyObject* GetOptions(PyBaseDescriptor *self) { - return GetOrBuildOptions(_GetDescriptor(self)); -} - -static int SetOptions(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("_options"); -} - -static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) { - return CopyToPythonProto<DescriptorProto>(_GetDescriptor(self), target); -} - -static PyObject* EnumValueName(PyBaseDescriptor *self, PyObject *args) { - const char *enum_name; - int number; - if (!PyArg_ParseTuple(args, "si", &enum_name, &number)) - return NULL; - const EnumDescriptor *enum_type = - _GetDescriptor(self)->FindEnumTypeByName(enum_name); - if (enum_type == NULL) { - PyErr_SetString(PyExc_KeyError, enum_name); - return NULL; - } - const EnumValueDescriptor *enum_value = - enum_type->FindValueByNumber(number); - if (enum_value == NULL) { - PyErr_Format(PyExc_KeyError, "%d", number); - return NULL; - } - return PyString_FromCppString(enum_value->name()); -} - -static PyObject* GetSyntax(PyBaseDescriptor *self, void *closure) { - return PyString_InternFromString( - FileDescriptor::SyntaxName(_GetDescriptor(self)->file()->syntax())); -} - -static PyGetSetDef Getters[] = { - { "name", (getter)GetName, NULL, "Last name"}, - { "full_name", (getter)GetFullName, NULL, "Full name"}, - { "_concrete_class", (getter)GetConcreteClass, NULL, "concrete class"}, - { "file", (getter)GetFile, NULL, "File descriptor"}, - - { "fields", (getter)GetFieldsSeq, NULL, "Fields sequence"}, - { "fields_by_name", (getter)GetFieldsByName, NULL, "Fields by name"}, - { "fields_by_camelcase_name", (getter)GetFieldsByCamelcaseName, NULL, - "Fields by camelCase name"}, - { "fields_by_number", (getter)GetFieldsByNumber, NULL, "Fields by number"}, - { "nested_types", (getter)GetNestedTypesSeq, NULL, "Nested types sequence"}, - { "nested_types_by_name", (getter)GetNestedTypesByName, NULL, - "Nested types by name"}, - { "extensions", (getter)GetExtensions, NULL, "Extensions Sequence"}, - { "extensions_by_name", (getter)GetExtensionsByName, NULL, - "Extensions by name"}, - { "extension_ranges", (getter)GetExtensionRanges, NULL, "Extension ranges"}, - { "enum_types", (getter)GetEnumsSeq, NULL, "Enum sequence"}, - { "enum_types_by_name", (getter)GetEnumTypesByName, NULL, - "Enum types by name"}, - { "enum_values_by_name", (getter)GetEnumValuesByName, NULL, - "Enum values by name"}, - { "oneofs_by_name", (getter)GetOneofsByName, NULL, "Oneofs by name"}, - { "oneofs", (getter)GetOneofsSeq, NULL, "Oneofs by name"}, - { "containing_type", (getter)GetContainingType, (setter)SetContainingType, - "Containing type"}, - { "is_extendable", (getter)IsExtendable, (setter)NULL}, - { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"}, - { "_options", (getter)NULL, (setter)SetOptions, "Options"}, - { "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"}, - {NULL} -}; - -static PyMethodDef Methods[] = { - { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, }, - { "CopyToProto", (PyCFunction)CopyToProto, METH_O, }, - { "EnumValueName", (PyCFunction)EnumValueName, METH_VARARGS, }, - {NULL} -}; - -} // namespace message_descriptor - -PyTypeObject PyMessageDescriptor_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".MessageDescriptor", // tp_name - sizeof(PyBaseDescriptor), // tp_basicsize - 0, // tp_itemsize - 0, // 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 - "A Message Descriptor", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - message_descriptor::Methods, // tp_methods - 0, // tp_members - message_descriptor::Getters, // tp_getset - &descriptor::PyBaseDescriptor_Type, // tp_base -}; - -PyObject* PyMessageDescriptor_FromDescriptor( - const Descriptor* message_descriptor) { - return descriptor::NewInternedDescriptor( - &PyMessageDescriptor_Type, message_descriptor, NULL); -} - -const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj) { - if (!PyObject_TypeCheck(obj, &PyMessageDescriptor_Type)) { - PyErr_SetString(PyExc_TypeError, "Not a MessageDescriptor"); - return NULL; - } - return reinterpret_cast<const Descriptor*>( - reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor); -} - -namespace field_descriptor { - -// Unchecked accessor to the C++ pointer. -static const FieldDescriptor* _GetDescriptor( - PyBaseDescriptor *self) { - return reinterpret_cast<const FieldDescriptor*>(self->descriptor); -} - -static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->full_name()); -} - -static PyObject* GetName(PyBaseDescriptor *self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->name()); -} - -static PyObject* GetCamelcaseName(PyBaseDescriptor* self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->camelcase_name()); -} - -static PyObject* GetType(PyBaseDescriptor *self, void *closure) { - return PyInt_FromLong(_GetDescriptor(self)->type()); -} - -static PyObject* GetCppType(PyBaseDescriptor *self, void *closure) { - return PyInt_FromLong(_GetDescriptor(self)->cpp_type()); -} - -static PyObject* GetLabel(PyBaseDescriptor *self, void *closure) { - return PyInt_FromLong(_GetDescriptor(self)->label()); -} - -static PyObject* GetNumber(PyBaseDescriptor *self, void *closure) { - return PyInt_FromLong(_GetDescriptor(self)->number()); -} - -static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) { - return PyInt_FromLong(_GetDescriptor(self)->index()); -} - -static PyObject* GetID(PyBaseDescriptor *self, void *closure) { - return PyLong_FromVoidPtr(self); -} - -static PyObject* IsExtension(PyBaseDescriptor *self, void *closure) { - return PyBool_FromLong(_GetDescriptor(self)->is_extension()); -} - -static PyObject* HasDefaultValue(PyBaseDescriptor *self, void *closure) { - return PyBool_FromLong(_GetDescriptor(self)->has_default_value()); -} - -static PyObject* GetDefaultValue(PyBaseDescriptor *self, void *closure) { - PyObject *result; - - switch (_GetDescriptor(self)->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: { - int32 value = _GetDescriptor(self)->default_value_int32(); - result = PyInt_FromLong(value); - break; - } - case FieldDescriptor::CPPTYPE_INT64: { - int64 value = _GetDescriptor(self)->default_value_int64(); - result = PyLong_FromLongLong(value); - break; - } - case FieldDescriptor::CPPTYPE_UINT32: { - uint32 value = _GetDescriptor(self)->default_value_uint32(); - result = PyInt_FromSize_t(value); - break; - } - case FieldDescriptor::CPPTYPE_UINT64: { - uint64 value = _GetDescriptor(self)->default_value_uint64(); - result = PyLong_FromUnsignedLongLong(value); - break; - } - case FieldDescriptor::CPPTYPE_FLOAT: { - float value = _GetDescriptor(self)->default_value_float(); - result = PyFloat_FromDouble(value); - break; - } - case FieldDescriptor::CPPTYPE_DOUBLE: { - double value = _GetDescriptor(self)->default_value_double(); - result = PyFloat_FromDouble(value); - break; - } - case FieldDescriptor::CPPTYPE_BOOL: { - bool value = _GetDescriptor(self)->default_value_bool(); - result = PyBool_FromLong(value); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - string value = _GetDescriptor(self)->default_value_string(); - result = ToStringObject(_GetDescriptor(self), value); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - const EnumValueDescriptor* value = - _GetDescriptor(self)->default_value_enum(); - result = PyInt_FromLong(value->number()); - break; - } - default: - PyErr_Format(PyExc_NotImplementedError, "default value for %s", - _GetDescriptor(self)->full_name().c_str()); - return NULL; - } - return result; -} - -static PyObject* GetCDescriptor(PyObject *self, void *closure) { - Py_INCREF(self); - return self; -} - -static PyObject *GetEnumType(PyBaseDescriptor *self, void *closure) { - const EnumDescriptor* enum_type = _GetDescriptor(self)->enum_type(); - if (enum_type) { - return PyEnumDescriptor_FromDescriptor(enum_type); - } else { - Py_RETURN_NONE; - } -} - -static int SetEnumType(PyBaseDescriptor *self, PyObject *value, void *closure) { - return CheckCalledFromGeneratedFile("enum_type"); -} - -static PyObject *GetMessageType(PyBaseDescriptor *self, void *closure) { - const Descriptor* message_type = _GetDescriptor(self)->message_type(); - if (message_type) { - return PyMessageDescriptor_FromDescriptor(message_type); - } else { - Py_RETURN_NONE; - } -} - -static int SetMessageType(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("message_type"); -} - -static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) { - const Descriptor* containing_type = - _GetDescriptor(self)->containing_type(); - if (containing_type) { - return PyMessageDescriptor_FromDescriptor(containing_type); - } else { - Py_RETURN_NONE; - } -} - -static int SetContainingType(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("containing_type"); -} - -static PyObject* GetExtensionScope(PyBaseDescriptor *self, void *closure) { - const Descriptor* extension_scope = - _GetDescriptor(self)->extension_scope(); - if (extension_scope) { - return PyMessageDescriptor_FromDescriptor(extension_scope); - } else { - Py_RETURN_NONE; - } -} - -static PyObject* GetContainingOneof(PyBaseDescriptor *self, void *closure) { - const OneofDescriptor* containing_oneof = - _GetDescriptor(self)->containing_oneof(); - if (containing_oneof) { - return PyOneofDescriptor_FromDescriptor(containing_oneof); - } else { - Py_RETURN_NONE; - } -} - -static int SetContainingOneof(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("containing_oneof"); -} - -static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) { - const FieldOptions& options(_GetDescriptor(self)->options()); - if (&options != &FieldOptions::default_instance()) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} -static int SetHasOptions(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("has_options"); -} - -static PyObject* GetOptions(PyBaseDescriptor *self) { - return GetOrBuildOptions(_GetDescriptor(self)); -} - -static int SetOptions(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("_options"); -} - - -static PyGetSetDef Getters[] = { - { "full_name", (getter)GetFullName, NULL, "Full name"}, - { "name", (getter)GetName, NULL, "Unqualified name"}, - { "camelcase_name", (getter)GetCamelcaseName, NULL, "Camelcase name"}, - { "type", (getter)GetType, NULL, "C++ Type"}, - { "cpp_type", (getter)GetCppType, NULL, "C++ Type"}, - { "label", (getter)GetLabel, NULL, "Label"}, - { "number", (getter)GetNumber, NULL, "Number"}, - { "index", (getter)GetIndex, NULL, "Index"}, - { "default_value", (getter)GetDefaultValue, NULL, "Default Value"}, - { "has_default_value", (getter)HasDefaultValue}, - { "is_extension", (getter)IsExtension, NULL, "ID"}, - { "id", (getter)GetID, NULL, "ID"}, - { "_cdescriptor", (getter)GetCDescriptor, NULL, "HAACK REMOVE ME"}, - - { "message_type", (getter)GetMessageType, (setter)SetMessageType, - "Message type"}, - { "enum_type", (getter)GetEnumType, (setter)SetEnumType, "Enum type"}, - { "containing_type", (getter)GetContainingType, (setter)SetContainingType, - "Containing type"}, - { "extension_scope", (getter)GetExtensionScope, (setter)NULL, - "Extension scope"}, - { "containing_oneof", (getter)GetContainingOneof, (setter)SetContainingOneof, - "Containing oneof"}, - { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"}, - { "_options", (getter)NULL, (setter)SetOptions, "Options"}, - {NULL} -}; - -static PyMethodDef Methods[] = { - { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, }, - {NULL} -}; - -} // namespace field_descriptor - -PyTypeObject PyFieldDescriptor_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".FieldDescriptor", // tp_name - sizeof(PyBaseDescriptor), // tp_basicsize - 0, // tp_itemsize - 0, // 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 - "A Field Descriptor", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - field_descriptor::Methods, // tp_methods - 0, // tp_members - field_descriptor::Getters, // tp_getset - &descriptor::PyBaseDescriptor_Type, // tp_base -}; - -PyObject* PyFieldDescriptor_FromDescriptor( - const FieldDescriptor* field_descriptor) { - return descriptor::NewInternedDescriptor( - &PyFieldDescriptor_Type, field_descriptor, NULL); -} - -const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj) { - if (!PyObject_TypeCheck(obj, &PyFieldDescriptor_Type)) { - PyErr_SetString(PyExc_TypeError, "Not a FieldDescriptor"); - return NULL; - } - return reinterpret_cast<const FieldDescriptor*>( - reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor); -} - -namespace enum_descriptor { - -// Unchecked accessor to the C++ pointer. -static const EnumDescriptor* _GetDescriptor( - PyBaseDescriptor *self) { - return reinterpret_cast<const EnumDescriptor*>(self->descriptor); -} - -static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->full_name()); -} - -static PyObject* GetName(PyBaseDescriptor *self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->name()); -} - -static PyObject* GetFile(PyBaseDescriptor *self, void *closure) { - return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file()); -} - -static PyObject* GetEnumvaluesByName(PyBaseDescriptor* self, void *closure) { - return NewEnumValuesByName(_GetDescriptor(self)); -} - -static PyObject* GetEnumvaluesByNumber(PyBaseDescriptor* self, void *closure) { - return NewEnumValuesByNumber(_GetDescriptor(self)); -} - -static PyObject* GetEnumvaluesSeq(PyBaseDescriptor* self, void *closure) { - return NewEnumValuesSeq(_GetDescriptor(self)); -} - -static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) { - const Descriptor* containing_type = - _GetDescriptor(self)->containing_type(); - if (containing_type) { - return PyMessageDescriptor_FromDescriptor(containing_type); - } else { - Py_RETURN_NONE; - } -} - -static int SetContainingType(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("containing_type"); -} - - -static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) { - const EnumOptions& options(_GetDescriptor(self)->options()); - if (&options != &EnumOptions::default_instance()) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} -static int SetHasOptions(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("has_options"); -} - -static PyObject* GetOptions(PyBaseDescriptor *self) { - return GetOrBuildOptions(_GetDescriptor(self)); -} - -static int SetOptions(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("_options"); -} - -static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) { - return CopyToPythonProto<EnumDescriptorProto>(_GetDescriptor(self), target); -} - -static PyMethodDef Methods[] = { - { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, }, - { "CopyToProto", (PyCFunction)CopyToProto, METH_O, }, - {NULL} -}; - -static PyGetSetDef Getters[] = { - { "full_name", (getter)GetFullName, NULL, "Full name"}, - { "name", (getter)GetName, NULL, "last name"}, - { "file", (getter)GetFile, NULL, "File descriptor"}, - { "values", (getter)GetEnumvaluesSeq, NULL, "values"}, - { "values_by_name", (getter)GetEnumvaluesByName, NULL, - "Enum values by name"}, - { "values_by_number", (getter)GetEnumvaluesByNumber, NULL, - "Enum values by number"}, - - { "containing_type", (getter)GetContainingType, (setter)SetContainingType, - "Containing type"}, - { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"}, - { "_options", (getter)NULL, (setter)SetOptions, "Options"}, - {NULL} -}; - -} // namespace enum_descriptor - -PyTypeObject PyEnumDescriptor_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".EnumDescriptor", // tp_name - sizeof(PyBaseDescriptor), // tp_basicsize - 0, // tp_itemsize - 0, // 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 - "A Enum Descriptor", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - enum_descriptor::Methods, // tp_methods - 0, // tp_members - enum_descriptor::Getters, // tp_getset - &descriptor::PyBaseDescriptor_Type, // tp_base -}; - -PyObject* PyEnumDescriptor_FromDescriptor( - const EnumDescriptor* enum_descriptor) { - return descriptor::NewInternedDescriptor( - &PyEnumDescriptor_Type, enum_descriptor, NULL); -} - -const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj) { - if (!PyObject_TypeCheck(obj, &PyEnumDescriptor_Type)) { - PyErr_SetString(PyExc_TypeError, "Not an EnumDescriptor"); - return NULL; - } - return reinterpret_cast<const EnumDescriptor*>( - reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor); -} - -namespace enumvalue_descriptor { - -// Unchecked accessor to the C++ pointer. -static const EnumValueDescriptor* _GetDescriptor( - PyBaseDescriptor *self) { - return reinterpret_cast<const EnumValueDescriptor*>(self->descriptor); -} - -static PyObject* GetName(PyBaseDescriptor *self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->name()); -} - -static PyObject* GetNumber(PyBaseDescriptor *self, void *closure) { - return PyInt_FromLong(_GetDescriptor(self)->number()); -} - -static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) { - return PyInt_FromLong(_GetDescriptor(self)->index()); -} - -static PyObject* GetType(PyBaseDescriptor *self, void *closure) { - return PyEnumDescriptor_FromDescriptor(_GetDescriptor(self)->type()); -} - -static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) { - const EnumValueOptions& options(_GetDescriptor(self)->options()); - if (&options != &EnumValueOptions::default_instance()) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} -static int SetHasOptions(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("has_options"); -} - -static PyObject* GetOptions(PyBaseDescriptor *self) { - return GetOrBuildOptions(_GetDescriptor(self)); -} - -static int SetOptions(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("_options"); -} - - -static PyGetSetDef Getters[] = { - { "name", (getter)GetName, NULL, "name"}, - { "number", (getter)GetNumber, NULL, "number"}, - { "index", (getter)GetIndex, NULL, "index"}, - { "type", (getter)GetType, NULL, "index"}, - - { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"}, - { "_options", (getter)NULL, (setter)SetOptions, "Options"}, - {NULL} -}; - -static PyMethodDef Methods[] = { - { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, }, - {NULL} -}; - -} // namespace enumvalue_descriptor - -PyTypeObject PyEnumValueDescriptor_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".EnumValueDescriptor", // tp_name - sizeof(PyBaseDescriptor), // tp_basicsize - 0, // tp_itemsize - 0, // 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 - "A EnumValue Descriptor", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - enumvalue_descriptor::Methods, // tp_methods - 0, // tp_members - enumvalue_descriptor::Getters, // tp_getset - &descriptor::PyBaseDescriptor_Type, // tp_base -}; - -PyObject* PyEnumValueDescriptor_FromDescriptor( - const EnumValueDescriptor* enumvalue_descriptor) { - return descriptor::NewInternedDescriptor( - &PyEnumValueDescriptor_Type, enumvalue_descriptor, NULL); -} - -namespace file_descriptor { - -// Unchecked accessor to the C++ pointer. -static const FileDescriptor* _GetDescriptor(PyFileDescriptor *self) { - return reinterpret_cast<const FileDescriptor*>(self->base.descriptor); -} - -static void Dealloc(PyFileDescriptor* self) { - Py_XDECREF(self->serialized_pb); - descriptor::Dealloc(&self->base); -} - -static PyObject* GetPool(PyFileDescriptor *self, void *closure) { - PyObject* pool = reinterpret_cast<PyObject*>( - GetDescriptorPool_FromPool(_GetDescriptor(self)->pool())); - Py_XINCREF(pool); - return pool; -} - -static PyObject* GetName(PyFileDescriptor *self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->name()); -} - -static PyObject* GetPackage(PyFileDescriptor *self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->package()); -} - -static PyObject* GetSerializedPb(PyFileDescriptor *self, void *closure) { - PyObject *serialized_pb = self->serialized_pb; - if (serialized_pb != NULL) { - Py_INCREF(serialized_pb); - return serialized_pb; - } - FileDescriptorProto file_proto; - _GetDescriptor(self)->CopyTo(&file_proto); - string contents; - file_proto.SerializePartialToString(&contents); - self->serialized_pb = PyBytes_FromStringAndSize( - contents.c_str(), contents.size()); - if (self->serialized_pb == NULL) { - return NULL; - } - Py_INCREF(self->serialized_pb); - return self->serialized_pb; -} - -static PyObject* GetMessageTypesByName(PyFileDescriptor* self, void *closure) { - return NewFileMessageTypesByName(_GetDescriptor(self)); -} - -static PyObject* GetEnumTypesByName(PyFileDescriptor* self, void *closure) { - return NewFileEnumTypesByName(_GetDescriptor(self)); -} - -static PyObject* GetExtensionsByName(PyFileDescriptor* self, void *closure) { - return NewFileExtensionsByName(_GetDescriptor(self)); -} - -static PyObject* GetServicesByName(PyFileDescriptor* self, void *closure) { - return NewFileServicesByName(_GetDescriptor(self)); -} - -static PyObject* GetDependencies(PyFileDescriptor* self, void *closure) { - return NewFileDependencies(_GetDescriptor(self)); -} - -static PyObject* GetPublicDependencies(PyFileDescriptor* self, void *closure) { - return NewFilePublicDependencies(_GetDescriptor(self)); -} - -static PyObject* GetHasOptions(PyFileDescriptor *self, void *closure) { - const FileOptions& options(_GetDescriptor(self)->options()); - if (&options != &FileOptions::default_instance()) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} -static int SetHasOptions(PyFileDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("has_options"); -} - -static PyObject* GetOptions(PyFileDescriptor *self) { - return GetOrBuildOptions(_GetDescriptor(self)); -} - -static int SetOptions(PyFileDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("_options"); -} - -static PyObject* GetSyntax(PyFileDescriptor *self, void *closure) { - return PyString_InternFromString( - FileDescriptor::SyntaxName(_GetDescriptor(self)->syntax())); -} - -static PyObject* CopyToProto(PyFileDescriptor *self, PyObject *target) { - return CopyToPythonProto<FileDescriptorProto>(_GetDescriptor(self), target); -} - -static PyGetSetDef Getters[] = { - { "pool", (getter)GetPool, NULL, "pool"}, - { "name", (getter)GetName, NULL, "name"}, - { "package", (getter)GetPackage, NULL, "package"}, - { "serialized_pb", (getter)GetSerializedPb}, - { "message_types_by_name", (getter)GetMessageTypesByName, NULL, - "Messages by name"}, - { "enum_types_by_name", (getter)GetEnumTypesByName, NULL, "Enums by name"}, - { "extensions_by_name", (getter)GetExtensionsByName, NULL, - "Extensions by name"}, - { "services_by_name", (getter)GetServicesByName, NULL, "Services by name"}, - { "dependencies", (getter)GetDependencies, NULL, "Dependencies"}, - { "public_dependencies", (getter)GetPublicDependencies, NULL, "Dependencies"}, - - { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"}, - { "_options", (getter)NULL, (setter)SetOptions, "Options"}, - { "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"}, - {NULL} -}; - -static PyMethodDef Methods[] = { - { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, }, - { "CopyToProto", (PyCFunction)CopyToProto, METH_O, }, - {NULL} -}; - -} // namespace file_descriptor - -PyTypeObject PyFileDescriptor_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".FileDescriptor", // tp_name - sizeof(PyFileDescriptor), // tp_basicsize - 0, // tp_itemsize - (destructor)file_descriptor::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 - "A File Descriptor", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - file_descriptor::Methods, // tp_methods - 0, // tp_members - file_descriptor::Getters, // tp_getset - &descriptor::PyBaseDescriptor_Type, // 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 - PyObject_Del, // tp_free -}; - -PyObject* PyFileDescriptor_FromDescriptor( - const FileDescriptor* file_descriptor) { - return PyFileDescriptor_FromDescriptorWithSerializedPb(file_descriptor, - NULL); -} - -PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb( - const FileDescriptor* file_descriptor, PyObject *serialized_pb) { - bool was_created; - PyObject* py_descriptor = descriptor::NewInternedDescriptor( - &PyFileDescriptor_Type, file_descriptor, &was_created); - if (py_descriptor == NULL) { - return NULL; - } - if (was_created) { - PyFileDescriptor* cfile_descriptor = - reinterpret_cast<PyFileDescriptor*>(py_descriptor); - Py_XINCREF(serialized_pb); - cfile_descriptor->serialized_pb = serialized_pb; - } - // TODO(amauryfa): In the case of a cached object, check that serialized_pb - // is the same as before. - - return py_descriptor; -} - -const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj) { - if (!PyObject_TypeCheck(obj, &PyFileDescriptor_Type)) { - PyErr_SetString(PyExc_TypeError, "Not a FileDescriptor"); - return NULL; - } - return reinterpret_cast<const FileDescriptor*>( - reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor); -} - -namespace oneof_descriptor { - -// Unchecked accessor to the C++ pointer. -static const OneofDescriptor* _GetDescriptor( - PyBaseDescriptor *self) { - return reinterpret_cast<const OneofDescriptor*>(self->descriptor); -} - -static PyObject* GetName(PyBaseDescriptor* self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->name()); -} - -static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->full_name()); -} - -static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) { - return PyInt_FromLong(_GetDescriptor(self)->index()); -} - -static PyObject* GetFields(PyBaseDescriptor* self, void *closure) { - return NewOneofFieldsSeq(_GetDescriptor(self)); -} - -static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) { - const Descriptor* containing_type = - _GetDescriptor(self)->containing_type(); - if (containing_type) { - return PyMessageDescriptor_FromDescriptor(containing_type); - } else { - Py_RETURN_NONE; - } -} - -static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) { - const OneofOptions& options(_GetDescriptor(self)->options()); - if (&options != &OneofOptions::default_instance()) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} -static int SetHasOptions(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("has_options"); -} - -static PyObject* GetOptions(PyBaseDescriptor *self) { - return GetOrBuildOptions(_GetDescriptor(self)); -} - -static int SetOptions(PyBaseDescriptor *self, PyObject *value, - void *closure) { - return CheckCalledFromGeneratedFile("_options"); -} - -static PyGetSetDef Getters[] = { - { "name", (getter)GetName, NULL, "Name"}, - { "full_name", (getter)GetFullName, NULL, "Full name"}, - { "index", (getter)GetIndex, NULL, "Index"}, - - { "containing_type", (getter)GetContainingType, NULL, "Containing type"}, - { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"}, - { "_options", (getter)NULL, (setter)SetOptions, "Options"}, - { "fields", (getter)GetFields, NULL, "Fields"}, - {NULL} -}; - -static PyMethodDef Methods[] = { - { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS }, - {NULL} -}; - -} // namespace oneof_descriptor - -PyTypeObject PyOneofDescriptor_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".OneofDescriptor", // tp_name - sizeof(PyBaseDescriptor), // tp_basicsize - 0, // tp_itemsize - 0, // 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 - "A Oneof Descriptor", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - oneof_descriptor::Methods, // tp_methods - 0, // tp_members - oneof_descriptor::Getters, // tp_getset - &descriptor::PyBaseDescriptor_Type, // tp_base -}; - -PyObject* PyOneofDescriptor_FromDescriptor( - const OneofDescriptor* oneof_descriptor) { - return descriptor::NewInternedDescriptor( - &PyOneofDescriptor_Type, oneof_descriptor, NULL); -} - -namespace service_descriptor { - -// Unchecked accessor to the C++ pointer. -static const ServiceDescriptor* _GetDescriptor( - PyBaseDescriptor *self) { - return reinterpret_cast<const ServiceDescriptor*>(self->descriptor); -} - -static PyObject* GetName(PyBaseDescriptor* self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->name()); -} - -static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->full_name()); -} - -static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) { - return PyInt_FromLong(_GetDescriptor(self)->index()); -} - -static PyObject* GetMethods(PyBaseDescriptor* self, void *closure) { - return NewServiceMethodsSeq(_GetDescriptor(self)); -} - -static PyObject* GetMethodsByName(PyBaseDescriptor* self, void *closure) { - return NewServiceMethodsByName(_GetDescriptor(self)); -} - -static PyObject* FindMethodByName(PyBaseDescriptor *self, PyObject* arg) { - Py_ssize_t name_size; - char* name; - if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { - return NULL; - } - - const MethodDescriptor* method_descriptor = - _GetDescriptor(self)->FindMethodByName(string(name, name_size)); - if (method_descriptor == NULL) { - PyErr_Format(PyExc_KeyError, "Couldn't find method %.200s", name); - return NULL; - } - - return PyMethodDescriptor_FromDescriptor(method_descriptor); -} - -static PyObject* GetOptions(PyBaseDescriptor *self) { - return GetOrBuildOptions(_GetDescriptor(self)); -} - -static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) { - return CopyToPythonProto<ServiceDescriptorProto>(_GetDescriptor(self), - target); -} - -static PyGetSetDef Getters[] = { - { "name", (getter)GetName, NULL, "Name", NULL}, - { "full_name", (getter)GetFullName, NULL, "Full name", NULL}, - { "index", (getter)GetIndex, NULL, "Index", NULL}, - - { "methods", (getter)GetMethods, NULL, "Methods", NULL}, - { "methods_by_name", (getter)GetMethodsByName, NULL, "Methods by name", NULL}, - {NULL} -}; - -static PyMethodDef Methods[] = { - { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS }, - { "CopyToProto", (PyCFunction)CopyToProto, METH_O, }, - { "FindMethodByName", (PyCFunction)FindMethodByName, METH_O }, - {NULL} -}; - -} // namespace service_descriptor - -PyTypeObject PyServiceDescriptor_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".ServiceDescriptor", // tp_name - sizeof(PyBaseDescriptor), // tp_basicsize - 0, // tp_itemsize - 0, // 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 - "A Service Descriptor", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - service_descriptor::Methods, // tp_methods - 0, // tp_members - service_descriptor::Getters, // tp_getset - &descriptor::PyBaseDescriptor_Type, // tp_base -}; - -PyObject* PyServiceDescriptor_FromDescriptor( - const ServiceDescriptor* service_descriptor) { - return descriptor::NewInternedDescriptor( - &PyServiceDescriptor_Type, service_descriptor, NULL); -} - -namespace method_descriptor { - -// Unchecked accessor to the C++ pointer. -static const MethodDescriptor* _GetDescriptor( - PyBaseDescriptor *self) { - return reinterpret_cast<const MethodDescriptor*>(self->descriptor); -} - -static PyObject* GetName(PyBaseDescriptor* self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->name()); -} - -static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) { - return PyString_FromCppString(_GetDescriptor(self)->full_name()); -} - -static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) { - return PyInt_FromLong(_GetDescriptor(self)->index()); -} - -static PyObject* GetContainingService(PyBaseDescriptor *self, void *closure) { - const ServiceDescriptor* containing_service = - _GetDescriptor(self)->service(); - return PyServiceDescriptor_FromDescriptor(containing_service); -} - -static PyObject* GetInputType(PyBaseDescriptor *self, void *closure) { - const Descriptor* input_type = _GetDescriptor(self)->input_type(); - return PyMessageDescriptor_FromDescriptor(input_type); -} - -static PyObject* GetOutputType(PyBaseDescriptor *self, void *closure) { - const Descriptor* output_type = _GetDescriptor(self)->output_type(); - return PyMessageDescriptor_FromDescriptor(output_type); -} - -static PyObject* GetOptions(PyBaseDescriptor *self) { - return GetOrBuildOptions(_GetDescriptor(self)); -} - -static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) { - return CopyToPythonProto<MethodDescriptorProto>(_GetDescriptor(self), target); -} - -static PyGetSetDef Getters[] = { - { "name", (getter)GetName, NULL, "Name", NULL}, - { "full_name", (getter)GetFullName, NULL, "Full name", NULL}, - { "index", (getter)GetIndex, NULL, "Index", NULL}, - { "containing_service", (getter)GetContainingService, NULL, - "Containing service", NULL}, - { "input_type", (getter)GetInputType, NULL, "Input type", NULL}, - { "output_type", (getter)GetOutputType, NULL, "Output type", NULL}, - {NULL} -}; - -static PyMethodDef Methods[] = { - { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, }, - { "CopyToProto", (PyCFunction)CopyToProto, METH_O, }, - {NULL} -}; - -} // namespace method_descriptor - -PyTypeObject PyMethodDescriptor_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".MethodDescriptor", // tp_name - sizeof(PyBaseDescriptor), // tp_basicsize - 0, // tp_itemsize - 0, // 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 - "A Method Descriptor", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - method_descriptor::Methods, // tp_methods - 0, // tp_members - method_descriptor::Getters, // tp_getset - &descriptor::PyBaseDescriptor_Type, // tp_base -}; - -PyObject* PyMethodDescriptor_FromDescriptor( - const MethodDescriptor* method_descriptor) { - return descriptor::NewInternedDescriptor( - &PyMethodDescriptor_Type, method_descriptor, NULL); -} - -// Add a enum values to a type dictionary. -static bool AddEnumValues(PyTypeObject *type, - const EnumDescriptor* enum_descriptor) { - for (int i = 0; i < enum_descriptor->value_count(); ++i) { - const EnumValueDescriptor* value = enum_descriptor->value(i); - ScopedPyObjectPtr obj(PyInt_FromLong(value->number())); - if (obj == NULL) { - return false; - } - if (PyDict_SetItemString(type->tp_dict, value->name().c_str(), obj.get()) < - 0) { - return false; - } - } - return true; -} - -static bool AddIntConstant(PyTypeObject *type, const char* name, int value) { - ScopedPyObjectPtr obj(PyInt_FromLong(value)); - if (PyDict_SetItemString(type->tp_dict, name, obj.get()) < 0) { - return false; - } - return true; -} - - -bool InitDescriptor() { - if (PyType_Ready(&PyMessageDescriptor_Type) < 0) - return false; - - if (PyType_Ready(&PyFieldDescriptor_Type) < 0) - return false; - - if (!AddEnumValues(&PyFieldDescriptor_Type, - FieldDescriptorProto::Label_descriptor())) { - return false; - } - if (!AddEnumValues(&PyFieldDescriptor_Type, - FieldDescriptorProto::Type_descriptor())) { - return false; - } -#define ADD_FIELDDESC_CONSTANT(NAME) AddIntConstant( \ - &PyFieldDescriptor_Type, #NAME, FieldDescriptor::NAME) - if (!ADD_FIELDDESC_CONSTANT(CPPTYPE_INT32) || - !ADD_FIELDDESC_CONSTANT(CPPTYPE_INT64) || - !ADD_FIELDDESC_CONSTANT(CPPTYPE_UINT32) || - !ADD_FIELDDESC_CONSTANT(CPPTYPE_UINT64) || - !ADD_FIELDDESC_CONSTANT(CPPTYPE_DOUBLE) || - !ADD_FIELDDESC_CONSTANT(CPPTYPE_FLOAT) || - !ADD_FIELDDESC_CONSTANT(CPPTYPE_BOOL) || - !ADD_FIELDDESC_CONSTANT(CPPTYPE_ENUM) || - !ADD_FIELDDESC_CONSTANT(CPPTYPE_STRING) || - !ADD_FIELDDESC_CONSTANT(CPPTYPE_MESSAGE)) { - return false; - } -#undef ADD_FIELDDESC_CONSTANT - - if (PyType_Ready(&PyEnumDescriptor_Type) < 0) - return false; - - if (PyType_Ready(&PyEnumValueDescriptor_Type) < 0) - return false; - - if (PyType_Ready(&PyFileDescriptor_Type) < 0) - return false; - - if (PyType_Ready(&PyOneofDescriptor_Type) < 0) - return false; - - if (PyType_Ready(&PyServiceDescriptor_Type) < 0) - return false; - - if (PyType_Ready(&PyMethodDescriptor_Type) < 0) - return false; - - if (!InitDescriptorMappingTypes()) - return false; - - return true; -} - -} // namespace python -} // namespace protobuf -} // namespace google diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h deleted file mode 100644 index 1ae0e672..00000000 --- a/python/google/protobuf/pyext/descriptor.h +++ /dev/null @@ -1,103 +0,0 @@ -// 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. - -// Author: petar@google.com (Petar Petrov) - -#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__ -#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__ - -#include <Python.h> - -#include <google/protobuf/descriptor.h> - -namespace google { -namespace protobuf { -namespace python { - -extern PyTypeObject PyMessageDescriptor_Type; -extern PyTypeObject PyFieldDescriptor_Type; -extern PyTypeObject PyEnumDescriptor_Type; -extern PyTypeObject PyEnumValueDescriptor_Type; -extern PyTypeObject PyFileDescriptor_Type; -extern PyTypeObject PyOneofDescriptor_Type; -extern PyTypeObject PyServiceDescriptor_Type; -extern PyTypeObject PyMethodDescriptor_Type; - -// Wraps a Descriptor in a Python object. -// The C++ pointer is usually borrowed from the global DescriptorPool. -// In any case, it must stay alive as long as the Python object. -// Returns a new reference. -PyObject* PyMessageDescriptor_FromDescriptor(const Descriptor* descriptor); -PyObject* PyFieldDescriptor_FromDescriptor(const FieldDescriptor* descriptor); -PyObject* PyEnumDescriptor_FromDescriptor(const EnumDescriptor* descriptor); -PyObject* PyEnumValueDescriptor_FromDescriptor( - const EnumValueDescriptor* descriptor); -PyObject* PyOneofDescriptor_FromDescriptor(const OneofDescriptor* descriptor); -PyObject* PyFileDescriptor_FromDescriptor( - const FileDescriptor* file_descriptor); -PyObject* PyServiceDescriptor_FromDescriptor( - const ServiceDescriptor* descriptor); -PyObject* PyMethodDescriptor_FromDescriptor( - const MethodDescriptor* descriptor); - -// Alternate constructor of PyFileDescriptor, used when we already have a -// serialized FileDescriptorProto that can be cached. -// Returns a new reference. -PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb( - const FileDescriptor* file_descriptor, PyObject* serialized_pb); - -// Return the C++ descriptor pointer. -// This function checks the parameter type; on error, return NULL with a Python -// exception set. -const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj); -const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj); -const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj); -const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj); - -// Returns the raw C++ pointer. -const void* PyDescriptor_AsVoidPtr(PyObject* obj); - -// Check that the calling Python code is the global scope of a _pb2.py module. -// This function is used to support the current code generated by the proto -// compiler, which insists on modifying descriptors after they have been -// created. -// -// stacklevel indicates which Python frame should be the _pb2.py module. -// -// Don't use this function outside descriptor classes. -bool _CalledFromGeneratedFile(int stacklevel); - -bool InitDescriptor(); - -} // namespace python -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__ diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc deleted file mode 100644 index d0aae9c9..00000000 --- a/python/google/protobuf/pyext/descriptor_containers.cc +++ /dev/null @@ -1,1786 +0,0 @@ -// 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); -} - -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 NULL; - return GetItem(self, index); - } - // Materialize the list and delegate the operation to it. - ScopedPyObjectPtr list(PyObject_CallFunctionObjArgs( - reinterpret_cast<PyObject*>(&PyList_Type), self, NULL)); - if (list == NULL) { - return NULL; - } - 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 == 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 -}; - -static PyMappingMethods SeqMappingMethods = { - (lenfunc)Length, // mp_length - (binaryfunc)SeqSubscript, // mp_subscript - 0, // mp_ass_subscript -}; - -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 - &SeqMappingMethods, // 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 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 ItemDescriptor GetByName(PyContainer* self, const string& name) { - return GetDescriptor(self)->FindMethodByName(name); -} - -static ItemDescriptor GetByIndex(PyContainer* self, int index) { - return GetDescriptor(self)->method(index); -} - -static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyMethodDescriptor_FromDescriptor(item); -} - -static const string& GetItemName(ItemDescriptor item) { - return item->name(); -} - -static int GetItemIndex(ItemDescriptor item) { - return item->index(); -} - -static DescriptorContainerDef ContainerDef = { - "ServiceMethods", - (CountMethod)Count, - (GetByIndexMethod)GetByIndex, - (GetByNameMethod)GetByName, - (GetByCamelcaseNameMethod)NULL, - (GetByNumberMethod)NULL, - (NewObjectFromItemMethod)NewObjectFromItem, - (GetItemNameMethod)GetItemName, - (GetItemCamelcaseNameMethod)NULL, - (GetItemNumberMethod)NULL, - (GetItemIndexMethod)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 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(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 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(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 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(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 ItemDescriptor GetByName(PyContainer* self, const string& name) { - return GetDescriptor(self)->FindServiceByName(name); -} - -static ItemDescriptor GetByIndex(PyContainer* self, int index) { - return GetDescriptor(self)->service(index); -} - -static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyServiceDescriptor_FromDescriptor(item); -} - -static const string& GetItemName(ItemDescriptor item) { - return item->name(); -} - -static int GetItemIndex(ItemDescriptor item) { - return item->index(); -} - -static DescriptorContainerDef ContainerDef = { - "FileServices", - (CountMethod)Count, - (GetByIndexMethod)GetByIndex, - (GetByNameMethod)GetByName, - (GetByCamelcaseNameMethod)NULL, - (GetByNumberMethod)NULL, - (NewObjectFromItemMethod)NewObjectFromItem, - (GetItemNameMethod)GetItemName, - (GetItemCamelcaseNameMethod)NULL, - (GetItemNumberMethod)NULL, - (GetItemIndexMethod)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 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 diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h deleted file mode 100644 index 83de07b6..00000000 --- a/python/google/protobuf/pyext/descriptor_containers.h +++ /dev/null @@ -1,109 +0,0 @@ -// 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. - -#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__ -#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__ - -// Mappings and Sequences of descriptors. -// They implement containers like fields_by_name, EnumDescriptor.values... -// See descriptor_containers.cc for more description. -#include <Python.h> - -namespace google { -namespace protobuf { - -class Descriptor; -class FileDescriptor; -class EnumDescriptor; -class OneofDescriptor; -class ServiceDescriptor; - -namespace python { - -// Initialize the various types and objects. -bool InitDescriptorMappingTypes(); - -// Each function below returns a Mapping, or a Sequence of descriptors. -// They all return a new reference. - -namespace message_descriptor { -PyObject* NewMessageFieldsByName(const Descriptor* descriptor); -PyObject* NewMessageFieldsByCamelcaseName(const Descriptor* descriptor); -PyObject* NewMessageFieldsByNumber(const Descriptor* descriptor); -PyObject* NewMessageFieldsSeq(const Descriptor* descriptor); - -PyObject* NewMessageNestedTypesSeq(const Descriptor* descriptor); -PyObject* NewMessageNestedTypesByName(const Descriptor* descriptor); - -PyObject* NewMessageEnumsByName(const Descriptor* descriptor); -PyObject* NewMessageEnumsSeq(const Descriptor* descriptor); -PyObject* NewMessageEnumValuesByName(const Descriptor* descriptor); - -PyObject* NewMessageExtensionsByName(const Descriptor* descriptor); -PyObject* NewMessageExtensionsSeq(const Descriptor* descriptor); - -PyObject* NewMessageOneofsByName(const Descriptor* descriptor); -PyObject* NewMessageOneofsSeq(const Descriptor* descriptor); -} // namespace message_descriptor - -namespace enum_descriptor { -PyObject* NewEnumValuesByName(const EnumDescriptor* descriptor); -PyObject* NewEnumValuesByNumber(const EnumDescriptor* descriptor); -PyObject* NewEnumValuesSeq(const EnumDescriptor* descriptor); -} // namespace enum_descriptor - -namespace oneof_descriptor { -PyObject* NewOneofFieldsSeq(const OneofDescriptor* descriptor); -} // namespace oneof_descriptor - -namespace file_descriptor { -PyObject* NewFileMessageTypesByName(const FileDescriptor* descriptor); - -PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor); - -PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor); - -PyObject* NewFileServicesByName(const FileDescriptor* descriptor); - -PyObject* NewFileDependencies(const FileDescriptor* descriptor); -PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor); -} // namespace file_descriptor - -namespace service_descriptor { -PyObject* NewServiceMethodsSeq(const ServiceDescriptor* descriptor); -PyObject* NewServiceMethodsByName(const ServiceDescriptor* descriptor); -} // namespace service_descriptor - - -} // namespace python -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__ diff --git a/python/google/protobuf/pyext/descriptor_database.cc b/python/google/protobuf/pyext/descriptor_database.cc deleted file mode 100644 index daa40cc7..00000000 --- a/python/google/protobuf/pyext/descriptor_database.cc +++ /dev/null @@ -1,148 +0,0 @@ -// 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. - -// This file defines a C++ DescriptorDatabase, which wraps a Python Database -// and delegate all its operations to Python methods. - -#include <google/protobuf/pyext/descriptor_database.h> - -#include <google/protobuf/stubs/logging.h> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/pyext/message.h> -#include <google/protobuf/pyext/scoped_pyobject_ptr.h> - -namespace google { -namespace protobuf { -namespace python { - -PyDescriptorDatabase::PyDescriptorDatabase(PyObject* py_database) - : py_database_(py_database) { - Py_INCREF(py_database_); -} - -PyDescriptorDatabase::~PyDescriptorDatabase() { Py_DECREF(py_database_); } - -// Convert a Python object to a FileDescriptorProto pointer. -// Handles all kinds of Python errors, which are simply logged. -static bool GetFileDescriptorProto(PyObject* py_descriptor, - FileDescriptorProto* output) { - if (py_descriptor == NULL) { - if (PyErr_ExceptionMatches(PyExc_KeyError)) { - // Expected error: item was simply not found. - PyErr_Clear(); - } else { - GOOGLE_LOG(ERROR) << "DescriptorDatabase method raised an error"; - PyErr_Print(); - } - return false; - } - if (py_descriptor == Py_None) { - return false; - } - const Descriptor* filedescriptor_descriptor = - FileDescriptorProto::default_instance().GetDescriptor(); - CMessage* message = reinterpret_cast<CMessage*>(py_descriptor); - if (PyObject_TypeCheck(py_descriptor, &CMessage_Type) && - message->message->GetDescriptor() == filedescriptor_descriptor) { - // Fast path: Just use the pointer. - FileDescriptorProto* file_proto = - static_cast<FileDescriptorProto*>(message->message); - *output = *file_proto; - return true; - } else { - // Slow path: serialize the message. This allows to use databases which - // use a different implementation of FileDescriptorProto. - ScopedPyObjectPtr serialized_pb( - PyObject_CallMethod(py_descriptor, "SerializeToString", NULL)); - if (serialized_pb == NULL) { - GOOGLE_LOG(ERROR) - << "DescriptorDatabase method did not return a FileDescriptorProto"; - PyErr_Print(); - return false; - } - char* str; - Py_ssize_t len; - if (PyBytes_AsStringAndSize(serialized_pb.get(), &str, &len) < 0) { - GOOGLE_LOG(ERROR) - << "DescriptorDatabase method did not return a FileDescriptorProto"; - PyErr_Print(); - return false; - } - FileDescriptorProto file_proto; - if (!file_proto.ParseFromArray(str, len)) { - GOOGLE_LOG(ERROR) - << "DescriptorDatabase method did not return a FileDescriptorProto"; - return false; - } - *output = file_proto; - return true; - } -} - -// Find a file by file name. -bool PyDescriptorDatabase::FindFileByName(const string& filename, - FileDescriptorProto* output) { - ScopedPyObjectPtr py_descriptor(PyObject_CallMethod( - py_database_, "FindFileByName", "s#", filename.c_str(), filename.size())); - return GetFileDescriptorProto(py_descriptor.get(), output); -} - -// Find the file that declares the given fully-qualified symbol name. -bool PyDescriptorDatabase::FindFileContainingSymbol( - const string& symbol_name, FileDescriptorProto* output) { - ScopedPyObjectPtr py_descriptor( - PyObject_CallMethod(py_database_, "FindFileContainingSymbol", "s#", - symbol_name.c_str(), symbol_name.size())); - return GetFileDescriptorProto(py_descriptor.get(), output); -} - -// Find the file which defines an extension extending the given message type -// with the given field number. -// Python DescriptorDatabases are not required to implement this method. -bool PyDescriptorDatabase::FindFileContainingExtension( - const string& containing_type, int field_number, - FileDescriptorProto* output) { - ScopedPyObjectPtr py_method( - PyObject_GetAttrString(py_database_, "FindFileContainingExtension")); - if (py_method == NULL) { - // This method is not implemented, returns without error. - PyErr_Clear(); - return false; - } - ScopedPyObjectPtr py_descriptor( - PyObject_CallFunction(py_method.get(), "s#i", containing_type.c_str(), - containing_type.size(), field_number)); - return GetFileDescriptorProto(py_descriptor.get(), output); -} - -} // namespace python -} // namespace protobuf -} // namespace google diff --git a/python/google/protobuf/pyext/descriptor_database.h b/python/google/protobuf/pyext/descriptor_database.h deleted file mode 100644 index fc71c4bc..00000000 --- a/python/google/protobuf/pyext/descriptor_database.h +++ /dev/null @@ -1,75 +0,0 @@ -// 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. - -#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__ -#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__ - -#include <Python.h> - -#include <google/protobuf/descriptor_database.h> - -namespace google { -namespace protobuf { -namespace python { - -class PyDescriptorDatabase : public DescriptorDatabase { - public: - explicit PyDescriptorDatabase(PyObject* py_database); - ~PyDescriptorDatabase(); - - // Implement the abstract interface. All these functions fill the output - // with a copy of FileDescriptorProto. - - // Find a file by file name. - bool FindFileByName(const string& filename, - FileDescriptorProto* output); - - // Find the file that declares the given fully-qualified symbol name. - bool FindFileContainingSymbol(const string& symbol_name, - FileDescriptorProto* output); - - // Find the file which defines an extension extending the given message type - // with the given field number. - // Containing_type must be a fully-qualified type name. - // Python objects are not required to implement this method. - bool FindFileContainingExtension(const string& containing_type, - int field_number, - FileDescriptorProto* output); - - private: - // The python object that implements the database. The reference is owned. - PyObject* py_database_; -}; - -} // namespace python -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__ diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc deleted file mode 100644 index cfd98690..00000000 --- a/python/google/protobuf/pyext/descriptor_pool.cc +++ /dev/null @@ -1,631 +0,0 @@ -// 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. - -// Implements the DescriptorPool, which collects all descriptors. - -#include <Python.h> - -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/dynamic_message.h> -#include <google/protobuf/pyext/descriptor.h> -#include <google/protobuf/pyext/descriptor_database.h> -#include <google/protobuf/pyext/descriptor_pool.h> -#include <google/protobuf/pyext/message.h> -#include <google/protobuf/pyext/scoped_pyobject_ptr.h> - -#if PY_MAJOR_VERSION >= 3 - #define PyString_FromStringAndSize PyUnicode_FromStringAndSize - #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 { - -// A map to cache Python Pools per C++ pointer. -// Pointers are not owned here, and belong to the PyDescriptorPool. -static hash_map<const DescriptorPool*, PyDescriptorPool*> descriptor_pool_map; - -namespace cdescriptor_pool { - -// Create a Python DescriptorPool object, but does not fill the "pool" -// attribute. -static PyDescriptorPool* _CreateDescriptorPool() { - PyDescriptorPool* cpool = PyObject_New( - PyDescriptorPool, &PyDescriptorPool_Type); - if (cpool == NULL) { - return NULL; - } - - cpool->underlay = NULL; - cpool->database = NULL; - - DynamicMessageFactory* message_factory = new DynamicMessageFactory(); - // This option might be the default some day. - message_factory->SetDelegateToGeneratedFactory(true); - cpool->message_factory = message_factory; - - // TODO(amauryfa): Rewrite the SymbolDatabase in C so that it uses the same - // storage. - cpool->classes_by_descriptor = - new PyDescriptorPool::ClassesByMessageMap(); - cpool->descriptor_options = - new hash_map<const void*, PyObject *>(); - - return cpool; -} - -// Create a Python DescriptorPool, using the given pool as an underlay: -// new messages will be added to a custom pool, not to the underlay. -// -// Ownership of the underlay is not transferred, its pointer should -// stay alive. -static PyDescriptorPool* PyDescriptorPool_NewWithUnderlay( - const DescriptorPool* underlay) { - PyDescriptorPool* cpool = _CreateDescriptorPool(); - if (cpool == NULL) { - return NULL; - } - cpool->pool = new DescriptorPool(underlay); - cpool->underlay = underlay; - - if (!descriptor_pool_map.insert( - std::make_pair(cpool->pool, cpool)).second) { - // Should never happen -- would indicate an internal error / bug. - PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered"); - return NULL; - } - - return cpool; -} - -static PyDescriptorPool* PyDescriptorPool_NewWithDatabase( - DescriptorDatabase* database) { - PyDescriptorPool* cpool = _CreateDescriptorPool(); - if (cpool == NULL) { - return NULL; - } - if (database != NULL) { - cpool->pool = new DescriptorPool(database); - cpool->database = database; - } else { - cpool->pool = new DescriptorPool(); - } - - if (!descriptor_pool_map.insert(std::make_pair(cpool->pool, cpool)).second) { - // Should never happen -- would indicate an internal error / bug. - PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered"); - return NULL; - } - - return cpool; -} - -// The public DescriptorPool constructor. -static PyObject* New(PyTypeObject* type, - PyObject* args, PyObject* kwargs) { - static char* kwlist[] = {"descriptor_db", 0}; - PyObject* py_database = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &py_database)) { - return NULL; - } - DescriptorDatabase* database = NULL; - if (py_database && py_database != Py_None) { - database = new PyDescriptorDatabase(py_database); - } - return reinterpret_cast<PyObject*>( - PyDescriptorPool_NewWithDatabase(database)); -} - -static void Dealloc(PyDescriptorPool* self) { - typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator; - descriptor_pool_map.erase(self->pool); - for (iterator it = self->classes_by_descriptor->begin(); - it != self->classes_by_descriptor->end(); ++it) { - Py_DECREF(it->second); - } - delete self->classes_by_descriptor; - for (hash_map<const void*, PyObject*>::iterator it = - self->descriptor_options->begin(); - it != self->descriptor_options->end(); ++it) { - Py_DECREF(it->second); - } - delete self->descriptor_options; - delete self->message_factory; - delete self->database; - delete self->pool; - Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); -} - -PyObject* FindMessageByName(PyDescriptorPool* self, PyObject* arg) { - Py_ssize_t name_size; - char* name; - if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { - return NULL; - } - - const Descriptor* message_descriptor = - self->pool->FindMessageTypeByName(string(name, name_size)); - - if (message_descriptor == NULL) { - PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name); - return NULL; - } - - return PyMessageDescriptor_FromDescriptor(message_descriptor); -} - -// Add a message class to our database. -int RegisterMessageClass(PyDescriptorPool* self, - const Descriptor* message_descriptor, - CMessageClass* message_class) { - Py_INCREF(message_class); - typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator; - std::pair<iterator, bool> ret = self->classes_by_descriptor->insert( - std::make_pair(message_descriptor, message_class)); - if (!ret.second) { - // Update case: DECREF the previous value. - Py_DECREF(ret.first->second); - ret.first->second = message_class; - } - return 0; -} - -// Retrieve the message class added to our database. -CMessageClass* GetMessageClass(PyDescriptorPool* self, - const Descriptor* message_descriptor) { - typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator; - iterator ret = self->classes_by_descriptor->find(message_descriptor); - if (ret == self->classes_by_descriptor->end()) { - PyErr_Format(PyExc_TypeError, "No message class registered for '%s'", - message_descriptor->full_name().c_str()); - return NULL; - } else { - return ret->second; - } -} - -PyObject* FindFileByName(PyDescriptorPool* self, PyObject* arg) { - Py_ssize_t name_size; - char* name; - if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { - return NULL; - } - - const FileDescriptor* file_descriptor = - self->pool->FindFileByName(string(name, name_size)); - if (file_descriptor == NULL) { - PyErr_Format(PyExc_KeyError, "Couldn't find file %.200s", - name); - return NULL; - } - - return PyFileDescriptor_FromDescriptor(file_descriptor); -} - -PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* arg) { - Py_ssize_t name_size; - char* name; - if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { - return NULL; - } - - const FieldDescriptor* field_descriptor = - self->pool->FindFieldByName(string(name, name_size)); - if (field_descriptor == NULL) { - PyErr_Format(PyExc_KeyError, "Couldn't find field %.200s", - name); - return NULL; - } - - return PyFieldDescriptor_FromDescriptor(field_descriptor); -} - -PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) { - Py_ssize_t name_size; - char* name; - if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { - return NULL; - } - - const FieldDescriptor* field_descriptor = - self->pool->FindExtensionByName(string(name, name_size)); - if (field_descriptor == NULL) { - PyErr_Format(PyExc_KeyError, "Couldn't find extension field %.200s", name); - return NULL; - } - - return PyFieldDescriptor_FromDescriptor(field_descriptor); -} - -PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg) { - Py_ssize_t name_size; - char* name; - if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { - return NULL; - } - - const EnumDescriptor* enum_descriptor = - self->pool->FindEnumTypeByName(string(name, name_size)); - if (enum_descriptor == NULL) { - PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name); - return NULL; - } - - return PyEnumDescriptor_FromDescriptor(enum_descriptor); -} - -PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) { - Py_ssize_t name_size; - char* name; - if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { - return NULL; - } - - const OneofDescriptor* oneof_descriptor = - self->pool->FindOneofByName(string(name, name_size)); - if (oneof_descriptor == NULL) { - PyErr_Format(PyExc_KeyError, "Couldn't find oneof %.200s", name); - return NULL; - } - - return PyOneofDescriptor_FromDescriptor(oneof_descriptor); -} - -PyObject* FindServiceByName(PyDescriptorPool* self, PyObject* arg) { - Py_ssize_t name_size; - char* name; - if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { - return NULL; - } - - const ServiceDescriptor* service_descriptor = - self->pool->FindServiceByName(string(name, name_size)); - if (service_descriptor == NULL) { - PyErr_Format(PyExc_KeyError, "Couldn't find service %.200s", name); - return NULL; - } - - return PyServiceDescriptor_FromDescriptor(service_descriptor); -} - -PyObject* FindMethodByName(PyDescriptorPool* self, PyObject* arg) { - Py_ssize_t name_size; - char* name; - if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { - return NULL; - } - - const MethodDescriptor* method_descriptor = - self->pool->FindMethodByName(string(name, name_size)); - if (method_descriptor == NULL) { - PyErr_Format(PyExc_KeyError, "Couldn't find method %.200s", name); - return NULL; - } - - return PyMethodDescriptor_FromDescriptor(method_descriptor); -} - -PyObject* FindFileContainingSymbol(PyDescriptorPool* self, PyObject* arg) { - Py_ssize_t name_size; - char* name; - if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { - return NULL; - } - - const FileDescriptor* file_descriptor = - self->pool->FindFileContainingSymbol(string(name, name_size)); - if (file_descriptor == NULL) { - PyErr_Format(PyExc_KeyError, "Couldn't find symbol %.200s", name); - return NULL; - } - - return PyFileDescriptor_FromDescriptor(file_descriptor); -} - -// These functions should not exist -- the only valid way to create -// descriptors is to call Add() or AddSerializedFile(). -// But these AddDescriptor() functions were created in Python and some people -// call them, so we support them for now for compatibility. -// However we do check that the existing descriptor already exists in the pool, -// which appears to always be true for existing calls -- but then why do people -// call a function that will just be a no-op? -// TODO(amauryfa): Need to investigate further. - -PyObject* AddFileDescriptor(PyDescriptorPool* self, PyObject* descriptor) { - const FileDescriptor* file_descriptor = - PyFileDescriptor_AsDescriptor(descriptor); - if (!file_descriptor) { - return NULL; - } - if (file_descriptor != - self->pool->FindFileByName(file_descriptor->name())) { - PyErr_Format(PyExc_ValueError, - "The file descriptor %s does not belong to this pool", - file_descriptor->name().c_str()); - return NULL; - } - Py_RETURN_NONE; -} - -PyObject* AddDescriptor(PyDescriptorPool* self, PyObject* descriptor) { - const Descriptor* message_descriptor = - PyMessageDescriptor_AsDescriptor(descriptor); - if (!message_descriptor) { - return NULL; - } - if (message_descriptor != - self->pool->FindMessageTypeByName(message_descriptor->full_name())) { - PyErr_Format(PyExc_ValueError, - "The message descriptor %s does not belong to this pool", - message_descriptor->full_name().c_str()); - return NULL; - } - Py_RETURN_NONE; -} - -PyObject* AddEnumDescriptor(PyDescriptorPool* self, PyObject* descriptor) { - const EnumDescriptor* enum_descriptor = - PyEnumDescriptor_AsDescriptor(descriptor); - if (!enum_descriptor) { - return NULL; - } - if (enum_descriptor != - self->pool->FindEnumTypeByName(enum_descriptor->full_name())) { - PyErr_Format(PyExc_ValueError, - "The enum descriptor %s does not belong to this pool", - enum_descriptor->full_name().c_str()); - return NULL; - } - Py_RETURN_NONE; -} - -// The code below loads new Descriptors from a serialized FileDescriptorProto. - - -// Collects errors that occur during proto file building to allow them to be -// propagated in the python exception instead of only living in ERROR logs. -class BuildFileErrorCollector : public DescriptorPool::ErrorCollector { - public: - BuildFileErrorCollector() : error_message(""), had_errors(false) {} - - void AddError(const string& filename, const string& element_name, - const Message* descriptor, ErrorLocation location, - const string& message) { - // Replicates the logging behavior that happens in the C++ implementation - // when an error collector is not passed in. - if (!had_errors) { - error_message += - ("Invalid proto descriptor for file \"" + filename + "\":\n"); - had_errors = true; - } - // As this only happens on failure and will result in the program not - // running at all, no effort is made to optimize this string manipulation. - error_message += (" " + element_name + ": " + message + "\n"); - } - - string error_message; - bool had_errors; -}; - -PyObject* AddSerializedFile(PyDescriptorPool* self, PyObject* serialized_pb) { - char* message_type; - Py_ssize_t message_len; - - if (self->database != NULL) { - PyErr_SetString( - PyExc_ValueError, - "Cannot call Add on a DescriptorPool that uses a DescriptorDatabase. " - "Add your file to the underlying database."); - return NULL; - } - - if (PyBytes_AsStringAndSize(serialized_pb, &message_type, &message_len) < 0) { - return NULL; - } - - FileDescriptorProto file_proto; - if (!file_proto.ParseFromArray(message_type, message_len)) { - PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!"); - return NULL; - } - - // If the file was already part of a C++ library, all its descriptors are in - // the underlying pool. No need to do anything else. - const FileDescriptor* generated_file = NULL; - if (self->underlay) { - generated_file = self->underlay->FindFileByName(file_proto.name()); - } - if (generated_file != NULL) { - return PyFileDescriptor_FromDescriptorWithSerializedPb( - generated_file, serialized_pb); - } - - BuildFileErrorCollector error_collector; - const FileDescriptor* descriptor = - self->pool->BuildFileCollectingErrors(file_proto, - &error_collector); - if (descriptor == NULL) { - PyErr_Format(PyExc_TypeError, - "Couldn't build proto file into descriptor pool!\n%s", - error_collector.error_message.c_str()); - return NULL; - } - - return PyFileDescriptor_FromDescriptorWithSerializedPb( - descriptor, serialized_pb); -} - -PyObject* Add(PyDescriptorPool* self, PyObject* file_descriptor_proto) { - ScopedPyObjectPtr serialized_pb( - PyObject_CallMethod(file_descriptor_proto, "SerializeToString", NULL)); - if (serialized_pb == NULL) { - return NULL; - } - return AddSerializedFile(self, serialized_pb.get()); -} - -static PyMethodDef Methods[] = { - { "Add", (PyCFunction)Add, METH_O, - "Adds the FileDescriptorProto and its types to this pool." }, - { "AddSerializedFile", (PyCFunction)AddSerializedFile, METH_O, - "Adds a serialized FileDescriptorProto to this pool." }, - - // TODO(amauryfa): Understand why the Python implementation differs from - // this one, ask users to use another API and deprecate these functions. - { "AddFileDescriptor", (PyCFunction)AddFileDescriptor, METH_O, - "No-op. Add() must have been called before." }, - { "AddDescriptor", (PyCFunction)AddDescriptor, METH_O, - "No-op. Add() must have been called before." }, - { "AddEnumDescriptor", (PyCFunction)AddEnumDescriptor, METH_O, - "No-op. Add() must have been called before." }, - - { "FindFileByName", (PyCFunction)FindFileByName, METH_O, - "Searches for a file descriptor by its .proto name." }, - { "FindMessageTypeByName", (PyCFunction)FindMessageByName, METH_O, - "Searches for a message descriptor by full name." }, - { "FindFieldByName", (PyCFunction)FindFieldByName, METH_O, - "Searches for a field descriptor by full name." }, - { "FindExtensionByName", (PyCFunction)FindExtensionByName, METH_O, - "Searches for extension descriptor by full name." }, - { "FindEnumTypeByName", (PyCFunction)FindEnumTypeByName, METH_O, - "Searches for enum type descriptor by full name." }, - { "FindOneofByName", (PyCFunction)FindOneofByName, METH_O, - "Searches for oneof descriptor by full name." }, - { "FindServiceByName", (PyCFunction)FindServiceByName, METH_O, - "Searches for service descriptor by full name." }, - { "FindMethodByName", (PyCFunction)FindMethodByName, METH_O, - "Searches for method descriptor by full name." }, - - { "FindFileContainingSymbol", (PyCFunction)FindFileContainingSymbol, METH_O, - "Gets the FileDescriptor containing the specified symbol." }, - {NULL} -}; - -} // namespace cdescriptor_pool - -PyTypeObject PyDescriptorPool_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".DescriptorPool", // tp_name - sizeof(PyDescriptorPool), // tp_basicsize - 0, // tp_itemsize - (destructor)cdescriptor_pool::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 - "A Descriptor Pool", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - cdescriptor_pool::Methods, // 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 - cdescriptor_pool::New, // tp_new - PyObject_Del, // tp_free -}; - -// This is the DescriptorPool which contains all the definitions from the -// generated _pb2.py modules. -static PyDescriptorPool* python_generated_pool = NULL; - -bool InitDescriptorPool() { - if (PyType_Ready(&PyDescriptorPool_Type) < 0) - return false; - - // The Pool of messages declared in Python libraries. - // generated_pool() contains all messages already linked in C++ libraries, and - // is used as underlay. - python_generated_pool = cdescriptor_pool::PyDescriptorPool_NewWithUnderlay( - DescriptorPool::generated_pool()); - if (python_generated_pool == NULL) { - return false; - } - // Register this pool to be found for C++-generated descriptors. - descriptor_pool_map.insert( - std::make_pair(DescriptorPool::generated_pool(), - python_generated_pool)); - - return true; -} - -// The default DescriptorPool used everywhere in this module. -// Today it's the python_generated_pool. -// TODO(amauryfa): Remove all usages of this function: the pool should be -// derived from the context. -PyDescriptorPool* GetDefaultDescriptorPool() { - return python_generated_pool; -} - -PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool) { - // Fast path for standard descriptors. - if (pool == python_generated_pool->pool || - pool == DescriptorPool::generated_pool()) { - return python_generated_pool; - } - hash_map<const DescriptorPool*, PyDescriptorPool*>::iterator it = - descriptor_pool_map.find(pool); - if (it == descriptor_pool_map.end()) { - PyErr_SetString(PyExc_KeyError, "Unknown descriptor pool"); - return NULL; - } - return it->second; -} - -} // namespace python -} // namespace protobuf -} // namespace google diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h deleted file mode 100644 index 2a42c112..00000000 --- a/python/google/protobuf/pyext/descriptor_pool.h +++ /dev/null @@ -1,167 +0,0 @@ -// 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. - -#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__ -#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__ - -#include <Python.h> - -#include <google/protobuf/stubs/hash.h> -#include <google/protobuf/descriptor.h> - -namespace google { -namespace protobuf { -class MessageFactory; - -namespace python { - -// The (meta) type of all Messages classes. -struct CMessageClass; - -// Wraps operations to the global DescriptorPool which contains information -// about all messages and fields. -// -// There is normally one pool per process. We make it a Python object only -// because it contains many Python references. -// TODO(amauryfa): See whether such objects can appear in reference cycles, and -// consider adding support for the cyclic GC. -// -// "Methods" that interacts with this DescriptorPool are in the cdescriptor_pool -// namespace. -typedef struct PyDescriptorPool { - PyObject_HEAD - - // The C++ pool containing Descriptors. - DescriptorPool* pool; - - // The C++ pool acting as an underlay. Can be NULL. - // This pointer is not owned and must stay alive. - const DescriptorPool* underlay; - - // The C++ descriptor database used to fetch unknown protos. Can be NULL. - // This pointer is owned. - const DescriptorDatabase* database; - - // DynamicMessageFactory used to create C++ instances of messages. - // This object cache the descriptors that were used, so the DescriptorPool - // needs to get rid of it before it can delete itself. - // - // Note: A C++ MessageFactory is different from the Python MessageFactory. - // The C++ one creates messages, when the Python one creates classes. - MessageFactory* message_factory; - - // Make our own mapping to retrieve Python classes from C++ descriptors. - // - // Descriptor pointers stored here are owned by the DescriptorPool above. - // Python references to classes are owned by this PyDescriptorPool. - typedef hash_map<const Descriptor*, CMessageClass*> ClassesByMessageMap; - ClassesByMessageMap* classes_by_descriptor; - - // Cache the options for any kind of descriptor. - // Descriptor pointers are owned by the DescriptorPool above. - // Python objects are owned by the map. - hash_map<const void*, PyObject*>* descriptor_options; -} PyDescriptorPool; - - -extern PyTypeObject PyDescriptorPool_Type; - -namespace cdescriptor_pool { - -// Looks up a message by name. -// Returns a message Descriptor, or NULL if not found. -const Descriptor* FindMessageTypeByName(PyDescriptorPool* self, - const string& name); - -// Registers a new Python class for the given message descriptor. -// On error, returns -1 with a Python exception set. -int RegisterMessageClass(PyDescriptorPool* self, - const Descriptor* message_descriptor, - CMessageClass* message_class); - -// Retrieves the Python class registered with the given message descriptor. -// -// Returns a *borrowed* reference if found, otherwise returns NULL with an -// exception set. -CMessageClass* GetMessageClass(PyDescriptorPool* self, - const Descriptor* message_descriptor); - -// The functions below are also exposed as methods of the DescriptorPool type. - -// Looks up a message by name. Returns a PyMessageDescriptor corresponding to -// the field on success, or NULL on failure. -// -// Returns a new reference. -PyObject* FindMessageByName(PyDescriptorPool* self, PyObject* name); - -// Looks up a field by name. Returns a PyFieldDescriptor corresponding to -// the field on success, or NULL on failure. -// -// Returns a new reference. -PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* name); - -// Looks up an extension by name. Returns a PyFieldDescriptor corresponding -// to the field on success, or NULL on failure. -// -// Returns a new reference. -PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg); - -// Looks up an enum type by name. Returns a PyEnumDescriptor corresponding -// to the field on success, or NULL on failure. -// -// Returns a new reference. -PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg); - -// Looks up a oneof by name. Returns a COneofDescriptor corresponding -// to the oneof on success, or NULL on failure. -// -// Returns a new reference. -PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg); - -} // namespace cdescriptor_pool - -// Retrieve the global descriptor pool owned by the _message module. -// This is the one used by pb2.py generated modules. -// Returns a *borrowed* reference. -// "Default" pool used to register messages from _pb2.py modules. -PyDescriptorPool* GetDefaultDescriptorPool(); - -// Retrieve the python descriptor pool owning a C++ descriptor pool. -// Returns a *borrowed* reference. -PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool); - -// Initialize objects used by this module. -bool InitDescriptorPool(); - -} // namespace python -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__ diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc deleted file mode 100644 index 21bbb8c2..00000000 --- a/python/google/protobuf/pyext/extension_dict.cc +++ /dev/null @@ -1,337 +0,0 @@ -// 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. - -// Author: anuraag@google.com (Anuraag Agrawal) -// Author: tibell@google.com (Johan Tibell) - -#include <google/protobuf/pyext/extension_dict.h> - -#include <google/protobuf/stubs/logging.h> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/dynamic_message.h> -#include <google/protobuf/message.h> -#include <google/protobuf/pyext/descriptor.h> -#include <google/protobuf/pyext/descriptor_pool.h> -#include <google/protobuf/pyext/message.h> -#include <google/protobuf/pyext/repeated_composite_container.h> -#include <google/protobuf/pyext/repeated_scalar_container.h> -#include <google/protobuf/pyext/scoped_pyobject_ptr.h> -#include <google/protobuf/stubs/shared_ptr.h> - -namespace google { -namespace protobuf { -namespace python { - -namespace extension_dict { - -PyObject* len(ExtensionDict* self) { -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(PyDict_Size(self->values)); -#else - return PyInt_FromLong(PyDict_Size(self->values)); -#endif -} - -// TODO(tibell): Use VisitCompositeField. -int ReleaseExtension(ExtensionDict* self, - PyObject* extension, - const FieldDescriptor* descriptor) { - if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) { - if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (repeated_composite_container::Release( - reinterpret_cast<RepeatedCompositeContainer*>( - extension)) < 0) { - return -1; - } - } else { - if (repeated_scalar_container::Release( - reinterpret_cast<RepeatedScalarContainer*>( - extension)) < 0) { - return -1; - } - } - } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (cmessage::ReleaseSubMessage( - self->parent, descriptor, - reinterpret_cast<CMessage*>(extension)) < 0) { - return -1; - } - } - - return 0; -} - -PyObject* subscript(ExtensionDict* self, PyObject* key) { - const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key); - if (descriptor == NULL) { - return NULL; - } - if (!CheckFieldBelongsToMessage(descriptor, self->message)) { - return NULL; - } - - if (descriptor->label() != FieldDescriptor::LABEL_REPEATED && - descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { - return cmessage::InternalGetScalar(self->message, descriptor); - } - - PyObject* value = PyDict_GetItem(self->values, key); - if (value != NULL) { - Py_INCREF(value); - return value; - } - - if (self->parent == NULL) { - // We are in "detached" state. Don't allow further modifications. - // TODO(amauryfa): Support adding non-scalars to a detached extension dict. - // This probably requires to store the type of the main message. - PyErr_SetObject(PyExc_KeyError, key); - return NULL; - } - - if (descriptor->label() != FieldDescriptor::LABEL_REPEATED && - descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - PyObject* sub_message = cmessage::InternalGetSubMessage( - self->parent, descriptor); - if (sub_message == NULL) { - return NULL; - } - PyDict_SetItem(self->values, key, sub_message); - return sub_message; - } - - if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) { - if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - CMessageClass* message_class = cdescriptor_pool::GetMessageClass( - cmessage::GetDescriptorPoolForMessage(self->parent), - descriptor->message_type()); - if (message_class == NULL) { - return NULL; - } - PyObject* py_container = repeated_composite_container::NewContainer( - self->parent, descriptor, message_class); - if (py_container == NULL) { - return NULL; - } - PyDict_SetItem(self->values, key, py_container); - return py_container; - } else { - PyObject* py_container = repeated_scalar_container::NewContainer( - self->parent, descriptor); - if (py_container == NULL) { - return NULL; - } - PyDict_SetItem(self->values, key, py_container); - return py_container; - } - } - PyErr_SetString(PyExc_ValueError, "control reached unexpected line"); - return NULL; -} - -int ass_subscript(ExtensionDict* self, PyObject* key, PyObject* value) { - const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key); - if (descriptor == NULL) { - return -1; - } - if (!CheckFieldBelongsToMessage(descriptor, self->message)) { - return -1; - } - - if (descriptor->label() != FieldDescriptor::LABEL_OPTIONAL || - descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - PyErr_SetString(PyExc_TypeError, "Extension is repeated and/or composite " - "type"); - return -1; - } - if (self->parent) { - cmessage::AssureWritable(self->parent); - if (cmessage::InternalSetScalar(self->parent, descriptor, value) < 0) { - return -1; - } - } - // TODO(tibell): We shouldn't write scalars to the cache. - PyDict_SetItem(self->values, key, value); - return 0; -} - -PyObject* ClearExtension(ExtensionDict* self, PyObject* extension) { - const FieldDescriptor* descriptor = - cmessage::GetExtensionDescriptor(extension); - if (descriptor == NULL) { - return NULL; - } - PyObject* value = PyDict_GetItem(self->values, extension); - if (self->parent) { - if (value != NULL) { - if (ReleaseExtension(self, value, descriptor) < 0) { - return NULL; - } - } - if (ScopedPyObjectPtr(cmessage::ClearFieldByDescriptor( - self->parent, descriptor)) == NULL) { - return NULL; - } - } - if (PyDict_DelItem(self->values, extension) < 0) { - PyErr_Clear(); - } - Py_RETURN_NONE; -} - -PyObject* HasExtension(ExtensionDict* self, PyObject* extension) { - const FieldDescriptor* descriptor = - cmessage::GetExtensionDescriptor(extension); - if (descriptor == NULL) { - return NULL; - } - if (self->parent) { - return cmessage::HasFieldByDescriptor(self->parent, descriptor); - } else { - int exists = PyDict_Contains(self->values, extension); - if (exists < 0) { - return NULL; - } - return PyBool_FromLong(exists); - } -} - -PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name) { - ScopedPyObjectPtr extensions_by_name(PyObject_GetAttrString( - reinterpret_cast<PyObject*>(self->parent), "_extensions_by_name")); - if (extensions_by_name == NULL) { - return NULL; - } - PyObject* result = PyDict_GetItem(extensions_by_name.get(), name); - if (result == NULL) { - Py_RETURN_NONE; - } else { - Py_INCREF(result); - return result; - } -} - -PyObject* _FindExtensionByNumber(ExtensionDict* self, PyObject* number) { - ScopedPyObjectPtr extensions_by_number(PyObject_GetAttrString( - reinterpret_cast<PyObject*>(self->parent), "_extensions_by_number")); - if (extensions_by_number == NULL) { - return NULL; - } - PyObject* result = PyDict_GetItem(extensions_by_number.get(), number); - if (result == NULL) { - Py_RETURN_NONE; - } else { - Py_INCREF(result); - return result; - } -} - -ExtensionDict* NewExtensionDict(CMessage *parent) { - ExtensionDict* self = reinterpret_cast<ExtensionDict*>( - PyType_GenericAlloc(&ExtensionDict_Type, 0)); - if (self == NULL) { - return NULL; - } - - self->parent = parent; // Store a borrowed reference. - self->message = parent->message; - self->owner = parent->owner; - self->values = PyDict_New(); - return self; -} - -void dealloc(ExtensionDict* self) { - Py_CLEAR(self->values); - self->owner.reset(); - Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); -} - -static PyMappingMethods MpMethods = { - (lenfunc)len, /* mp_length */ - (binaryfunc)subscript, /* mp_subscript */ - (objobjargproc)ass_subscript,/* mp_ass_subscript */ -}; - -#define EDMETHOD(name, args, doc) { #name, (PyCFunction)name, args, doc } -static PyMethodDef Methods[] = { - EDMETHOD(ClearExtension, METH_O, "Clears an extension from the object."), - EDMETHOD(HasExtension, METH_O, "Checks if the object has an extension."), - EDMETHOD(_FindExtensionByName, METH_O, - "Finds an extension by name."), - EDMETHOD(_FindExtensionByNumber, METH_O, - "Finds an extension by field number."), - { NULL, NULL } -}; - -} // namespace extension_dict - -PyTypeObject ExtensionDict_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".ExtensionDict", // tp_name - sizeof(ExtensionDict), // tp_basicsize - 0, // tp_itemsize - (destructor)extension_dict::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 - &extension_dict::MpMethods, // tp_as_mapping - PyObject_HashNotImplemented, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "An extension dict", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - extension_dict::Methods, // 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 -}; - -} // namespace python -} // namespace protobuf -} // namespace google diff --git a/python/google/protobuf/pyext/extension_dict.h b/python/google/protobuf/pyext/extension_dict.h deleted file mode 100644 index 2456eda1..00000000 --- a/python/google/protobuf/pyext/extension_dict.h +++ /dev/null @@ -1,137 +0,0 @@ -// 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. - -// Author: anuraag@google.com (Anuraag Agrawal) -// Author: tibell@google.com (Johan Tibell) - -#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_EXTENSION_DICT_H__ -#define GOOGLE_PROTOBUF_PYTHON_CPP_EXTENSION_DICT_H__ - -#include <Python.h> - -#include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif - -namespace google { -namespace protobuf { - -class Message; -class FieldDescriptor; - -#ifdef _SHARED_PTR_H -using std::shared_ptr; -#else -using internal::shared_ptr; -#endif - -namespace python { - -struct CMessage; - -typedef struct ExtensionDict { - PyObject_HEAD; - - // This is the top-level C++ Message object that owns the whole - // proto tree. Every Python container class holds a - // reference to it in order to keep it alive as long as there's a - // Python object that references any part of the tree. - shared_ptr<Message> owner; - - // Weak reference to parent message. Used to make sure - // the parent is writable when an extension field is modified. - CMessage* parent; - - // Pointer to the C++ Message that this ExtensionDict extends. - // Not owned by us. - Message* message; - - // A dict of child messages, indexed by Extension descriptors. - // Similar to CMessage::composite_fields. - PyObject* values; -} ExtensionDict; - -extern PyTypeObject ExtensionDict_Type; - -namespace extension_dict { - -// Builds an Extensions dict for a specific message. -ExtensionDict* NewExtensionDict(CMessage *parent); - -// Gets the number of extension values in this ExtensionDict as a python object. -// -// Returns a new reference. -PyObject* len(ExtensionDict* self); - -// Releases extensions referenced outside this dictionary to keep outside -// references alive. -// -// Returns 0 on success, -1 on failure. -int ReleaseExtension(ExtensionDict* self, - PyObject* extension, - const FieldDescriptor* descriptor); - -// Gets an extension from the dict for the given extension descriptor. -// -// Returns a new reference. -PyObject* subscript(ExtensionDict* self, PyObject* key); - -// Assigns a value to an extension in the dict. Can only be used for singular -// simple types. -// -// Returns 0 on success, -1 on failure. -int ass_subscript(ExtensionDict* self, PyObject* key, PyObject* value); - -// Clears an extension from the dict. Will release the extension if there -// is still an external reference left to it. -// -// Returns None on success. -PyObject* ClearExtension(ExtensionDict* self, - PyObject* extension); - -// Gets an extension from the dict given the extension name as opposed to -// descriptor. -// -// Returns a new reference. -PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name); - -// Gets an extension from the dict given the extension field number as -// opposed to descriptor. -// -// Returns a new reference. -PyObject* _FindExtensionByNumber(ExtensionDict* self, PyObject* number); - -} // namespace extension_dict -} // namespace python -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_PYTHON_CPP_EXTENSION_DICT_H__ diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc deleted file mode 100644 index 90438df1..00000000 --- a/python/google/protobuf/pyext/map_container.cc +++ /dev/null @@ -1,969 +0,0 @@ -// 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. - -// Author: haberman@google.com (Josh Haberman) - -#include <google/protobuf/pyext/map_container.h> - -#include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif - -#include <google/protobuf/stubs/logging.h> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/map_field.h> -#include <google/protobuf/map.h> -#include <google/protobuf/message.h> -#include <google/protobuf/pyext/message.h> -#include <google/protobuf/pyext/scoped_pyobject_ptr.h> - -#if PY_MAJOR_VERSION >= 3 - #define PyInt_FromLong PyLong_FromLong - #define PyInt_FromSize_t PyLong_FromSize_t -#endif - -namespace google { -namespace protobuf { -namespace python { - -// Functions that need access to map reflection functionality. -// They need to be contained in this class because it is friended. -class MapReflectionFriend { - public: - // Methods that are in common between the map types. - static PyObject* Contains(PyObject* _self, PyObject* key); - static Py_ssize_t Length(PyObject* _self); - static PyObject* GetIterator(PyObject *_self); - static PyObject* IterNext(PyObject* _self); - - // Methods that differ between the map types. - static PyObject* ScalarMapGetItem(PyObject* _self, PyObject* key); - static PyObject* MessageMapGetItem(PyObject* _self, PyObject* key); - static int ScalarMapSetItem(PyObject* _self, PyObject* key, PyObject* v); - static int MessageMapSetItem(PyObject* _self, PyObject* key, PyObject* v); -}; - -struct MapIterator { - PyObject_HEAD; - - google::protobuf::scoped_ptr< ::google::protobuf::MapIterator> iter; - - // A pointer back to the container, so we can notice changes to the version. - // We own a ref on this. - MapContainer* container; - - // We need to keep a ref on the Message* too, because - // MapIterator::~MapIterator() accesses it. Normally this would be ok because - // the ref on container (above) would guarantee outlive semantics. However in - // the case of ClearField(), InitializeAndCopyToParentContainer() resets the - // message pointer (and the owner) to a different message, a copy of the - // original. But our iterator still points to the original, which could now - // get deleted before us. - // - // To prevent this, we ensure that the Message will always stay alive as long - // as this iterator does. This is solely for the benefit of the MapIterator - // destructor -- we should never actually access the iterator in this state - // except to delete it. - shared_ptr<Message> owner; - - // The version of the map when we took the iterator to it. - // - // We store this so that if the map is modified during iteration we can throw - // an error. - uint64 version; - - // True if the container is empty. We signal this separately to avoid calling - // any of the iteration methods, which are non-const. - bool empty; -}; - -Message* MapContainer::GetMutableMessage() { - cmessage::AssureWritable(parent); - return const_cast<Message*>(message); -} - -// Consumes a reference on the Python string object. -static bool PyStringToSTL(PyObject* py_string, string* stl_string) { - char *value; - Py_ssize_t value_len; - - if (!py_string) { - return false; - } - if (PyBytes_AsStringAndSize(py_string, &value, &value_len) < 0) { - Py_DECREF(py_string); - return false; - } else { - stl_string->assign(value, value_len); - Py_DECREF(py_string); - return true; - } -} - -static bool PythonToMapKey(PyObject* obj, - const FieldDescriptor* field_descriptor, - MapKey* key) { - switch (field_descriptor->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: { - GOOGLE_CHECK_GET_INT32(obj, value, false); - key->SetInt32Value(value); - break; - } - case FieldDescriptor::CPPTYPE_INT64: { - GOOGLE_CHECK_GET_INT64(obj, value, false); - key->SetInt64Value(value); - break; - } - case FieldDescriptor::CPPTYPE_UINT32: { - GOOGLE_CHECK_GET_UINT32(obj, value, false); - key->SetUInt32Value(value); - break; - } - case FieldDescriptor::CPPTYPE_UINT64: { - GOOGLE_CHECK_GET_UINT64(obj, value, false); - key->SetUInt64Value(value); - break; - } - case FieldDescriptor::CPPTYPE_BOOL: { - GOOGLE_CHECK_GET_BOOL(obj, value, false); - key->SetBoolValue(value); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - string str; - if (!PyStringToSTL(CheckString(obj, field_descriptor), &str)) { - return false; - } - key->SetStringValue(str); - break; - } - default: - PyErr_Format( - PyExc_SystemError, "Type %d cannot be a map key", - field_descriptor->cpp_type()); - return false; - } - return true; -} - -static PyObject* MapKeyToPython(const FieldDescriptor* field_descriptor, - const MapKey& key) { - switch (field_descriptor->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - return PyInt_FromLong(key.GetInt32Value()); - case FieldDescriptor::CPPTYPE_INT64: - return PyLong_FromLongLong(key.GetInt64Value()); - case FieldDescriptor::CPPTYPE_UINT32: - return PyInt_FromSize_t(key.GetUInt32Value()); - case FieldDescriptor::CPPTYPE_UINT64: - return PyLong_FromUnsignedLongLong(key.GetUInt64Value()); - case FieldDescriptor::CPPTYPE_BOOL: - return PyBool_FromLong(key.GetBoolValue()); - case FieldDescriptor::CPPTYPE_STRING: - return ToStringObject(field_descriptor, key.GetStringValue()); - default: - PyErr_Format( - PyExc_SystemError, "Couldn't convert type %d to value", - field_descriptor->cpp_type()); - return NULL; - } -} - -// This is only used for ScalarMap, so we don't need to handle the -// CPPTYPE_MESSAGE case. -PyObject* MapValueRefToPython(const FieldDescriptor* field_descriptor, - MapValueRef* value) { - switch (field_descriptor->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - return PyInt_FromLong(value->GetInt32Value()); - case FieldDescriptor::CPPTYPE_INT64: - return PyLong_FromLongLong(value->GetInt64Value()); - case FieldDescriptor::CPPTYPE_UINT32: - return PyInt_FromSize_t(value->GetUInt32Value()); - case FieldDescriptor::CPPTYPE_UINT64: - return PyLong_FromUnsignedLongLong(value->GetUInt64Value()); - case FieldDescriptor::CPPTYPE_FLOAT: - return PyFloat_FromDouble(value->GetFloatValue()); - case FieldDescriptor::CPPTYPE_DOUBLE: - return PyFloat_FromDouble(value->GetDoubleValue()); - case FieldDescriptor::CPPTYPE_BOOL: - return PyBool_FromLong(value->GetBoolValue()); - case FieldDescriptor::CPPTYPE_STRING: - return ToStringObject(field_descriptor, value->GetStringValue()); - case FieldDescriptor::CPPTYPE_ENUM: - return PyInt_FromLong(value->GetEnumValue()); - default: - PyErr_Format( - PyExc_SystemError, "Couldn't convert type %d to value", - field_descriptor->cpp_type()); - return NULL; - } -} - -// This is only used for ScalarMap, so we don't need to handle the -// CPPTYPE_MESSAGE case. -static bool PythonToMapValueRef(PyObject* obj, - const FieldDescriptor* field_descriptor, - bool allow_unknown_enum_values, - MapValueRef* value_ref) { - switch (field_descriptor->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: { - GOOGLE_CHECK_GET_INT32(obj, value, false); - value_ref->SetInt32Value(value); - return true; - } - case FieldDescriptor::CPPTYPE_INT64: { - GOOGLE_CHECK_GET_INT64(obj, value, false); - value_ref->SetInt64Value(value); - return true; - } - case FieldDescriptor::CPPTYPE_UINT32: { - GOOGLE_CHECK_GET_UINT32(obj, value, false); - value_ref->SetUInt32Value(value); - return true; - } - case FieldDescriptor::CPPTYPE_UINT64: { - GOOGLE_CHECK_GET_UINT64(obj, value, false); - value_ref->SetUInt64Value(value); - return true; - } - case FieldDescriptor::CPPTYPE_FLOAT: { - GOOGLE_CHECK_GET_FLOAT(obj, value, false); - value_ref->SetFloatValue(value); - return true; - } - case FieldDescriptor::CPPTYPE_DOUBLE: { - GOOGLE_CHECK_GET_DOUBLE(obj, value, false); - value_ref->SetDoubleValue(value); - return true; - } - case FieldDescriptor::CPPTYPE_BOOL: { - GOOGLE_CHECK_GET_BOOL(obj, value, false); - value_ref->SetBoolValue(value); - return true;; - } - case FieldDescriptor::CPPTYPE_STRING: { - string str; - if (!PyStringToSTL(CheckString(obj, field_descriptor), &str)) { - return false; - } - value_ref->SetStringValue(str); - return true; - } - case FieldDescriptor::CPPTYPE_ENUM: { - GOOGLE_CHECK_GET_INT32(obj, value, false); - if (allow_unknown_enum_values) { - value_ref->SetEnumValue(value); - return true; - } else { - const EnumDescriptor* enum_descriptor = field_descriptor->enum_type(); - const EnumValueDescriptor* enum_value = - enum_descriptor->FindValueByNumber(value); - if (enum_value != NULL) { - value_ref->SetEnumValue(value); - return true; - } else { - PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value); - return false; - } - } - break; - } - default: - PyErr_Format( - PyExc_SystemError, "Setting value to a field of unknown type %d", - field_descriptor->cpp_type()); - return false; - } -} - -// Map methods common to ScalarMap and MessageMap ////////////////////////////// - -static MapContainer* GetMap(PyObject* obj) { - return reinterpret_cast<MapContainer*>(obj); -} - -Py_ssize_t MapReflectionFriend::Length(PyObject* _self) { - MapContainer* self = GetMap(_self); - const google::protobuf::Message* message = self->message; - return message->GetReflection()->MapSize(*message, - self->parent_field_descriptor); -} - -PyObject* Clear(PyObject* _self) { - MapContainer* self = GetMap(_self); - Message* message = self->GetMutableMessage(); - const Reflection* reflection = message->GetReflection(); - - reflection->ClearField(message, self->parent_field_descriptor); - - Py_RETURN_NONE; -} - -PyObject* MapReflectionFriend::Contains(PyObject* _self, PyObject* key) { - MapContainer* self = GetMap(_self); - - const Message* message = self->message; - const Reflection* reflection = message->GetReflection(); - MapKey map_key; - - if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) { - return NULL; - } - - if (reflection->ContainsMapKey(*message, self->parent_field_descriptor, - map_key)) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} - -// Initializes the underlying Message object of "to" so it becomes a new parent -// repeated scalar, and copies all the values from "from" to it. A child scalar -// container can be released by passing it as both from and to (e.g. making it -// the recipient of the new parent message and copying the values from itself). -static int InitializeAndCopyToParentContainer(MapContainer* from, - MapContainer* to) { - // For now we require from == to, re-evaluate if we want to support deep copy - // as in repeated_scalar_container.cc. - GOOGLE_DCHECK(from == to); - Message* new_message = from->message->New(); - - if (MapReflectionFriend::Length(reinterpret_cast<PyObject*>(from)) > 0) { - // A somewhat roundabout way of copying just one field from old_message to - // new_message. This is the best we can do with what Reflection gives us. - Message* mutable_old = from->GetMutableMessage(); - vector<const FieldDescriptor*> fields; - fields.push_back(from->parent_field_descriptor); - - // Move the map field into the new message. - mutable_old->GetReflection()->SwapFields(mutable_old, new_message, fields); - - // If/when we support from != to, this will be required also to copy the - // map field back into the existing message: - // mutable_old->MergeFrom(*new_message); - } - - // If from == to this could delete old_message. - to->owner.reset(new_message); - - to->parent = NULL; - to->parent_field_descriptor = from->parent_field_descriptor; - to->message = new_message; - - // Invalidate iterators, since they point to the old copy of the field. - to->version++; - - return 0; -} - -int MapContainer::Release() { - return InitializeAndCopyToParentContainer(this, this); -} - - -// ScalarMap /////////////////////////////////////////////////////////////////// - -PyObject *NewScalarMapContainer( - CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor) { - if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) { - return NULL; - } - -#if PY_MAJOR_VERSION >= 3 - ScopedPyObjectPtr obj(PyType_GenericAlloc( - reinterpret_cast<PyTypeObject *>(ScalarMapContainer_Type), 0)); -#else - ScopedPyObjectPtr obj(PyType_GenericAlloc(&ScalarMapContainer_Type, 0)); -#endif - if (obj.get() == NULL) { - return PyErr_Format(PyExc_RuntimeError, - "Could not allocate new container."); - } - - MapContainer* self = GetMap(obj.get()); - - self->message = parent->message; - self->parent = parent; - self->parent_field_descriptor = parent_field_descriptor; - self->owner = parent->owner; - self->version = 0; - - self->key_field_descriptor = - parent_field_descriptor->message_type()->FindFieldByName("key"); - self->value_field_descriptor = - parent_field_descriptor->message_type()->FindFieldByName("value"); - - if (self->key_field_descriptor == NULL || - self->value_field_descriptor == NULL) { - return PyErr_Format(PyExc_KeyError, - "Map entry descriptor did not have key/value fields"); - } - - return obj.release(); -} - -PyObject* MapReflectionFriend::ScalarMapGetItem(PyObject* _self, - PyObject* key) { - MapContainer* self = GetMap(_self); - - Message* message = self->GetMutableMessage(); - const Reflection* reflection = message->GetReflection(); - MapKey map_key; - MapValueRef value; - - if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) { - return NULL; - } - - if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor, - map_key, &value)) { - self->version++; - } - - return MapValueRefToPython(self->value_field_descriptor, &value); -} - -int MapReflectionFriend::ScalarMapSetItem(PyObject* _self, PyObject* key, - PyObject* v) { - MapContainer* self = GetMap(_self); - - Message* message = self->GetMutableMessage(); - const Reflection* reflection = message->GetReflection(); - MapKey map_key; - MapValueRef value; - - if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) { - return -1; - } - - self->version++; - - if (v) { - // Set item to v. - reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor, - map_key, &value); - - return PythonToMapValueRef(v, self->value_field_descriptor, - reflection->SupportsUnknownEnumValues(), &value) - ? 0 - : -1; - } else { - // Delete key from map. - if (reflection->DeleteMapValue(message, self->parent_field_descriptor, - map_key)) { - return 0; - } else { - PyErr_Format(PyExc_KeyError, "Key not present in map"); - return -1; - } - } -} - -static PyObject* ScalarMapGet(PyObject* self, PyObject* args) { - PyObject* key; - PyObject* default_value = NULL; - if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) { - return NULL; - } - - ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key)); - if (is_present.get() == NULL) { - return NULL; - } - - if (PyObject_IsTrue(is_present.get())) { - return MapReflectionFriend::ScalarMapGetItem(self, key); - } else { - if (default_value != NULL) { - Py_INCREF(default_value); - return default_value; - } else { - Py_RETURN_NONE; - } - } -} - -static void ScalarMapDealloc(PyObject* _self) { - MapContainer* self = GetMap(_self); - self->owner.reset(); - Py_TYPE(_self)->tp_free(_self); -} - -static PyMethodDef ScalarMapMethods[] = { - { "__contains__", MapReflectionFriend::Contains, METH_O, - "Tests whether a key is a member of the map." }, - { "clear", (PyCFunction)Clear, METH_NOARGS, - "Removes all elements from the map." }, - { "get", ScalarMapGet, METH_VARARGS, - "Gets the value for the given key if present, or otherwise a default" }, - /* - { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS, - "Makes a deep copy of the class." }, - { "__reduce__", (PyCFunction)Reduce, METH_NOARGS, - "Outputs picklable representation of the repeated field." }, - */ - {NULL, NULL}, -}; - -#if PY_MAJOR_VERSION >= 3 - static PyType_Slot ScalarMapContainer_Type_slots[] = { - {Py_tp_dealloc, (void *)ScalarMapDealloc}, - {Py_mp_length, (void *)MapReflectionFriend::Length}, - {Py_mp_subscript, (void *)MapReflectionFriend::ScalarMapGetItem}, - {Py_mp_ass_subscript, (void *)MapReflectionFriend::ScalarMapSetItem}, - {Py_tp_methods, (void *)ScalarMapMethods}, - {Py_tp_iter, (void *)MapReflectionFriend::GetIterator}, - {0, 0}, - }; - - PyType_Spec ScalarMapContainer_Type_spec = { - FULL_MODULE_NAME ".ScalarMapContainer", - sizeof(MapContainer), - 0, - Py_TPFLAGS_DEFAULT, - ScalarMapContainer_Type_slots - }; - PyObject *ScalarMapContainer_Type; -#else - static PyMappingMethods ScalarMapMappingMethods = { - MapReflectionFriend::Length, // mp_length - MapReflectionFriend::ScalarMapGetItem, // mp_subscript - MapReflectionFriend::ScalarMapSetItem, // mp_ass_subscript - }; - - PyTypeObject ScalarMapContainer_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".ScalarMapContainer", // tp_name - sizeof(MapContainer), // tp_basicsize - 0, // tp_itemsize - ScalarMapDealloc, // 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 - &ScalarMapMappingMethods, // 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 - "A scalar map container", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - MapReflectionFriend::GetIterator, // tp_iter - 0, // tp_iternext - ScalarMapMethods, // 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 - }; -#endif - - -// MessageMap ////////////////////////////////////////////////////////////////// - -static MessageMapContainer* GetMessageMap(PyObject* obj) { - return reinterpret_cast<MessageMapContainer*>(obj); -} - -static PyObject* GetCMessage(MessageMapContainer* self, Message* message) { - // Get or create the CMessage object corresponding to this message. - ScopedPyObjectPtr key(PyLong_FromVoidPtr(message)); - PyObject* ret = PyDict_GetItem(self->message_dict, key.get()); - - if (ret == NULL) { - CMessage* cmsg = cmessage::NewEmptyMessage(self->message_class); - ret = reinterpret_cast<PyObject*>(cmsg); - - if (cmsg == NULL) { - return NULL; - } - cmsg->owner = self->owner; - cmsg->message = message; - cmsg->parent = self->parent; - - if (PyDict_SetItem(self->message_dict, key.get(), ret) < 0) { - Py_DECREF(ret); - return NULL; - } - } else { - Py_INCREF(ret); - } - - return ret; -} - -PyObject* NewMessageMapContainer( - CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor, - CMessageClass* message_class) { - if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) { - return NULL; - } - -#if PY_MAJOR_VERSION >= 3 - PyObject* obj = PyType_GenericAlloc( - reinterpret_cast<PyTypeObject *>(MessageMapContainer_Type), 0); -#else - PyObject* obj = PyType_GenericAlloc(&MessageMapContainer_Type, 0); -#endif - if (obj == NULL) { - return PyErr_Format(PyExc_RuntimeError, - "Could not allocate new container."); - } - - MessageMapContainer* self = GetMessageMap(obj); - - self->message = parent->message; - self->parent = parent; - self->parent_field_descriptor = parent_field_descriptor; - self->owner = parent->owner; - self->version = 0; - - self->key_field_descriptor = - parent_field_descriptor->message_type()->FindFieldByName("key"); - self->value_field_descriptor = - parent_field_descriptor->message_type()->FindFieldByName("value"); - - self->message_dict = PyDict_New(); - if (self->message_dict == NULL) { - return PyErr_Format(PyExc_RuntimeError, - "Could not allocate message dict."); - } - - Py_INCREF(message_class); - self->message_class = message_class; - - if (self->key_field_descriptor == NULL || - self->value_field_descriptor == NULL) { - Py_DECREF(obj); - return PyErr_Format(PyExc_KeyError, - "Map entry descriptor did not have key/value fields"); - } - - return obj; -} - -int MapReflectionFriend::MessageMapSetItem(PyObject* _self, PyObject* key, - PyObject* v) { - if (v) { - PyErr_Format(PyExc_ValueError, - "Direct assignment of submessage not allowed"); - return -1; - } - - // Now we know that this is a delete, not a set. - - MessageMapContainer* self = GetMessageMap(_self); - Message* message = self->GetMutableMessage(); - const Reflection* reflection = message->GetReflection(); - MapKey map_key; - MapValueRef value; - - self->version++; - - if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) { - return -1; - } - - // Delete key from map. - if (reflection->DeleteMapValue(message, self->parent_field_descriptor, - map_key)) { - return 0; - } else { - PyErr_Format(PyExc_KeyError, "Key not present in map"); - return -1; - } -} - -PyObject* MapReflectionFriend::MessageMapGetItem(PyObject* _self, - PyObject* key) { - MessageMapContainer* self = GetMessageMap(_self); - - Message* message = self->GetMutableMessage(); - const Reflection* reflection = message->GetReflection(); - MapKey map_key; - MapValueRef value; - - if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) { - return NULL; - } - - if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor, - map_key, &value)) { - self->version++; - } - - return GetCMessage(self, value.MutableMessageValue()); -} - -PyObject* MessageMapGet(PyObject* self, PyObject* args) { - PyObject* key; - PyObject* default_value = NULL; - if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) { - return NULL; - } - - ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key)); - if (is_present.get() == NULL) { - return NULL; - } - - if (PyObject_IsTrue(is_present.get())) { - return MapReflectionFriend::MessageMapGetItem(self, key); - } else { - if (default_value != NULL) { - Py_INCREF(default_value); - return default_value; - } else { - Py_RETURN_NONE; - } - } -} - -static void MessageMapDealloc(PyObject* _self) { - MessageMapContainer* self = GetMessageMap(_self); - self->owner.reset(); - Py_DECREF(self->message_dict); - Py_DECREF(self->message_class); - Py_TYPE(_self)->tp_free(_self); -} - -static PyMethodDef MessageMapMethods[] = { - { "__contains__", (PyCFunction)MapReflectionFriend::Contains, METH_O, - "Tests whether the map contains this element."}, - { "clear", (PyCFunction)Clear, METH_NOARGS, - "Removes all elements from the map."}, - { "get", MessageMapGet, METH_VARARGS, - "Gets the value for the given key if present, or otherwise a default" }, - { "get_or_create", MapReflectionFriend::MessageMapGetItem, METH_O, - "Alias for getitem, useful to make explicit that the map is mutated." }, - /* - { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS, - "Makes a deep copy of the class." }, - { "__reduce__", (PyCFunction)Reduce, METH_NOARGS, - "Outputs picklable representation of the repeated field." }, - */ - {NULL, NULL}, -}; - -#if PY_MAJOR_VERSION >= 3 - static PyType_Slot MessageMapContainer_Type_slots[] = { - {Py_tp_dealloc, (void *)MessageMapDealloc}, - {Py_mp_length, (void *)MapReflectionFriend::Length}, - {Py_mp_subscript, (void *)MapReflectionFriend::MessageMapGetItem}, - {Py_mp_ass_subscript, (void *)MapReflectionFriend::MessageMapSetItem}, - {Py_tp_methods, (void *)MessageMapMethods}, - {Py_tp_iter, (void *)MapReflectionFriend::GetIterator}, - {0, 0} - }; - - PyType_Spec MessageMapContainer_Type_spec = { - FULL_MODULE_NAME ".MessageMapContainer", - sizeof(MessageMapContainer), - 0, - Py_TPFLAGS_DEFAULT, - MessageMapContainer_Type_slots - }; - - PyObject *MessageMapContainer_Type; -#else - static PyMappingMethods MessageMapMappingMethods = { - MapReflectionFriend::Length, // mp_length - MapReflectionFriend::MessageMapGetItem, // mp_subscript - MapReflectionFriend::MessageMapSetItem, // mp_ass_subscript - }; - - PyTypeObject MessageMapContainer_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".MessageMapContainer", // tp_name - sizeof(MessageMapContainer), // tp_basicsize - 0, // tp_itemsize - MessageMapDealloc, // 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 - &MessageMapMappingMethods, // 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 - "A map container for message", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - MapReflectionFriend::GetIterator, // tp_iter - 0, // tp_iternext - MessageMapMethods, // 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 - }; -#endif - -// MapIterator ///////////////////////////////////////////////////////////////// - -static MapIterator* GetIter(PyObject* obj) { - return reinterpret_cast<MapIterator*>(obj); -} - -PyObject* MapReflectionFriend::GetIterator(PyObject *_self) { - MapContainer* self = GetMap(_self); - - ScopedPyObjectPtr obj(PyType_GenericAlloc(&MapIterator_Type, 0)); - if (obj == NULL) { - return PyErr_Format(PyExc_KeyError, "Could not allocate iterator"); - } - - MapIterator* iter = GetIter(obj.get()); - - Py_INCREF(self); - iter->container = self; - iter->version = self->version; - iter->owner = self->owner; - - if (MapReflectionFriend::Length(_self) > 0) { - Message* message = self->GetMutableMessage(); - const Reflection* reflection = message->GetReflection(); - - iter->iter.reset(new ::google::protobuf::MapIterator( - reflection->MapBegin(message, self->parent_field_descriptor))); - } - - return obj.release(); -} - -PyObject* MapReflectionFriend::IterNext(PyObject* _self) { - MapIterator* self = GetIter(_self); - - // This won't catch mutations to the map performed by MergeFrom(); no easy way - // to address that. - if (self->version != self->container->version) { - return PyErr_Format(PyExc_RuntimeError, - "Map modified during iteration."); - } - - if (self->iter.get() == NULL) { - return NULL; - } - - Message* message = self->container->GetMutableMessage(); - const Reflection* reflection = message->GetReflection(); - - if (*self->iter == - reflection->MapEnd(message, self->container->parent_field_descriptor)) { - return NULL; - } - - PyObject* ret = MapKeyToPython(self->container->key_field_descriptor, - self->iter->GetKey()); - - ++(*self->iter); - - return ret; -} - -static void DeallocMapIterator(PyObject* _self) { - MapIterator* self = GetIter(_self); - self->iter.reset(); - self->owner.reset(); - Py_XDECREF(self->container); - Py_TYPE(_self)->tp_free(_self); -} - -PyTypeObject MapIterator_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".MapIterator", // tp_name - sizeof(MapIterator), // tp_basicsize - 0, // tp_itemsize - DeallocMapIterator, // 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 - "A scalar map iterator", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - PyObject_SelfIter, // tp_iter - MapReflectionFriend::IterNext, // 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 -}; - -} // namespace python -} // namespace protobuf -} // namespace google diff --git a/python/google/protobuf/pyext/map_container.h b/python/google/protobuf/pyext/map_container.h deleted file mode 100644 index fbd6713f..00000000 --- a/python/google/protobuf/pyext/map_container.h +++ /dev/null @@ -1,142 +0,0 @@ -// 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. - -#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__ -#define GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__ - -#include <Python.h> - -#include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif - -#include <google/protobuf/descriptor.h> -#include <google/protobuf/message.h> - -namespace google { -namespace protobuf { - -class Message; - -#ifdef _SHARED_PTR_H -using std::shared_ptr; -#else -using internal::shared_ptr; -#endif - -namespace python { - -struct CMessage; -struct CMessageClass; - -// This struct is used directly for ScalarMap, and is the base class of -// MessageMapContainer, which is used for MessageMap. -struct MapContainer { - PyObject_HEAD; - - // This is the top-level C++ Message object that owns the whole - // proto tree. Every Python MapContainer holds a - // reference to it in order to keep it alive as long as there's a - // Python object that references any part of the tree. - shared_ptr<Message> owner; - - // Pointer to the C++ Message that contains this container. The - // MapContainer does not own this pointer. - const Message* message; - - // Use to get a mutable message when necessary. - Message* GetMutableMessage(); - - // Weak reference to a parent CMessage object (i.e. may be NULL.) - // - // Used to make sure all ancestors are also mutable when first - // modifying the container. - CMessage* parent; - - // Pointer to the parent's descriptor that describes this - // field. Used together with the parent's message when making a - // default message instance mutable. - // The pointer is owned by the global DescriptorPool. - const FieldDescriptor* parent_field_descriptor; - const FieldDescriptor* key_field_descriptor; - const FieldDescriptor* value_field_descriptor; - - // We bump this whenever we perform a mutation, to invalidate existing - // iterators. - uint64 version; - - // Releases the messages in the container to a new message. - // - // Returns 0 on success, -1 on failure. - int Release(); - - // Set the owner field of self and any children of self. - void SetOwner(const shared_ptr<Message>& new_owner) { - owner = new_owner; - } -}; - -struct MessageMapContainer : public MapContainer { - // The type used to create new child messages. - CMessageClass* message_class; - - // A dict mapping Message* -> CMessage. - PyObject* message_dict; -}; - -#if PY_MAJOR_VERSION >= 3 - extern PyObject *MessageMapContainer_Type; - extern PyType_Spec MessageMapContainer_Type_spec; - extern PyObject *ScalarMapContainer_Type; - extern PyType_Spec ScalarMapContainer_Type_spec; -#else - extern PyTypeObject MessageMapContainer_Type; - extern PyTypeObject ScalarMapContainer_Type; -#endif - -extern PyTypeObject MapIterator_Type; // Both map types use the same iterator. - -// Builds a MapContainer object, from a parent message and a -// field descriptor. -extern PyObject* NewScalarMapContainer( - CMessage* parent, const FieldDescriptor* parent_field_descriptor); - -// Builds a MessageMap object, from a parent message and a -// field descriptor. -extern PyObject* NewMessageMapContainer( - CMessage* parent, const FieldDescriptor* parent_field_descriptor, - CMessageClass* message_class); - -} // namespace python -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__ diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc deleted file mode 100644 index a9261f20..00000000 --- a/python/google/protobuf/pyext/message.cc +++ /dev/null @@ -1,3085 +0,0 @@ -// 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. - -// Author: anuraag@google.com (Anuraag Agrawal) -// Author: tibell@google.com (Johan Tibell) - -#include <google/protobuf/pyext/message.h> - -#include <map> -#include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif -#include <string> -#include <vector> -#include <structmember.h> // A Python header file. - -#ifndef PyVarObject_HEAD_INIT -#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, -#endif -#ifndef Py_TYPE -#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) -#endif -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/logging.h> -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/util/message_differencer.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/message.h> -#include <google/protobuf/text_format.h> -#include <google/protobuf/unknown_field_set.h> -#include <google/protobuf/pyext/descriptor.h> -#include <google/protobuf/pyext/descriptor_pool.h> -#include <google/protobuf/pyext/extension_dict.h> -#include <google/protobuf/pyext/repeated_composite_container.h> -#include <google/protobuf/pyext/repeated_scalar_container.h> -#include <google/protobuf/pyext/map_container.h> -#include <google/protobuf/pyext/scoped_pyobject_ptr.h> -#include <google/protobuf/stubs/strutil.h> - -#if PY_MAJOR_VERSION >= 3 - #define PyInt_Check PyLong_Check - #define PyInt_AsLong PyLong_AsLong - #define PyInt_FromLong PyLong_FromLong - #define PyInt_FromSize_t PyLong_FromSize_t - #define PyString_Check PyUnicode_Check - #define PyString_FromString PyUnicode_FromString - #define PyString_FromStringAndSize PyUnicode_FromStringAndSize - #if PY_VERSION_HEX < 0x03030000 - #error "Python 3.0 - 3.2 are not supported." - #else - #define PyString_AsString(ob) \ - (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AsString(ob)) - #define PyString_AsStringAndSize(ob, charpp, sizep) \ - (PyUnicode_Check(ob)? \ - ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \ - PyBytes_AsStringAndSize(ob, (charpp), (sizep))) - #endif -#endif - -namespace google { -namespace protobuf { -namespace python { - -static PyObject* kDESCRIPTOR; -static PyObject* k_extensions_by_name; -static PyObject* k_extensions_by_number; -PyObject* EnumTypeWrapper_class; -static PyObject* PythonMessage_class; -static PyObject* kEmptyWeakref; -static PyObject* WKT_classes = NULL; - -namespace message_meta { - -static int InsertEmptyWeakref(PyTypeObject* base); - -// Add the number of a field descriptor to the containing message class. -// Equivalent to: -// _cls.<field>_FIELD_NUMBER = <number> -static bool AddFieldNumberToClass( - PyObject* cls, const FieldDescriptor* field_descriptor) { - string constant_name = field_descriptor->name() + "_FIELD_NUMBER"; - UpperString(&constant_name); - ScopedPyObjectPtr attr_name(PyString_FromStringAndSize( - constant_name.c_str(), constant_name.size())); - if (attr_name == NULL) { - return false; - } - ScopedPyObjectPtr number(PyInt_FromLong(field_descriptor->number())); - if (number == NULL) { - return false; - } - if (PyObject_SetAttr(cls, attr_name.get(), number.get()) == -1) { - return false; - } - return true; -} - - -// Finalize the creation of the Message class. -static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) { - // If there are extension_ranges, the message is "extendable", and extension - // classes will register themselves in this class. - if (descriptor->extension_range_count() > 0) { - ScopedPyObjectPtr by_name(PyDict_New()); - if (PyObject_SetAttr(cls, k_extensions_by_name, by_name.get()) < 0) { - return -1; - } - ScopedPyObjectPtr by_number(PyDict_New()); - if (PyObject_SetAttr(cls, k_extensions_by_number, by_number.get()) < 0) { - return -1; - } - } - - // For each field set: cls.<field>_FIELD_NUMBER = <number> - for (int i = 0; i < descriptor->field_count(); ++i) { - if (!AddFieldNumberToClass(cls, descriptor->field(i))) { - return -1; - } - } - - // For each enum set cls.<enum name> = EnumTypeWrapper(<enum descriptor>). - for (int i = 0; i < descriptor->enum_type_count(); ++i) { - const EnumDescriptor* enum_descriptor = descriptor->enum_type(i); - ScopedPyObjectPtr enum_type( - PyEnumDescriptor_FromDescriptor(enum_descriptor)); - if (enum_type == NULL) { - return -1; - } - // Add wrapped enum type to message class. - ScopedPyObjectPtr wrapped(PyObject_CallFunctionObjArgs( - EnumTypeWrapper_class, enum_type.get(), NULL)); - if (wrapped == NULL) { - return -1; - } - if (PyObject_SetAttrString( - cls, enum_descriptor->name().c_str(), wrapped.get()) == -1) { - return -1; - } - - // For each enum value add cls.<name> = <number> - for (int j = 0; j < enum_descriptor->value_count(); ++j) { - const EnumValueDescriptor* enum_value_descriptor = - enum_descriptor->value(j); - ScopedPyObjectPtr value_number(PyInt_FromLong( - enum_value_descriptor->number())); - if (value_number == NULL) { - return -1; - } - if (PyObject_SetAttrString(cls, enum_value_descriptor->name().c_str(), - value_number.get()) == -1) { - return -1; - } - } - } - - // For each extension set cls.<extension name> = <extension descriptor>. - // - // Extension descriptors come from - // <message descriptor>.extensions_by_name[name] - // which was defined previously. - for (int i = 0; i < descriptor->extension_count(); ++i) { - const google::protobuf::FieldDescriptor* field = descriptor->extension(i); - ScopedPyObjectPtr extension_field(PyFieldDescriptor_FromDescriptor(field)); - if (extension_field == NULL) { - return -1; - } - - // Add the extension field to the message class. - if (PyObject_SetAttrString( - cls, field->name().c_str(), extension_field.get()) == -1) { - return -1; - } - - // For each extension set cls.<extension name>_FIELD_NUMBER = <number>. - if (!AddFieldNumberToClass(cls, field)) { - return -1; - } - } - - return 0; -} - -static PyObject* New(PyTypeObject* type, - PyObject* args, PyObject* kwargs) { - static char *kwlist[] = {"name", "bases", "dict", 0}; - PyObject *bases, *dict; - const char* name; - - // Check arguments: (name, bases, dict) - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!O!:type", kwlist, - &name, - &PyTuple_Type, &bases, - &PyDict_Type, &dict)) { - return NULL; - } - - // Check bases: only (), or (message.Message,) are allowed - if (!(PyTuple_GET_SIZE(bases) == 0 || - (PyTuple_GET_SIZE(bases) == 1 && - PyTuple_GET_ITEM(bases, 0) == PythonMessage_class))) { - PyErr_SetString(PyExc_TypeError, - "A Message class can only inherit from Message"); - return NULL; - } - - // Check dict['DESCRIPTOR'] - PyObject* py_descriptor = PyDict_GetItem(dict, kDESCRIPTOR); - if (py_descriptor == NULL) { - PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR"); - return NULL; - } - if (!PyObject_TypeCheck(py_descriptor, &PyMessageDescriptor_Type)) { - PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s", - py_descriptor->ob_type->tp_name); - return NULL; - } - - // Build the arguments to the base metaclass. - // We change the __bases__ classes. - ScopedPyObjectPtr new_args; - const Descriptor* message_descriptor = - PyMessageDescriptor_AsDescriptor(py_descriptor); - if (message_descriptor == NULL) { - return NULL; - } - - if (WKT_classes == NULL) { - ScopedPyObjectPtr well_known_types(PyImport_ImportModule( - "google.protobuf.internal.well_known_types")); - GOOGLE_DCHECK(well_known_types != NULL); - - WKT_classes = PyObject_GetAttrString(well_known_types.get(), "WKTBASES"); - GOOGLE_DCHECK(WKT_classes != NULL); - } - - PyObject* well_known_class = PyDict_GetItemString( - WKT_classes, message_descriptor->full_name().c_str()); - if (well_known_class == NULL) { - new_args.reset(Py_BuildValue("s(OO)O", name, &CMessage_Type, - PythonMessage_class, dict)); - } else { - new_args.reset(Py_BuildValue("s(OOO)O", name, &CMessage_Type, - PythonMessage_class, well_known_class, dict)); - } - - if (new_args == NULL) { - return NULL; - } - // Call the base metaclass. - ScopedPyObjectPtr result(PyType_Type.tp_new(type, new_args.get(), NULL)); - if (result == NULL) { - return NULL; - } - CMessageClass* newtype = reinterpret_cast<CMessageClass*>(result.get()); - - // Insert the empty weakref into the base classes. - if (InsertEmptyWeakref( - reinterpret_cast<PyTypeObject*>(PythonMessage_class)) < 0 || - InsertEmptyWeakref(&CMessage_Type) < 0) { - return NULL; - } - - // Cache the descriptor, both as Python object and as C++ pointer. - const Descriptor* descriptor = - PyMessageDescriptor_AsDescriptor(py_descriptor); - if (descriptor == NULL) { - return NULL; - } - Py_INCREF(py_descriptor); - newtype->py_message_descriptor = py_descriptor; - newtype->message_descriptor = descriptor; - // TODO(amauryfa): Don't always use the canonical pool of the descriptor, - // use the MessageFactory optionally passed in the class dict. - newtype->py_descriptor_pool = GetDescriptorPool_FromPool( - descriptor->file()->pool()); - if (newtype->py_descriptor_pool == NULL) { - return NULL; - } - Py_INCREF(newtype->py_descriptor_pool); - - // Add the message to the DescriptorPool. - if (cdescriptor_pool::RegisterMessageClass(newtype->py_descriptor_pool, - descriptor, newtype) < 0) { - return NULL; - } - - // Continue with type initialization: add other descriptors, enum values... - if (AddDescriptors(result.get(), descriptor) < 0) { - return NULL; - } - return result.release(); -} - -static void Dealloc(CMessageClass *self) { - Py_DECREF(self->py_message_descriptor); - Py_DECREF(self->py_descriptor_pool); - Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); -} - - -// This function inserts and empty weakref at the end of the list of -// subclasses for the main protocol buffer Message class. -// -// This eliminates a O(n^2) behaviour in the internal add_subclass -// routine. -static int InsertEmptyWeakref(PyTypeObject *base_type) { -#if PY_MAJOR_VERSION >= 3 - // Python 3.4 has already included the fix for the issue that this - // hack addresses. For further background and the fix please see - // https://bugs.python.org/issue17936. - return 0; -#else - PyObject *subclasses = base_type->tp_subclasses; - if (subclasses && PyList_CheckExact(subclasses)) { - return PyList_Append(subclasses, kEmptyWeakref); - } - return 0; -#endif // PY_MAJOR_VERSION >= 3 -} - -} // namespace message_meta - -PyTypeObject CMessageClass_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".MessageMeta", // tp_name - sizeof(CMessageClass), // tp_basicsize - 0, // tp_itemsize - (destructor)message_meta::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 | Py_TPFLAGS_BASETYPE, // tp_flags - "The metaclass of ProtocolMessages", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // 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 - message_meta::New, // tp_new -}; - -static CMessageClass* CheckMessageClass(PyTypeObject* cls) { - if (!PyObject_TypeCheck(cls, &CMessageClass_Type)) { - PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name); - return NULL; - } - return reinterpret_cast<CMessageClass*>(cls); -} - -static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) { - CMessageClass* type = CheckMessageClass(cls); - if (type == NULL) { - return NULL; - } - return type->message_descriptor; -} - -// Forward declarations -namespace cmessage { -int InternalReleaseFieldByDescriptor( - CMessage* self, - const FieldDescriptor* field_descriptor, - PyObject* composite_field); -} // namespace cmessage - -// --------------------------------------------------------------------- -// Visiting the composite children of a CMessage - -struct ChildVisitor { - // Returns 0 on success, -1 on failure. - int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) { - return 0; - } - - // Returns 0 on success, -1 on failure. - int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) { - return 0; - } - - // Returns 0 on success, -1 on failure. - int VisitCMessage(CMessage* cmessage, - const FieldDescriptor* field_descriptor) { - return 0; - } -}; - -// Apply a function to a composite field. Does nothing if child is of -// non-composite type. -template<class Visitor> -static int VisitCompositeField(const FieldDescriptor* descriptor, - PyObject* child, - Visitor visitor) { - if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) { - if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (descriptor->is_map()) { - MapContainer* container = reinterpret_cast<MapContainer*>(child); - if (visitor.VisitMapContainer(container) == -1) { - return -1; - } - } else { - RepeatedCompositeContainer* container = - reinterpret_cast<RepeatedCompositeContainer*>(child); - if (visitor.VisitRepeatedCompositeContainer(container) == -1) - return -1; - } - } else { - RepeatedScalarContainer* container = - reinterpret_cast<RepeatedScalarContainer*>(child); - if (visitor.VisitRepeatedScalarContainer(container) == -1) - return -1; - } - } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - CMessage* cmsg = reinterpret_cast<CMessage*>(child); - if (visitor.VisitCMessage(cmsg, descriptor) == -1) - return -1; - } - // The ExtensionDict might contain non-composite fields, which we - // skip here. - return 0; -} - -// Visit each composite field and extension field of this CMessage. -// Returns -1 on error and 0 on success. -template<class Visitor> -int ForEachCompositeField(CMessage* self, Visitor visitor) { - Py_ssize_t pos = 0; - PyObject* key; - PyObject* field; - - // Visit normal fields. - if (self->composite_fields) { - // Never use self->message in this function, it may be already freed. - const Descriptor* message_descriptor = - GetMessageDescriptor(Py_TYPE(self)); - while (PyDict_Next(self->composite_fields, &pos, &key, &field)) { - Py_ssize_t key_str_size; - char *key_str_data; - if (PyString_AsStringAndSize(key, &key_str_data, &key_str_size) != 0) - return -1; - const string key_str(key_str_data, key_str_size); - const FieldDescriptor* descriptor = - message_descriptor->FindFieldByName(key_str); - if (descriptor != NULL) { - if (VisitCompositeField(descriptor, field, visitor) == -1) - return -1; - } - } - } - - // Visit extension fields. - if (self->extensions != NULL) { - pos = 0; - while (PyDict_Next(self->extensions->values, &pos, &key, &field)) { - const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key); - if (descriptor == NULL) - return -1; - if (VisitCompositeField(descriptor, field, visitor) == -1) - return -1; - } - } - - return 0; -} - -// --------------------------------------------------------------------- - -// Constants used for integer type range checking. -PyObject* kPythonZero; -PyObject* kint32min_py; -PyObject* kint32max_py; -PyObject* kuint32max_py; -PyObject* kint64min_py; -PyObject* kint64max_py; -PyObject* kuint64max_py; - -PyObject* EncodeError_class; -PyObject* DecodeError_class; -PyObject* PickleError_class; - -// Constant PyString values used for GetAttr/GetItem. -static PyObject* k_cdescriptor; -static PyObject* kfull_name; - -/* Is 64bit */ -void FormatTypeError(PyObject* arg, char* expected_types) { - PyObject* repr = PyObject_Repr(arg); - if (repr) { - PyErr_Format(PyExc_TypeError, - "%.100s has type %.100s, but expected one of: %s", - PyString_AsString(repr), - Py_TYPE(arg)->tp_name, - expected_types); - Py_DECREF(repr); - } -} - -template<class T> -bool CheckAndGetInteger( - PyObject* arg, T* value, PyObject* min, PyObject* max) { - bool is_long = PyLong_Check(arg); -#if PY_MAJOR_VERSION < 3 - if (!PyInt_Check(arg) && !is_long) { - FormatTypeError(arg, "int, long"); - return false; - } - if (PyObject_Compare(min, arg) > 0 || PyObject_Compare(max, arg) < 0) { -#else - if (!is_long) { - FormatTypeError(arg, "int"); - return false; - } - if (PyObject_RichCompareBool(min, arg, Py_LE) != 1 || - PyObject_RichCompareBool(max, arg, Py_GE) != 1) { -#endif - if (!PyErr_Occurred()) { - PyObject *s = PyObject_Str(arg); - if (s) { - PyErr_Format(PyExc_ValueError, - "Value out of range: %s", - PyString_AsString(s)); - Py_DECREF(s); - } - } - return false; - } -#if PY_MAJOR_VERSION < 3 - if (!is_long) { - *value = static_cast<T>(PyInt_AsLong(arg)); - } else // NOLINT -#endif - { - if (min == kPythonZero) { - *value = static_cast<T>(PyLong_AsUnsignedLongLong(arg)); - } else { - *value = static_cast<T>(PyLong_AsLongLong(arg)); - } - } - return true; -} - -// These are referenced by repeated_scalar_container, and must -// be explicitly instantiated. -template bool CheckAndGetInteger<int32>( - PyObject*, int32*, PyObject*, PyObject*); -template bool CheckAndGetInteger<int64>( - PyObject*, int64*, PyObject*, PyObject*); -template bool CheckAndGetInteger<uint32>( - PyObject*, uint32*, PyObject*, PyObject*); -template bool CheckAndGetInteger<uint64>( - PyObject*, uint64*, PyObject*, PyObject*); - -bool CheckAndGetDouble(PyObject* arg, double* value) { - if (!PyInt_Check(arg) && !PyLong_Check(arg) && - !PyFloat_Check(arg)) { - FormatTypeError(arg, "int, long, float"); - return false; - } - *value = PyFloat_AsDouble(arg); - return true; -} - -bool CheckAndGetFloat(PyObject* arg, float* value) { - double double_value; - if (!CheckAndGetDouble(arg, &double_value)) { - return false; - } - *value = static_cast<float>(double_value); - return true; -} - -bool CheckAndGetBool(PyObject* arg, bool* value) { - if (!PyInt_Check(arg) && !PyBool_Check(arg) && !PyLong_Check(arg)) { - FormatTypeError(arg, "int, long, bool"); - return false; - } - *value = static_cast<bool>(PyInt_AsLong(arg)); - return true; -} - -// Checks whether the given object (which must be "bytes" or "unicode") contains -// valid UTF-8. -bool IsValidUTF8(PyObject* obj) { - if (PyBytes_Check(obj)) { - PyObject* unicode = PyUnicode_FromEncodedObject(obj, "utf-8", NULL); - - // Clear the error indicator; we report our own error when desired. - PyErr_Clear(); - - if (unicode) { - Py_DECREF(unicode); - return true; - } else { - return false; - } - } else { - // Unicode object, known to be valid UTF-8. - return true; - } -} - -bool AllowInvalidUTF8(const FieldDescriptor* field) { return false; } - -PyObject* CheckString(PyObject* arg, const FieldDescriptor* descriptor) { - GOOGLE_DCHECK(descriptor->type() == FieldDescriptor::TYPE_STRING || - descriptor->type() == FieldDescriptor::TYPE_BYTES); - if (descriptor->type() == FieldDescriptor::TYPE_STRING) { - if (!PyBytes_Check(arg) && !PyUnicode_Check(arg)) { - FormatTypeError(arg, "bytes, unicode"); - return NULL; - } - - if (!IsValidUTF8(arg) && !AllowInvalidUTF8(descriptor)) { - PyObject* repr = PyObject_Repr(arg); - PyErr_Format(PyExc_ValueError, - "%s has type str, but isn't valid UTF-8 " - "encoding. Non-UTF-8 strings must be converted to " - "unicode objects before being added.", - PyString_AsString(repr)); - Py_DECREF(repr); - return NULL; - } - } else if (!PyBytes_Check(arg)) { - FormatTypeError(arg, "bytes"); - return NULL; - } - - PyObject* encoded_string = NULL; - if (descriptor->type() == FieldDescriptor::TYPE_STRING) { - if (PyBytes_Check(arg)) { - // The bytes were already validated as correctly encoded UTF-8 above. - encoded_string = arg; // Already encoded. - Py_INCREF(encoded_string); - } else { - encoded_string = PyUnicode_AsEncodedObject(arg, "utf-8", NULL); - } - } else { - // In this case field type is "bytes". - encoded_string = arg; - Py_INCREF(encoded_string); - } - - return encoded_string; -} - -bool CheckAndSetString( - PyObject* arg, Message* message, - const FieldDescriptor* descriptor, - const Reflection* reflection, - bool append, - int index) { - ScopedPyObjectPtr encoded_string(CheckString(arg, descriptor)); - - if (encoded_string.get() == NULL) { - return false; - } - - char* value; - Py_ssize_t value_len; - if (PyBytes_AsStringAndSize(encoded_string.get(), &value, &value_len) < 0) { - return false; - } - - string value_string(value, value_len); - if (append) { - reflection->AddString(message, descriptor, value_string); - } else if (index < 0) { - reflection->SetString(message, descriptor, value_string); - } else { - reflection->SetRepeatedString(message, descriptor, index, value_string); - } - return true; -} - -PyObject* ToStringObject(const FieldDescriptor* descriptor, string value) { - if (descriptor->type() != FieldDescriptor::TYPE_STRING) { - return PyBytes_FromStringAndSize(value.c_str(), value.length()); - } - - PyObject* result = PyUnicode_DecodeUTF8(value.c_str(), value.length(), NULL); - // If the string can't be decoded in UTF-8, just return a string object that - // contains the raw bytes. This can't happen if the value was assigned using - // the members of the Python message object, but can happen if the values were - // parsed from the wire (binary). - if (result == NULL) { - PyErr_Clear(); - result = PyBytes_FromStringAndSize(value.c_str(), value.length()); - } - return result; -} - -bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor, - const Message* message) { - if (message->GetDescriptor() == field_descriptor->containing_type()) { - return true; - } - PyErr_Format(PyExc_KeyError, "Field '%s' does not belong to message '%s'", - field_descriptor->full_name().c_str(), - message->GetDescriptor()->full_name().c_str()); - return false; -} - -namespace cmessage { - -PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message) { - // No need to check the type: the type of instances of CMessage is always - // an instance of CMessageClass. Let's prove it with a debug-only check. - GOOGLE_DCHECK(PyObject_TypeCheck(message, &CMessage_Type)); - return reinterpret_cast<CMessageClass*>(Py_TYPE(message))->py_descriptor_pool; -} - -MessageFactory* GetFactoryForMessage(CMessage* message) { - return GetDescriptorPoolForMessage(message)->message_factory; -} - -static int MaybeReleaseOverlappingOneofField( - CMessage* cmessage, - const FieldDescriptor* field) { -#ifdef GOOGLE_PROTOBUF_HAS_ONEOF - Message* message = cmessage->message; - const Reflection* reflection = message->GetReflection(); - if (!field->containing_oneof() || - !reflection->HasOneof(*message, field->containing_oneof()) || - reflection->HasField(*message, field)) { - // No other field in this oneof, no need to release. - return 0; - } - - const OneofDescriptor* oneof = field->containing_oneof(); - const FieldDescriptor* existing_field = - reflection->GetOneofFieldDescriptor(*message, oneof); - if (existing_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { - // Non-message fields don't need to be released. - return 0; - } - const char* field_name = existing_field->name().c_str(); - PyObject* child_message = cmessage->composite_fields ? - PyDict_GetItemString(cmessage->composite_fields, field_name) : NULL; - if (child_message == NULL) { - // No python reference to this field so no need to release. - return 0; - } - - if (InternalReleaseFieldByDescriptor( - cmessage, existing_field, child_message) < 0) { - return -1; - } - return PyDict_DelItemString(cmessage->composite_fields, field_name); -#else - return 0; -#endif -} - -// --------------------------------------------------------------------- -// Making a message writable - -static Message* GetMutableMessage( - CMessage* parent, - const FieldDescriptor* parent_field) { - Message* parent_message = parent->message; - const Reflection* reflection = parent_message->GetReflection(); - if (MaybeReleaseOverlappingOneofField(parent, parent_field) < 0) { - return NULL; - } - return reflection->MutableMessage( - parent_message, parent_field, GetFactoryForMessage(parent)); -} - -struct FixupMessageReference : public ChildVisitor { - // message must outlive this object. - explicit FixupMessageReference(Message* message) : - message_(message) {} - - int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) { - container->message = message_; - return 0; - } - - int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) { - container->message = message_; - return 0; - } - - int VisitMapContainer(MapContainer* container) { - container->message = message_; - return 0; - } - - private: - Message* message_; -}; - -int AssureWritable(CMessage* self) { - if (self == NULL || !self->read_only) { - return 0; - } - - if (self->parent == NULL) { - // If parent is NULL but we are trying to modify a read-only message, this - // is a reference to a constant default instance that needs to be replaced - // with a mutable top-level message. - self->message = self->message->New(); - self->owner.reset(self->message); - // Cascade the new owner to eventual children: even if this message is - // empty, some submessages or repeated containers might exist already. - SetOwner(self, self->owner); - } else { - // Otherwise, we need a mutable child message. - if (AssureWritable(self->parent) == -1) - return -1; - - // Make self->message writable. - Message* mutable_message = GetMutableMessage( - self->parent, - self->parent_field_descriptor); - if (mutable_message == NULL) { - return -1; - } - self->message = mutable_message; - } - self->read_only = false; - - // When a CMessage is made writable its Message pointer is updated - // to point to a new mutable Message. When that happens we need to - // update any references to the old, read-only CMessage. There are - // four places such references occur: RepeatedScalarContainer, - // RepeatedCompositeContainer, MapContainer, and ExtensionDict. - if (self->extensions != NULL) - self->extensions->message = self->message; - if (ForEachCompositeField(self, FixupMessageReference(self->message)) == -1) - return -1; - - return 0; -} - -// --- Globals: - -// Retrieve a C++ FieldDescriptor for a message attribute. -// The C++ message must be valid. -// TODO(amauryfa): This function should stay internal, because exception -// handling is not consistent. -static const FieldDescriptor* GetFieldDescriptor( - CMessage* self, PyObject* name) { - const Descriptor *message_descriptor = self->message->GetDescriptor(); - char* field_name; - Py_ssize_t size; - if (PyString_AsStringAndSize(name, &field_name, &size) < 0) { - return NULL; - } - const FieldDescriptor *field_descriptor = - message_descriptor->FindFieldByName(string(field_name, size)); - if (field_descriptor == NULL) { - // Note: No exception is set! - return NULL; - } - return field_descriptor; -} - -// Retrieve a C++ FieldDescriptor for an extension handle. -const FieldDescriptor* GetExtensionDescriptor(PyObject* extension) { - ScopedPyObjectPtr cdescriptor; - if (!PyObject_TypeCheck(extension, &PyFieldDescriptor_Type)) { - // Most callers consider extensions as a plain dictionary. We should - // allow input which is not a field descriptor, and simply pretend it does - // not exist. - PyErr_SetObject(PyExc_KeyError, extension); - return NULL; - } - return PyFieldDescriptor_AsDescriptor(extension); -} - -// If value is a string, convert it into an enum value based on the labels in -// descriptor, otherwise simply return value. Always returns a new reference. -static PyObject* GetIntegerEnumValue(const FieldDescriptor& descriptor, - PyObject* value) { - if (PyString_Check(value) || PyUnicode_Check(value)) { - const EnumDescriptor* enum_descriptor = descriptor.enum_type(); - if (enum_descriptor == NULL) { - PyErr_SetString(PyExc_TypeError, "not an enum field"); - return NULL; - } - char* enum_label; - Py_ssize_t size; - if (PyString_AsStringAndSize(value, &enum_label, &size) < 0) { - return NULL; - } - const EnumValueDescriptor* enum_value_descriptor = - enum_descriptor->FindValueByName(string(enum_label, size)); - if (enum_value_descriptor == NULL) { - PyErr_SetString(PyExc_ValueError, "unknown enum label"); - return NULL; - } - return PyInt_FromLong(enum_value_descriptor->number()); - } - Py_INCREF(value); - return value; -} - -// If cmessage_list is not NULL, this function releases values into the -// container CMessages instead of just removing. Repeated composite container -// needs to do this to make sure CMessages stay alive if they're still -// referenced after deletion. Repeated scalar container doesn't need to worry. -int InternalDeleteRepeatedField( - CMessage* self, - const FieldDescriptor* field_descriptor, - PyObject* slice, - PyObject* cmessage_list) { - Message* message = self->message; - Py_ssize_t length, from, to, step, slice_length; - const Reflection* reflection = message->GetReflection(); - int min, max; - length = reflection->FieldSize(*message, field_descriptor); - - if (PyInt_Check(slice) || PyLong_Check(slice)) { - from = to = PyLong_AsLong(slice); - if (from < 0) { - from = to = length + from; - } - step = 1; - min = max = from; - - // Range check. - if (from < 0 || from >= length) { - PyErr_Format(PyExc_IndexError, "list assignment index out of range"); - return -1; - } - } else if (PySlice_Check(slice)) { - from = to = step = slice_length = 0; - PySlice_GetIndicesEx( -#if PY_MAJOR_VERSION < 3 - reinterpret_cast<PySliceObject*>(slice), -#else - slice, -#endif - length, &from, &to, &step, &slice_length); - if (from < to) { - min = from; - max = to - 1; - } else { - min = to + 1; - max = from; - } - } else { - PyErr_SetString(PyExc_TypeError, "list indices must be integers"); - return -1; - } - - Py_ssize_t i = from; - std::vector<bool> to_delete(length, false); - while (i >= min && i <= max) { - to_delete[i] = true; - i += step; - } - - to = 0; - for (i = 0; i < length; ++i) { - if (!to_delete[i]) { - if (i != to) { - reflection->SwapElements(message, field_descriptor, i, to); - if (cmessage_list != NULL) { - // If a list of cmessages is passed in (i.e. from a repeated - // composite container), swap those as well to correspond to the - // swaps in the underlying message so they're in the right order - // when we start releasing. - PyObject* tmp = PyList_GET_ITEM(cmessage_list, i); - PyList_SET_ITEM(cmessage_list, i, - PyList_GET_ITEM(cmessage_list, to)); - PyList_SET_ITEM(cmessage_list, to, tmp); - } - } - ++to; - } - } - - while (i > to) { - if (cmessage_list == NULL) { - reflection->RemoveLast(message, field_descriptor); - } else { - CMessage* last_cmessage = reinterpret_cast<CMessage*>( - PyList_GET_ITEM(cmessage_list, PyList_GET_SIZE(cmessage_list) - 1)); - repeated_composite_container::ReleaseLastTo( - self, field_descriptor, last_cmessage); - if (PySequence_DelItem(cmessage_list, -1) < 0) { - return -1; - } - } - --i; - } - - return 0; -} - -// Initializes fields of a message. Used in constructors. -int InitAttributes(CMessage* self, PyObject* kwargs) { - if (kwargs == NULL) { - return 0; - } - - Py_ssize_t pos = 0; - PyObject* name; - PyObject* value; - while (PyDict_Next(kwargs, &pos, &name, &value)) { - if (!PyString_Check(name)) { - PyErr_SetString(PyExc_ValueError, "Field name must be a string"); - return -1; - } - const FieldDescriptor* descriptor = GetFieldDescriptor(self, name); - if (descriptor == NULL) { - PyErr_Format(PyExc_ValueError, "Protocol message %s has no \"%s\" field.", - self->message->GetDescriptor()->name().c_str(), - PyString_AsString(name)); - return -1; - } - if (value == Py_None) { - // field=None is the same as no field at all. - continue; - } - if (descriptor->is_map()) { - ScopedPyObjectPtr map(GetAttr(self, name)); - const FieldDescriptor* value_descriptor = - descriptor->message_type()->FindFieldByName("value"); - if (value_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - Py_ssize_t map_pos = 0; - PyObject* map_key; - PyObject* map_value; - while (PyDict_Next(value, &map_pos, &map_key, &map_value)) { - ScopedPyObjectPtr function_return; - function_return.reset(PyObject_GetItem(map.get(), map_key)); - if (function_return.get() == NULL) { - return -1; - } - ScopedPyObjectPtr ok(PyObject_CallMethod( - function_return.get(), "MergeFrom", "O", map_value)); - if (ok.get() == NULL) { - return -1; - } - } - } else { - ScopedPyObjectPtr function_return; - function_return.reset( - PyObject_CallMethod(map.get(), "update", "O", value)); - if (function_return.get() == NULL) { - return -1; - } - } - } else if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) { - ScopedPyObjectPtr container(GetAttr(self, name)); - if (container == NULL) { - return -1; - } - if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - RepeatedCompositeContainer* rc_container = - reinterpret_cast<RepeatedCompositeContainer*>(container.get()); - ScopedPyObjectPtr iter(PyObject_GetIter(value)); - if (iter == NULL) { - PyErr_SetString(PyExc_TypeError, "Value must be iterable"); - return -1; - } - ScopedPyObjectPtr next; - while ((next.reset(PyIter_Next(iter.get()))) != NULL) { - PyObject* kwargs = (PyDict_Check(next.get()) ? next.get() : NULL); - ScopedPyObjectPtr new_msg( - repeated_composite_container::Add(rc_container, NULL, kwargs)); - if (new_msg == NULL) { - return -1; - } - if (kwargs == NULL) { - // next was not a dict, it's a message we need to merge - ScopedPyObjectPtr merged(MergeFrom( - reinterpret_cast<CMessage*>(new_msg.get()), next.get())); - if (merged.get() == NULL) { - return -1; - } - } - } - if (PyErr_Occurred()) { - // Check to see how PyIter_Next() exited. - return -1; - } - } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { - RepeatedScalarContainer* rs_container = - reinterpret_cast<RepeatedScalarContainer*>(container.get()); - ScopedPyObjectPtr iter(PyObject_GetIter(value)); - if (iter == NULL) { - PyErr_SetString(PyExc_TypeError, "Value must be iterable"); - return -1; - } - ScopedPyObjectPtr next; - while ((next.reset(PyIter_Next(iter.get()))) != NULL) { - ScopedPyObjectPtr enum_value( - GetIntegerEnumValue(*descriptor, next.get())); - if (enum_value == NULL) { - return -1; - } - ScopedPyObjectPtr new_msg(repeated_scalar_container::Append( - rs_container, enum_value.get())); - if (new_msg == NULL) { - return -1; - } - } - if (PyErr_Occurred()) { - // Check to see how PyIter_Next() exited. - return -1; - } - } else { - if (ScopedPyObjectPtr(repeated_scalar_container::Extend( - reinterpret_cast<RepeatedScalarContainer*>(container.get()), - value)) == - NULL) { - return -1; - } - } - } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - ScopedPyObjectPtr message(GetAttr(self, name)); - if (message == NULL) { - return -1; - } - CMessage* cmessage = reinterpret_cast<CMessage*>(message.get()); - if (PyDict_Check(value)) { - if (InitAttributes(cmessage, value) < 0) { - return -1; - } - } else { - ScopedPyObjectPtr merged(MergeFrom(cmessage, value)); - if (merged == NULL) { - return -1; - } - } - } else { - ScopedPyObjectPtr new_val; - if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { - new_val.reset(GetIntegerEnumValue(*descriptor, value)); - if (new_val == NULL) { - return -1; - } - } - if (SetAttr(self, name, (new_val.get() == NULL) ? value : new_val.get()) < - 0) { - return -1; - } - } - } - return 0; -} - -// Allocates an incomplete Python Message: the caller must fill self->message, -// self->owner and eventually self->parent. -CMessage* NewEmptyMessage(CMessageClass* type) { - CMessage* self = reinterpret_cast<CMessage*>( - PyType_GenericAlloc(&type->super.ht_type, 0)); - if (self == NULL) { - return NULL; - } - - self->message = NULL; - self->parent = NULL; - self->parent_field_descriptor = NULL; - self->read_only = false; - self->extensions = NULL; - - self->composite_fields = NULL; - - return self; -} - -// The __new__ method of Message classes. -// Creates a new C++ message and takes ownership. -static PyObject* New(PyTypeObject* cls, - PyObject* unused_args, PyObject* unused_kwargs) { - CMessageClass* type = CheckMessageClass(cls); - if (type == NULL) { - return NULL; - } - // Retrieve the message descriptor and the default instance (=prototype). - const Descriptor* message_descriptor = type->message_descriptor; - if (message_descriptor == NULL) { - return NULL; - } - const Message* default_message = type->py_descriptor_pool->message_factory - ->GetPrototype(message_descriptor); - if (default_message == NULL) { - PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str()); - return NULL; - } - - CMessage* self = NewEmptyMessage(type); - if (self == NULL) { - return NULL; - } - self->message = default_message->New(); - self->owner.reset(self->message); - return reinterpret_cast<PyObject*>(self); -} - -// The __init__ method of Message classes. -// It initializes fields from keywords passed to the constructor. -static int Init(CMessage* self, PyObject* args, PyObject* kwargs) { - if (PyTuple_Size(args) != 0) { - PyErr_SetString(PyExc_TypeError, "No positional arguments allowed"); - return -1; - } - - return InitAttributes(self, kwargs); -} - -// --------------------------------------------------------------------- -// Deallocating a CMessage -// -// Deallocating a CMessage requires that we clear any weak references -// from children to the message being deallocated. - -// Clear the weak reference from the child to the parent. -struct ClearWeakReferences : public ChildVisitor { - int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) { - container->parent = NULL; - // The elements in the container have the same parent as the - // container itself, so NULL out that pointer as well. - const Py_ssize_t n = PyList_GET_SIZE(container->child_messages); - for (Py_ssize_t i = 0; i < n; ++i) { - CMessage* child_cmessage = reinterpret_cast<CMessage*>( - PyList_GET_ITEM(container->child_messages, i)); - child_cmessage->parent = NULL; - } - return 0; - } - - int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) { - container->parent = NULL; - return 0; - } - - int VisitMapContainer(MapContainer* container) { - container->parent = NULL; - return 0; - } - - int VisitCMessage(CMessage* cmessage, - const FieldDescriptor* field_descriptor) { - cmessage->parent = NULL; - return 0; - } -}; - -static void Dealloc(CMessage* self) { - // Null out all weak references from children to this message. - GOOGLE_CHECK_EQ(0, ForEachCompositeField(self, ClearWeakReferences())); - if (self->extensions) { - self->extensions->parent = NULL; - } - - Py_CLEAR(self->extensions); - Py_CLEAR(self->composite_fields); - self->owner.reset(); - Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); -} - -// --------------------------------------------------------------------- - - -PyObject* IsInitialized(CMessage* self, PyObject* args) { - PyObject* errors = NULL; - if (PyArg_ParseTuple(args, "|O", &errors) < 0) { - return NULL; - } - if (self->message->IsInitialized()) { - Py_RETURN_TRUE; - } - if (errors != NULL) { - ScopedPyObjectPtr initialization_errors( - FindInitializationErrors(self)); - if (initialization_errors == NULL) { - return NULL; - } - ScopedPyObjectPtr extend_name(PyString_FromString("extend")); - if (extend_name == NULL) { - return NULL; - } - ScopedPyObjectPtr result(PyObject_CallMethodObjArgs( - errors, - extend_name.get(), - initialization_errors.get(), - NULL)); - if (result == NULL) { - return NULL; - } - } - Py_RETURN_FALSE; -} - -PyObject* HasFieldByDescriptor( - CMessage* self, const FieldDescriptor* field_descriptor) { - Message* message = self->message; - if (!CheckFieldBelongsToMessage(field_descriptor, message)) { - return NULL; - } - if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) { - PyErr_SetString(PyExc_KeyError, - "Field is repeated. A singular method is required."); - return NULL; - } - bool has_field = - message->GetReflection()->HasField(*message, field_descriptor); - return PyBool_FromLong(has_field ? 1 : 0); -} - -const FieldDescriptor* FindFieldWithOneofs( - const Message* message, const string& field_name, bool* in_oneof) { - *in_oneof = false; - const Descriptor* descriptor = message->GetDescriptor(); - const FieldDescriptor* field_descriptor = - descriptor->FindFieldByName(field_name); - if (field_descriptor != NULL) { - return field_descriptor; - } - const OneofDescriptor* oneof_desc = - descriptor->FindOneofByName(field_name); - if (oneof_desc != NULL) { - *in_oneof = true; - return message->GetReflection()->GetOneofFieldDescriptor(*message, - oneof_desc); - } - return NULL; -} - -bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) { - if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) { - PyErr_Format(PyExc_ValueError, - "Protocol message has no singular \"%s\" field.", - field_descriptor->name().c_str()); - return false; - } - - if (field_descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { - // HasField() for a oneof *itself* isn't supported. - if (in_oneof) { - PyErr_Format(PyExc_ValueError, - "Can't test oneof field \"%s\" for presence in proto3, use " - "WhichOneof instead.", - field_descriptor->containing_oneof()->name().c_str()); - return false; - } - - // ...but HasField() for fields *in* a oneof is supported. - if (field_descriptor->containing_oneof() != NULL) { - return true; - } - - if (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { - PyErr_Format( - PyExc_ValueError, - "Can't test non-submessage field \"%s\" for presence in proto3.", - field_descriptor->name().c_str()); - return false; - } - } - - return true; -} - -PyObject* HasField(CMessage* self, PyObject* arg) { - char* field_name; - Py_ssize_t size; -#if PY_MAJOR_VERSION < 3 - if (PyString_AsStringAndSize(arg, &field_name, &size) < 0) { - return NULL; - } -#else - field_name = PyUnicode_AsUTF8AndSize(arg, &size); - if (!field_name) { - return NULL; - } -#endif - - Message* message = self->message; - bool is_in_oneof; - const FieldDescriptor* field_descriptor = - FindFieldWithOneofs(message, string(field_name, size), &is_in_oneof); - if (field_descriptor == NULL) { - if (!is_in_oneof) { - PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name); - return NULL; - } else { - Py_RETURN_FALSE; - } - } - - if (!CheckHasPresence(field_descriptor, is_in_oneof)) { - return NULL; - } - - if (message->GetReflection()->HasField(*message, field_descriptor)) { - Py_RETURN_TRUE; - } - if (!message->GetReflection()->SupportsUnknownEnumValues() && - field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { - // Special case: Python HasField() differs in semantics from C++ - // slightly: we return HasField('enum_field') == true if there is - // an unknown enum value present. To implement this we have to - // look in the UnknownFieldSet. - const UnknownFieldSet& unknown_field_set = - message->GetReflection()->GetUnknownFields(*message); - for (int i = 0; i < unknown_field_set.field_count(); ++i) { - if (unknown_field_set.field(i).number() == field_descriptor->number()) { - Py_RETURN_TRUE; - } - } - } - Py_RETURN_FALSE; -} - -PyObject* ClearExtension(CMessage* self, PyObject* extension) { - if (self->extensions != NULL) { - return extension_dict::ClearExtension(self->extensions, extension); - } else { - const FieldDescriptor* descriptor = GetExtensionDescriptor(extension); - if (descriptor == NULL) { - return NULL; - } - if (ScopedPyObjectPtr(ClearFieldByDescriptor(self, descriptor)) == NULL) { - return NULL; - } - } - Py_RETURN_NONE; -} - -PyObject* HasExtension(CMessage* self, PyObject* extension) { - const FieldDescriptor* descriptor = GetExtensionDescriptor(extension); - if (descriptor == NULL) { - return NULL; - } - return HasFieldByDescriptor(self, descriptor); -} - -// --------------------------------------------------------------------- -// Releasing messages -// -// The Python API's ClearField() and Clear() methods behave -// differently than their C++ counterparts. While the C++ versions -// clears the children the Python versions detaches the children, -// without touching their content. This impedance mismatch causes -// some complexity in the implementation, which is captured in this -// section. -// -// When a CMessage field is cleared we need to: -// -// * Release the Message used as the backing store for the CMessage -// from its parent. -// -// * Change the owner field of the released CMessage and all of its -// children to point to the newly released Message. -// -// * Clear the weak references from the released CMessage to the -// parent. -// -// When a RepeatedCompositeContainer field is cleared we need to: -// -// * Release all the Message used as the backing store for the -// CMessages stored in the container. -// -// * Change the owner field of all the released CMessage and all of -// their children to point to the newly released Messages. -// -// * Clear the weak references from the released container to the -// parent. - -struct SetOwnerVisitor : public ChildVisitor { - // new_owner must outlive this object. - explicit SetOwnerVisitor(const shared_ptr<Message>& new_owner) - : new_owner_(new_owner) {} - - int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) { - repeated_composite_container::SetOwner(container, new_owner_); - return 0; - } - - int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) { - repeated_scalar_container::SetOwner(container, new_owner_); - return 0; - } - - int VisitMapContainer(MapContainer* container) { - container->SetOwner(new_owner_); - return 0; - } - - int VisitCMessage(CMessage* cmessage, - const FieldDescriptor* field_descriptor) { - return SetOwner(cmessage, new_owner_); - } - - private: - const shared_ptr<Message>& new_owner_; -}; - -// Change the owner of this CMessage and all its children, recursively. -int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner) { - self->owner = new_owner; - if (ForEachCompositeField(self, SetOwnerVisitor(new_owner)) == -1) - return -1; - return 0; -} - -// Releases the message specified by 'field' and returns the -// pointer. If the field does not exist a new message is created using -// 'descriptor'. The caller takes ownership of the returned pointer. -Message* ReleaseMessage(CMessage* self, - const Descriptor* descriptor, - const FieldDescriptor* field_descriptor) { - MessageFactory* message_factory = GetFactoryForMessage(self); - Message* released_message = self->message->GetReflection()->ReleaseMessage( - self->message, field_descriptor, message_factory); - // ReleaseMessage will return NULL which differs from - // child_cmessage->message, if the field does not exist. In this case, - // the latter points to the default instance via a const_cast<>, so we - // have to reset it to a new mutable object since we are taking ownership. - if (released_message == NULL) { - const Message* prototype = message_factory->GetPrototype(descriptor); - GOOGLE_DCHECK(prototype != NULL); - released_message = prototype->New(); - } - - return released_message; -} - -int ReleaseSubMessage(CMessage* self, - const FieldDescriptor* field_descriptor, - CMessage* child_cmessage) { - // Release the Message - shared_ptr<Message> released_message(ReleaseMessage( - self, child_cmessage->message->GetDescriptor(), field_descriptor)); - child_cmessage->message = released_message.get(); - child_cmessage->owner.swap(released_message); - child_cmessage->parent = NULL; - child_cmessage->parent_field_descriptor = NULL; - child_cmessage->read_only = false; - return ForEachCompositeField(child_cmessage, - SetOwnerVisitor(child_cmessage->owner)); -} - -struct ReleaseChild : public ChildVisitor { - // message must outlive this object. - explicit ReleaseChild(CMessage* parent) : - parent_(parent) {} - - int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) { - return repeated_composite_container::Release(container); - } - - int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) { - return repeated_scalar_container::Release(container); - } - - int VisitMapContainer(MapContainer* container) { - return container->Release(); - } - - int VisitCMessage(CMessage* cmessage, - const FieldDescriptor* field_descriptor) { - return ReleaseSubMessage(parent_, field_descriptor, cmessage); - } - - CMessage* parent_; -}; - -int InternalReleaseFieldByDescriptor( - CMessage* self, - const FieldDescriptor* field_descriptor, - PyObject* composite_field) { - return VisitCompositeField( - field_descriptor, - composite_field, - ReleaseChild(self)); -} - -PyObject* ClearFieldByDescriptor( - CMessage* self, - const FieldDescriptor* descriptor) { - if (!CheckFieldBelongsToMessage(descriptor, self->message)) { - return NULL; - } - AssureWritable(self); - self->message->GetReflection()->ClearField(self->message, descriptor); - Py_RETURN_NONE; -} - -PyObject* ClearField(CMessage* self, PyObject* arg) { - if (!PyString_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "field name must be a string"); - return NULL; - } -#if PY_MAJOR_VERSION < 3 - const char* field_name = PyString_AS_STRING(arg); - Py_ssize_t size = PyString_GET_SIZE(arg); -#else - Py_ssize_t size; - const char* field_name = PyUnicode_AsUTF8AndSize(arg, &size); -#endif - AssureWritable(self); - Message* message = self->message; - ScopedPyObjectPtr arg_in_oneof; - bool is_in_oneof; - const FieldDescriptor* field_descriptor = - FindFieldWithOneofs(message, string(field_name, size), &is_in_oneof); - if (field_descriptor == NULL) { - if (!is_in_oneof) { - PyErr_Format(PyExc_ValueError, - "Protocol message has no \"%s\" field.", field_name); - return NULL; - } else { - Py_RETURN_NONE; - } - } else if (is_in_oneof) { - const string& name = field_descriptor->name(); - arg_in_oneof.reset(PyString_FromStringAndSize(name.c_str(), name.size())); - arg = arg_in_oneof.get(); - } - - PyObject* composite_field = self->composite_fields ? - PyDict_GetItem(self->composite_fields, arg) : NULL; - - // Only release the field if there's a possibility that there are - // references to it. - if (composite_field != NULL) { - if (InternalReleaseFieldByDescriptor(self, field_descriptor, - composite_field) < 0) { - return NULL; - } - PyDict_DelItem(self->composite_fields, arg); - } - message->GetReflection()->ClearField(message, field_descriptor); - if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && - !message->GetReflection()->SupportsUnknownEnumValues()) { - UnknownFieldSet* unknown_field_set = - message->GetReflection()->MutableUnknownFields(message); - unknown_field_set->DeleteByNumber(field_descriptor->number()); - } - - Py_RETURN_NONE; -} - -PyObject* Clear(CMessage* self) { - AssureWritable(self); - if (ForEachCompositeField(self, ReleaseChild(self)) == -1) - return NULL; - Py_CLEAR(self->extensions); - if (self->composite_fields) { - PyDict_Clear(self->composite_fields); - } - self->message->Clear(); - Py_RETURN_NONE; -} - -// --------------------------------------------------------------------- - -static string GetMessageName(CMessage* self) { - if (self->parent_field_descriptor != NULL) { - return self->parent_field_descriptor->full_name(); - } else { - return self->message->GetDescriptor()->full_name(); - } -} - -static PyObject* SerializeToString(CMessage* self, PyObject* args) { - if (!self->message->IsInitialized()) { - ScopedPyObjectPtr errors(FindInitializationErrors(self)); - if (errors == NULL) { - return NULL; - } - ScopedPyObjectPtr comma(PyString_FromString(",")); - if (comma == NULL) { - return NULL; - } - ScopedPyObjectPtr joined( - PyObject_CallMethod(comma.get(), "join", "O", errors.get())); - if (joined == NULL) { - return NULL; - } - - // TODO(haberman): this is a (hopefully temporary) hack. The unit testing - // infrastructure reloads all pure-Python modules for every test, but not - // C++ modules (because that's generally impossible: - // http://bugs.python.org/issue1144263). But if we cache EncodeError, we'll - // return the EncodeError from a previous load of the module, which won't - // match a user's attempt to catch EncodeError. So we have to look it up - // again every time. - ScopedPyObjectPtr message_module(PyImport_ImportModule( - "google.protobuf.message")); - if (message_module.get() == NULL) { - return NULL; - } - - ScopedPyObjectPtr encode_error( - PyObject_GetAttrString(message_module.get(), "EncodeError")); - if (encode_error.get() == NULL) { - return NULL; - } - PyErr_Format(encode_error.get(), - "Message %s is missing required fields: %s", - GetMessageName(self).c_str(), PyString_AsString(joined.get())); - return NULL; - } - int size = self->message->ByteSize(); - if (size <= 0) { - return PyBytes_FromString(""); - } - PyObject* result = PyBytes_FromStringAndSize(NULL, size); - if (result == NULL) { - return NULL; - } - char* buffer = PyBytes_AS_STRING(result); - self->message->SerializeWithCachedSizesToArray( - reinterpret_cast<uint8*>(buffer)); - return result; -} - -static PyObject* SerializePartialToString(CMessage* self) { - string contents; - self->message->SerializePartialToString(&contents); - return PyBytes_FromStringAndSize(contents.c_str(), contents.size()); -} - -// Formats proto fields for ascii dumps using python formatting functions where -// appropriate. -class PythonFieldValuePrinter : public TextFormat::FieldValuePrinter { - public: - // Python has some differences from C++ when printing floating point numbers. - // - // 1) Trailing .0 is always printed. - // 2) (Python2) Output is rounded to 12 digits. - // 3) (Python3) The full precision of the double is preserved (and Python uses - // David M. Gay's dtoa(), when the C++ code uses SimpleDtoa. There are some - // differences, but they rarely happen) - // - // We override floating point printing with the C-API function for printing - // Python floats to ensure consistency. - string PrintFloat(float value) const { return PrintDouble(value); } - string PrintDouble(double value) const { - // This implementation is not highly optimized (it allocates two temporary - // Python objects) but it is simple and portable. If this is shown to be a - // performance bottleneck, we can optimize it, but the results will likely - // be more complicated to accommodate the differing behavior of double - // formatting between Python 2 and Python 3. - // - // (Though a valid question is: do we really want to make out output - // dependent on the Python version?) - ScopedPyObjectPtr py_value(PyFloat_FromDouble(value)); - if (!py_value.get()) { - return string(); - } - - ScopedPyObjectPtr py_str(PyObject_Str(py_value.get())); - if (!py_str.get()) { - return string(); - } - - return string(PyString_AsString(py_str.get())); - } -}; - -static PyObject* ToStr(CMessage* self) { - TextFormat::Printer printer; - // Passes ownership - printer.SetDefaultFieldValuePrinter(new PythonFieldValuePrinter()); - printer.SetHideUnknownFields(true); - string output; - if (!printer.PrintToString(*self->message, &output)) { - PyErr_SetString(PyExc_ValueError, "Unable to convert message to str"); - return NULL; - } - return PyString_FromString(output.c_str()); -} - -PyObject* MergeFrom(CMessage* self, PyObject* arg) { - CMessage* other_message; - if (!PyObject_TypeCheck(arg, &CMessage_Type)) { - PyErr_Format(PyExc_TypeError, - "Parameter to MergeFrom() must be instance of same class: " - "expected %s got %s.", - self->message->GetDescriptor()->full_name().c_str(), - Py_TYPE(arg)->tp_name); - return NULL; - } - - other_message = reinterpret_cast<CMessage*>(arg); - if (other_message->message->GetDescriptor() != - self->message->GetDescriptor()) { - PyErr_Format(PyExc_TypeError, - "Parameter to MergeFrom() must be instance of same class: " - "expected %s got %s.", - self->message->GetDescriptor()->full_name().c_str(), - other_message->message->GetDescriptor()->full_name().c_str()); - return NULL; - } - AssureWritable(self); - - // TODO(tibell): Message::MergeFrom might turn some child Messages - // into mutable messages, invalidating the message field in the - // corresponding CMessages. We should run a FixupMessageReferences - // pass here. - - self->message->MergeFrom(*other_message->message); - Py_RETURN_NONE; -} - -static PyObject* CopyFrom(CMessage* self, PyObject* arg) { - CMessage* other_message; - if (!PyObject_TypeCheck(arg, &CMessage_Type)) { - PyErr_Format(PyExc_TypeError, - "Parameter to CopyFrom() must be instance of same class: " - "expected %s got %s.", - self->message->GetDescriptor()->full_name().c_str(), - Py_TYPE(arg)->tp_name); - return NULL; - } - - other_message = reinterpret_cast<CMessage*>(arg); - - if (self == other_message) { - Py_RETURN_NONE; - } - - if (other_message->message->GetDescriptor() != - self->message->GetDescriptor()) { - PyErr_Format(PyExc_TypeError, - "Parameter to CopyFrom() must be instance of same class: " - "expected %s got %s.", - self->message->GetDescriptor()->full_name().c_str(), - other_message->message->GetDescriptor()->full_name().c_str()); - return NULL; - } - - AssureWritable(self); - - // CopyFrom on the message will not clean up self->composite_fields, - // which can leave us in an inconsistent state, so clear it out here. - (void)ScopedPyObjectPtr(Clear(self)); - - self->message->CopyFrom(*other_message->message); - - Py_RETURN_NONE; -} - -// Protobuf has a 64MB limit built in, this variable will override this. Please -// do not enable this unless you fully understand the implications: protobufs -// must all be kept in memory at the same time, so if they grow too big you may -// get OOM errors. The protobuf APIs do not provide any tools for processing -// protobufs in chunks. If you have protos this big you should break them up if -// it is at all convenient to do so. -static bool allow_oversize_protos = false; - -// Provide a method in the module to set allow_oversize_protos to a boolean -// value. This method returns the newly value of allow_oversize_protos. -PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg) { - if (!arg || !PyBool_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "Argument to SetAllowOversizeProtos must be boolean"); - return NULL; - } - allow_oversize_protos = PyObject_IsTrue(arg); - if (allow_oversize_protos) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} - -static PyObject* MergeFromString(CMessage* self, PyObject* arg) { - const void* data; - Py_ssize_t data_length; - if (PyObject_AsReadBuffer(arg, &data, &data_length) < 0) { - return NULL; - } - - AssureWritable(self); - io::CodedInputStream input( - reinterpret_cast<const uint8*>(data), data_length); - if (allow_oversize_protos) { - input.SetTotalBytesLimit(INT_MAX, INT_MAX); - } - PyDescriptorPool* pool = GetDescriptorPoolForMessage(self); - input.SetExtensionRegistry(pool->pool, pool->message_factory); - bool success = self->message->MergePartialFromCodedStream(&input); - if (success) { - return PyInt_FromLong(input.CurrentPosition()); - } else { - PyErr_Format(DecodeError_class, "Error parsing message"); - return NULL; - } -} - -static PyObject* ParseFromString(CMessage* self, PyObject* arg) { - if (ScopedPyObjectPtr(Clear(self)) == NULL) { - return NULL; - } - return MergeFromString(self, arg); -} - -static PyObject* ByteSize(CMessage* self, PyObject* args) { - return PyLong_FromLong(self->message->ByteSize()); -} - -static PyObject* RegisterExtension(PyObject* cls, - PyObject* extension_handle) { - const FieldDescriptor* descriptor = - GetExtensionDescriptor(extension_handle); - if (descriptor == NULL) { - return NULL; - } - - ScopedPyObjectPtr extensions_by_name( - PyObject_GetAttr(cls, k_extensions_by_name)); - if (extensions_by_name == NULL) { - PyErr_SetString(PyExc_TypeError, "no extensions_by_name on class"); - return NULL; - } - ScopedPyObjectPtr full_name(PyObject_GetAttr(extension_handle, kfull_name)); - if (full_name == NULL) { - return NULL; - } - - // If the extension was already registered, check that it is the same. - PyObject* existing_extension = - PyDict_GetItem(extensions_by_name.get(), full_name.get()); - if (existing_extension != NULL) { - const FieldDescriptor* existing_extension_descriptor = - GetExtensionDescriptor(existing_extension); - if (existing_extension_descriptor != descriptor) { - PyErr_SetString(PyExc_ValueError, "Double registration of Extensions"); - return NULL; - } - // Nothing else to do. - Py_RETURN_NONE; - } - - if (PyDict_SetItem(extensions_by_name.get(), full_name.get(), - extension_handle) < 0) { - return NULL; - } - - // Also store a mapping from extension number to implementing class. - ScopedPyObjectPtr extensions_by_number( - PyObject_GetAttr(cls, k_extensions_by_number)); - if (extensions_by_number == NULL) { - PyErr_SetString(PyExc_TypeError, "no extensions_by_number on class"); - return NULL; - } - - ScopedPyObjectPtr number(PyObject_GetAttrString(extension_handle, "number")); - if (number == NULL) { - return NULL; - } - - // If the extension was already registered by number, check that it is the - // same. - existing_extension = PyDict_GetItem(extensions_by_number.get(), number.get()); - if (existing_extension != NULL) { - const FieldDescriptor* existing_extension_descriptor = - GetExtensionDescriptor(existing_extension); - if (existing_extension_descriptor != descriptor) { - const Descriptor* msg_desc = GetMessageDescriptor( - reinterpret_cast<PyTypeObject*>(cls)); - PyErr_Format( - PyExc_ValueError, - "Extensions \"%s\" and \"%s\" both try to extend message type " - "\"%s\" with field number %ld.", - existing_extension_descriptor->full_name().c_str(), - descriptor->full_name().c_str(), - msg_desc->full_name().c_str(), - PyInt_AsLong(number.get())); - return NULL; - } - // Nothing else to do. - Py_RETURN_NONE; - } - if (PyDict_SetItem(extensions_by_number.get(), number.get(), - extension_handle) < 0) { - return NULL; - } - - // Check if it's a message set - if (descriptor->is_extension() && - descriptor->containing_type()->options().message_set_wire_format() && - descriptor->type() == FieldDescriptor::TYPE_MESSAGE && - descriptor->label() == FieldDescriptor::LABEL_OPTIONAL) { - ScopedPyObjectPtr message_name(PyString_FromStringAndSize( - descriptor->message_type()->full_name().c_str(), - descriptor->message_type()->full_name().size())); - if (message_name == NULL) { - return NULL; - } - PyDict_SetItem(extensions_by_name.get(), message_name.get(), - extension_handle); - } - - Py_RETURN_NONE; -} - -static PyObject* SetInParent(CMessage* self, PyObject* args) { - AssureWritable(self); - Py_RETURN_NONE; -} - -static PyObject* WhichOneof(CMessage* self, PyObject* arg) { - Py_ssize_t name_size; - char *name_data; - if (PyString_AsStringAndSize(arg, &name_data, &name_size) < 0) - return NULL; - string oneof_name = string(name_data, name_size); - const OneofDescriptor* oneof_desc = - self->message->GetDescriptor()->FindOneofByName(oneof_name); - if (oneof_desc == NULL) { - PyErr_Format(PyExc_ValueError, - "Protocol message has no oneof \"%s\" field.", - oneof_name.c_str()); - return NULL; - } - const FieldDescriptor* field_in_oneof = - self->message->GetReflection()->GetOneofFieldDescriptor( - *self->message, oneof_desc); - if (field_in_oneof == NULL) { - Py_RETURN_NONE; - } else { - const string& name = field_in_oneof->name(); - return PyString_FromStringAndSize(name.c_str(), name.size()); - } -} - -static PyObject* GetExtensionDict(CMessage* self, void *closure); - -static PyObject* ListFields(CMessage* self) { - vector<const FieldDescriptor*> fields; - self->message->GetReflection()->ListFields(*self->message, &fields); - - // Normally, the list will be exactly the size of the fields. - ScopedPyObjectPtr all_fields(PyList_New(fields.size())); - if (all_fields == NULL) { - return NULL; - } - - // When there are unknown extensions, the py list will *not* contain - // the field information. Thus the actual size of the py list will be - // smaller than the size of fields. Set the actual size at the end. - Py_ssize_t actual_size = 0; - for (size_t i = 0; i < fields.size(); ++i) { - ScopedPyObjectPtr t(PyTuple_New(2)); - if (t == NULL) { - return NULL; - } - - if (fields[i]->is_extension()) { - ScopedPyObjectPtr extension_field( - PyFieldDescriptor_FromDescriptor(fields[i])); - if (extension_field == NULL) { - return NULL; - } - // With C++ descriptors, the field can always be retrieved, but for - // unknown extensions which have not been imported in Python code, there - // is no message class and we cannot retrieve the value. - // TODO(amauryfa): consider building the class on the fly! - if (fields[i]->message_type() != NULL && - cdescriptor_pool::GetMessageClass( - GetDescriptorPoolForMessage(self), - fields[i]->message_type()) == NULL) { - PyErr_Clear(); - continue; - } - ScopedPyObjectPtr extensions(GetExtensionDict(self, NULL)); - if (extensions == NULL) { - return NULL; - } - // 'extension' reference later stolen by PyTuple_SET_ITEM. - PyObject* extension = PyObject_GetItem( - extensions.get(), extension_field.get()); - if (extension == NULL) { - return NULL; - } - PyTuple_SET_ITEM(t.get(), 0, extension_field.release()); - // Steals reference to 'extension' - PyTuple_SET_ITEM(t.get(), 1, extension); - } else { - // Normal field - const string& field_name = fields[i]->name(); - ScopedPyObjectPtr py_field_name(PyString_FromStringAndSize( - field_name.c_str(), field_name.length())); - if (py_field_name == NULL) { - PyErr_SetString(PyExc_ValueError, "bad string"); - return NULL; - } - ScopedPyObjectPtr field_descriptor( - PyFieldDescriptor_FromDescriptor(fields[i])); - if (field_descriptor == NULL) { - return NULL; - } - - PyObject* field_value = GetAttr(self, py_field_name.get()); - if (field_value == NULL) { - PyErr_SetObject(PyExc_ValueError, py_field_name.get()); - return NULL; - } - PyTuple_SET_ITEM(t.get(), 0, field_descriptor.release()); - PyTuple_SET_ITEM(t.get(), 1, field_value); - } - PyList_SET_ITEM(all_fields.get(), actual_size, t.release()); - ++actual_size; - } - if (static_cast<size_t>(actual_size) != fields.size() && - (PyList_SetSlice(all_fields.get(), actual_size, fields.size(), NULL) < - 0)) { - return NULL; - } - return all_fields.release(); -} - -static PyObject* DiscardUnknownFields(CMessage* self) { - AssureWritable(self); - self->message->DiscardUnknownFields(); - Py_RETURN_NONE; -} - -PyObject* FindInitializationErrors(CMessage* self) { - Message* message = self->message; - vector<string> errors; - message->FindInitializationErrors(&errors); - - PyObject* error_list = PyList_New(errors.size()); - if (error_list == NULL) { - return NULL; - } - for (size_t i = 0; i < errors.size(); ++i) { - const string& error = errors[i]; - PyObject* error_string = PyString_FromStringAndSize( - error.c_str(), error.length()); - if (error_string == NULL) { - Py_DECREF(error_list); - return NULL; - } - PyList_SET_ITEM(error_list, i, error_string); - } - return error_list; -} - -static PyObject* RichCompare(CMessage* self, PyObject* other, int opid) { - // Only equality comparisons are implemented. - if (opid != Py_EQ && opid != Py_NE) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - bool equals = true; - // If other is not a message, it cannot be equal. - if (!PyObject_TypeCheck(other, &CMessage_Type)) { - equals = false; - } - const google::protobuf::Message* other_message = - reinterpret_cast<CMessage*>(other)->message; - // If messages don't have the same descriptors, they are not equal. - if (equals && - self->message->GetDescriptor() != other_message->GetDescriptor()) { - equals = false; - } - // Check the message contents. - if (equals && !google::protobuf::util::MessageDifferencer::Equals( - *self->message, - *reinterpret_cast<CMessage*>(other)->message)) { - equals = false; - } - if (equals ^ (opid == Py_EQ)) { - Py_RETURN_FALSE; - } else { - Py_RETURN_TRUE; - } -} - -PyObject* InternalGetScalar(const Message* message, - const FieldDescriptor* field_descriptor) { - const Reflection* reflection = message->GetReflection(); - - if (!CheckFieldBelongsToMessage(field_descriptor, message)) { - return NULL; - } - - PyObject* result = NULL; - switch (field_descriptor->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: { - int32 value = reflection->GetInt32(*message, field_descriptor); - result = PyInt_FromLong(value); - break; - } - case FieldDescriptor::CPPTYPE_INT64: { - int64 value = reflection->GetInt64(*message, field_descriptor); - result = PyLong_FromLongLong(value); - break; - } - case FieldDescriptor::CPPTYPE_UINT32: { - uint32 value = reflection->GetUInt32(*message, field_descriptor); - result = PyInt_FromSize_t(value); - break; - } - case FieldDescriptor::CPPTYPE_UINT64: { - uint64 value = reflection->GetUInt64(*message, field_descriptor); - result = PyLong_FromUnsignedLongLong(value); - break; - } - case FieldDescriptor::CPPTYPE_FLOAT: { - float value = reflection->GetFloat(*message, field_descriptor); - result = PyFloat_FromDouble(value); - break; - } - case FieldDescriptor::CPPTYPE_DOUBLE: { - double value = reflection->GetDouble(*message, field_descriptor); - result = PyFloat_FromDouble(value); - break; - } - case FieldDescriptor::CPPTYPE_BOOL: { - bool value = reflection->GetBool(*message, field_descriptor); - result = PyBool_FromLong(value); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - string value = reflection->GetString(*message, field_descriptor); - result = ToStringObject(field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - if (!message->GetReflection()->SupportsUnknownEnumValues() && - !message->GetReflection()->HasField(*message, field_descriptor)) { - // Look for the value in the unknown fields. - const UnknownFieldSet& unknown_field_set = - message->GetReflection()->GetUnknownFields(*message); - for (int i = 0; i < unknown_field_set.field_count(); ++i) { - if (unknown_field_set.field(i).number() == - field_descriptor->number() && - unknown_field_set.field(i).type() == - google::protobuf::UnknownField::TYPE_VARINT) { - result = PyInt_FromLong(unknown_field_set.field(i).varint()); - break; - } - } - } - - if (result == NULL) { - const EnumValueDescriptor* enum_value = - message->GetReflection()->GetEnum(*message, field_descriptor); - result = PyInt_FromLong(enum_value->number()); - } - break; - } - default: - PyErr_Format( - PyExc_SystemError, "Getting a value from a field of unknown type %d", - field_descriptor->cpp_type()); - } - - return result; -} - -PyObject* InternalGetSubMessage( - CMessage* self, const FieldDescriptor* field_descriptor) { - const Reflection* reflection = self->message->GetReflection(); - PyDescriptorPool* pool = GetDescriptorPoolForMessage(self); - const Message& sub_message = reflection->GetMessage( - *self->message, field_descriptor, pool->message_factory); - - CMessageClass* message_class = cdescriptor_pool::GetMessageClass( - pool, field_descriptor->message_type()); - if (message_class == NULL) { - return NULL; - } - - CMessage* cmsg = cmessage::NewEmptyMessage(message_class); - if (cmsg == NULL) { - return NULL; - } - - cmsg->owner = self->owner; - cmsg->parent = self; - cmsg->parent_field_descriptor = field_descriptor; - cmsg->read_only = !reflection->HasField(*self->message, field_descriptor); - cmsg->message = const_cast<Message*>(&sub_message); - - return reinterpret_cast<PyObject*>(cmsg); -} - -int InternalSetNonOneofScalar( - Message* message, - const FieldDescriptor* field_descriptor, - PyObject* arg) { - const Reflection* reflection = message->GetReflection(); - - if (!CheckFieldBelongsToMessage(field_descriptor, message)) { - return -1; - } - - switch (field_descriptor->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: { - GOOGLE_CHECK_GET_INT32(arg, value, -1); - reflection->SetInt32(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_INT64: { - GOOGLE_CHECK_GET_INT64(arg, value, -1); - reflection->SetInt64(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_UINT32: { - GOOGLE_CHECK_GET_UINT32(arg, value, -1); - reflection->SetUInt32(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_UINT64: { - GOOGLE_CHECK_GET_UINT64(arg, value, -1); - reflection->SetUInt64(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_FLOAT: { - GOOGLE_CHECK_GET_FLOAT(arg, value, -1); - reflection->SetFloat(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_DOUBLE: { - GOOGLE_CHECK_GET_DOUBLE(arg, value, -1); - reflection->SetDouble(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_BOOL: { - GOOGLE_CHECK_GET_BOOL(arg, value, -1); - reflection->SetBool(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - if (!CheckAndSetString( - arg, message, field_descriptor, reflection, false, -1)) { - return -1; - } - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - GOOGLE_CHECK_GET_INT32(arg, value, -1); - if (reflection->SupportsUnknownEnumValues()) { - reflection->SetEnumValue(message, field_descriptor, value); - } else { - const EnumDescriptor* enum_descriptor = field_descriptor->enum_type(); - const EnumValueDescriptor* enum_value = - enum_descriptor->FindValueByNumber(value); - if (enum_value != NULL) { - reflection->SetEnum(message, field_descriptor, enum_value); - } else { - PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value); - return -1; - } - } - break; - } - default: - PyErr_Format( - PyExc_SystemError, "Setting value to a field of unknown type %d", - field_descriptor->cpp_type()); - return -1; - } - - return 0; -} - -int InternalSetScalar( - CMessage* self, - const FieldDescriptor* field_descriptor, - PyObject* arg) { - if (!CheckFieldBelongsToMessage(field_descriptor, self->message)) { - return -1; - } - - if (MaybeReleaseOverlappingOneofField(self, field_descriptor) < 0) { - return -1; - } - - return InternalSetNonOneofScalar(self->message, field_descriptor, arg); -} - -PyObject* FromString(PyTypeObject* cls, PyObject* serialized) { - PyObject* py_cmsg = PyObject_CallObject( - reinterpret_cast<PyObject*>(cls), NULL); - if (py_cmsg == NULL) { - return NULL; - } - CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg); - - ScopedPyObjectPtr py_length(MergeFromString(cmsg, serialized)); - if (py_length == NULL) { - Py_DECREF(py_cmsg); - return NULL; - } - - return py_cmsg; -} - -PyObject* DeepCopy(CMessage* self, PyObject* arg) { - PyObject* clone = PyObject_CallObject( - reinterpret_cast<PyObject*>(Py_TYPE(self)), NULL); - if (clone == NULL) { - return NULL; - } - if (!PyObject_TypeCheck(clone, &CMessage_Type)) { - Py_DECREF(clone); - return NULL; - } - if (ScopedPyObjectPtr(MergeFrom( - reinterpret_cast<CMessage*>(clone), - reinterpret_cast<PyObject*>(self))) == NULL) { - Py_DECREF(clone); - return NULL; - } - return clone; -} - -PyObject* ToUnicode(CMessage* self) { - // Lazy import to prevent circular dependencies - ScopedPyObjectPtr text_format( - PyImport_ImportModule("google.protobuf.text_format")); - if (text_format == NULL) { - return NULL; - } - ScopedPyObjectPtr method_name(PyString_FromString("MessageToString")); - if (method_name == NULL) { - return NULL; - } - Py_INCREF(Py_True); - ScopedPyObjectPtr encoded(PyObject_CallMethodObjArgs( - text_format.get(), method_name.get(), self, Py_True, NULL)); - Py_DECREF(Py_True); - if (encoded == NULL) { - return NULL; - } -#if PY_MAJOR_VERSION < 3 - PyObject* decoded = PyString_AsDecodedObject(encoded.get(), "utf-8", NULL); -#else - PyObject* decoded = PyUnicode_FromEncodedObject(encoded.get(), "utf-8", NULL); -#endif - if (decoded == NULL) { - return NULL; - } - return decoded; -} - -PyObject* Reduce(CMessage* self) { - ScopedPyObjectPtr constructor(reinterpret_cast<PyObject*>(Py_TYPE(self))); - constructor.inc(); - ScopedPyObjectPtr args(PyTuple_New(0)); - if (args == NULL) { - return NULL; - } - ScopedPyObjectPtr state(PyDict_New()); - if (state == NULL) { - return NULL; - } - ScopedPyObjectPtr serialized(SerializePartialToString(self)); - if (serialized == NULL) { - return NULL; - } - if (PyDict_SetItemString(state.get(), "serialized", serialized.get()) < 0) { - return NULL; - } - return Py_BuildValue("OOO", constructor.get(), args.get(), state.get()); -} - -PyObject* SetState(CMessage* self, PyObject* state) { - if (!PyDict_Check(state)) { - PyErr_SetString(PyExc_TypeError, "state not a dict"); - return NULL; - } - PyObject* serialized = PyDict_GetItemString(state, "serialized"); - if (serialized == NULL) { - return NULL; - } - if (ScopedPyObjectPtr(ParseFromString(self, serialized)) == NULL) { - return NULL; - } - Py_RETURN_NONE; -} - -// CMessage static methods: -PyObject* _CheckCalledFromGeneratedFile(PyObject* unused, - PyObject* unused_arg) { - if (!_CalledFromGeneratedFile(1)) { - PyErr_SetString(PyExc_TypeError, - "Descriptors should not be created directly, " - "but only retrieved from their parent."); - return NULL; - } - Py_RETURN_NONE; -} - -static PyObject* GetExtensionDict(CMessage* self, void *closure) { - if (self->extensions) { - Py_INCREF(self->extensions); - return reinterpret_cast<PyObject*>(self->extensions); - } - - // If there are extension_ranges, the message is "extendable". Allocate a - // dictionary to store the extension fields. - const Descriptor* descriptor = GetMessageDescriptor(Py_TYPE(self)); - if (descriptor->extension_range_count() > 0) { - ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self); - if (extension_dict == NULL) { - return NULL; - } - self->extensions = extension_dict; - Py_INCREF(self->extensions); - return reinterpret_cast<PyObject*>(self->extensions); - } - - PyErr_SetNone(PyExc_AttributeError); - return NULL; -} - -static PyGetSetDef Getters[] = { - {"Extensions", (getter)GetExtensionDict, NULL, "Extension dict"}, - {NULL} -}; - -static PyMethodDef Methods[] = { - { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS, - "Makes a deep copy of the class." }, - { "__reduce__", (PyCFunction)Reduce, METH_NOARGS, - "Outputs picklable representation of the message." }, - { "__setstate__", (PyCFunction)SetState, METH_O, - "Inputs picklable representation of the message." }, - { "__unicode__", (PyCFunction)ToUnicode, METH_NOARGS, - "Outputs a unicode representation of the message." }, - { "ByteSize", (PyCFunction)ByteSize, METH_NOARGS, - "Returns the size of the message in bytes." }, - { "Clear", (PyCFunction)Clear, METH_NOARGS, - "Clears the message." }, - { "ClearExtension", (PyCFunction)ClearExtension, METH_O, - "Clears a message field." }, - { "ClearField", (PyCFunction)ClearField, METH_O, - "Clears a message field." }, - { "CopyFrom", (PyCFunction)CopyFrom, METH_O, - "Copies a protocol message into the current message." }, - { "DiscardUnknownFields", (PyCFunction)DiscardUnknownFields, METH_NOARGS, - "Discards the unknown fields." }, - { "FindInitializationErrors", (PyCFunction)FindInitializationErrors, - METH_NOARGS, - "Finds unset required fields." }, - { "FromString", (PyCFunction)FromString, METH_O | METH_CLASS, - "Creates new method instance from given serialized data." }, - { "HasExtension", (PyCFunction)HasExtension, METH_O, - "Checks if a message field is set." }, - { "HasField", (PyCFunction)HasField, METH_O, - "Checks if a message field is set." }, - { "IsInitialized", (PyCFunction)IsInitialized, METH_VARARGS, - "Checks if all required fields of a protocol message are set." }, - { "ListFields", (PyCFunction)ListFields, METH_NOARGS, - "Lists all set fields of a message." }, - { "MergeFrom", (PyCFunction)MergeFrom, METH_O, - "Merges a protocol message into the current message." }, - { "MergeFromString", (PyCFunction)MergeFromString, METH_O, - "Merges a serialized message into the current message." }, - { "ParseFromString", (PyCFunction)ParseFromString, METH_O, - "Parses a serialized message into the current message." }, - { "RegisterExtension", (PyCFunction)RegisterExtension, METH_O | METH_CLASS, - "Registers an extension with the current message." }, - { "SerializePartialToString", (PyCFunction)SerializePartialToString, - METH_NOARGS, - "Serializes the message to a string, even if it isn't initialized." }, - { "SerializeToString", (PyCFunction)SerializeToString, METH_NOARGS, - "Serializes the message to a string, only for initialized messages." }, - { "SetInParent", (PyCFunction)SetInParent, METH_NOARGS, - "Sets the has bit of the given field in its parent message." }, - { "WhichOneof", (PyCFunction)WhichOneof, METH_O, - "Returns the name of the field set inside a oneof, " - "or None if no field is set." }, - - // Static Methods. - { "_CheckCalledFromGeneratedFile", (PyCFunction)_CheckCalledFromGeneratedFile, - METH_NOARGS | METH_STATIC, - "Raises TypeError if the caller is not in a _pb2.py file."}, - { NULL, NULL} -}; - -static bool SetCompositeField( - CMessage* self, PyObject* name, PyObject* value) { - if (self->composite_fields == NULL) { - self->composite_fields = PyDict_New(); - if (self->composite_fields == NULL) { - return false; - } - } - return PyDict_SetItem(self->composite_fields, name, value) == 0; -} - -PyObject* GetAttr(CMessage* self, PyObject* name) { - PyObject* value = self->composite_fields ? - PyDict_GetItem(self->composite_fields, name) : NULL; - if (value != NULL) { - Py_INCREF(value); - return value; - } - - const FieldDescriptor* field_descriptor = GetFieldDescriptor(self, name); - if (field_descriptor == NULL) { - return CMessage_Type.tp_base->tp_getattro( - reinterpret_cast<PyObject*>(self), name); - } - - if (field_descriptor->is_map()) { - PyObject* py_container = NULL; - const Descriptor* entry_type = field_descriptor->message_type(); - const FieldDescriptor* value_type = entry_type->FindFieldByName("value"); - if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - CMessageClass* value_class = cdescriptor_pool::GetMessageClass( - GetDescriptorPoolForMessage(self), value_type->message_type()); - if (value_class == NULL) { - return NULL; - } - py_container = - NewMessageMapContainer(self, field_descriptor, value_class); - } else { - py_container = NewScalarMapContainer(self, field_descriptor); - } - if (py_container == NULL) { - return NULL; - } - if (!SetCompositeField(self, name, py_container)) { - Py_DECREF(py_container); - return NULL; - } - return py_container; - } - - if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) { - PyObject* py_container = NULL; - if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - CMessageClass* message_class = cdescriptor_pool::GetMessageClass( - GetDescriptorPoolForMessage(self), field_descriptor->message_type()); - if (message_class == NULL) { - return NULL; - } - py_container = repeated_composite_container::NewContainer( - self, field_descriptor, message_class); - } else { - py_container = repeated_scalar_container::NewContainer( - self, field_descriptor); - } - if (py_container == NULL) { - return NULL; - } - if (!SetCompositeField(self, name, py_container)) { - Py_DECREF(py_container); - return NULL; - } - return py_container; - } - - if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - PyObject* sub_message = InternalGetSubMessage(self, field_descriptor); - if (sub_message == NULL) { - return NULL; - } - if (!SetCompositeField(self, name, sub_message)) { - Py_DECREF(sub_message); - return NULL; - } - return sub_message; - } - - return InternalGetScalar(self->message, field_descriptor); -} - -int SetAttr(CMessage* self, PyObject* name, PyObject* value) { - if (self->composite_fields && PyDict_Contains(self->composite_fields, name)) { - PyErr_SetString(PyExc_TypeError, "Can't set composite field"); - return -1; - } - - const FieldDescriptor* field_descriptor = GetFieldDescriptor(self, name); - if (field_descriptor != NULL) { - AssureWritable(self); - if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) { - PyErr_Format(PyExc_AttributeError, "Assignment not allowed to repeated " - "field \"%s\" in protocol message object.", - field_descriptor->name().c_str()); - return -1; - } else { - if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - PyErr_Format(PyExc_AttributeError, "Assignment not allowed to " - "field \"%s\" in protocol message object.", - field_descriptor->name().c_str()); - return -1; - } else { - return InternalSetScalar(self, field_descriptor, value); - } - } - } - - PyErr_Format(PyExc_AttributeError, - "Assignment not allowed " - "(no field \"%s\" in protocol message object).", - PyString_AsString(name)); - return -1; -} - -} // namespace cmessage - -PyTypeObject CMessage_Type = { - PyVarObject_HEAD_INIT(&CMessageClass_Type, 0) - FULL_MODULE_NAME ".CMessage", // tp_name - sizeof(CMessage), // tp_basicsize - 0, // tp_itemsize - (destructor)cmessage::Dealloc, // tp_dealloc - 0, // tp_print - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_compare - (reprfunc)cmessage::ToStr, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - PyObject_HashNotImplemented, // tp_hash - 0, // tp_call - (reprfunc)cmessage::ToStr, // tp_str - (getattrofunc)cmessage::GetAttr, // tp_getattro - (setattrofunc)cmessage::SetAttr, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags - "A ProtocolMessage", // tp_doc - 0, // tp_traverse - 0, // tp_clear - (richcmpfunc)cmessage::RichCompare, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - cmessage::Methods, // tp_methods - 0, // tp_members - cmessage::Getters, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc)cmessage::Init, // tp_init - 0, // tp_alloc - cmessage::New, // tp_new -}; - -// --- Exposing the C proto living inside Python proto to C code: - -const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg); -Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg); - -static const Message* GetCProtoInsidePyProtoImpl(PyObject* msg) { - if (!PyObject_TypeCheck(msg, &CMessage_Type)) { - return NULL; - } - CMessage* cmsg = reinterpret_cast<CMessage*>(msg); - return cmsg->message; -} - -static Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) { - if (!PyObject_TypeCheck(msg, &CMessage_Type)) { - return NULL; - } - CMessage* cmsg = reinterpret_cast<CMessage*>(msg); - if ((cmsg->composite_fields && PyDict_Size(cmsg->composite_fields) != 0) || - (cmsg->extensions != NULL && - PyDict_Size(cmsg->extensions->values) != 0)) { - // There is currently no way of accurately syncing arbitrary changes to - // the underlying C++ message back to the CMessage (e.g. removed repeated - // composite containers). We only allow direct mutation of the underlying - // C++ message if there is no child data in the CMessage. - return NULL; - } - cmessage::AssureWritable(cmsg); - return cmsg->message; -} - -static const char module_docstring[] = -"python-proto2 is a module that can be used to enhance proto2 Python API\n" -"performance.\n" -"\n" -"It provides access to the protocol buffers C++ reflection API that\n" -"implements the basic protocol buffer functions."; - -void InitGlobals() { - // TODO(gps): Check all return values in this function for NULL and propagate - // the error (MemoryError) on up to result in an import failure. These should - // also be freed and reset to NULL during finalization. - kPythonZero = PyInt_FromLong(0); - kint32min_py = PyInt_FromLong(kint32min); - kint32max_py = PyInt_FromLong(kint32max); - kuint32max_py = PyLong_FromLongLong(kuint32max); - kint64min_py = PyLong_FromLongLong(kint64min); - kint64max_py = PyLong_FromLongLong(kint64max); - kuint64max_py = PyLong_FromUnsignedLongLong(kuint64max); - - kDESCRIPTOR = PyString_FromString("DESCRIPTOR"); - k_cdescriptor = PyString_FromString("_cdescriptor"); - kfull_name = PyString_FromString("full_name"); - k_extensions_by_name = PyString_FromString("_extensions_by_name"); - k_extensions_by_number = PyString_FromString("_extensions_by_number"); - - PyObject *dummy_obj = PySet_New(NULL); - kEmptyWeakref = PyWeakref_NewRef(dummy_obj, NULL); - Py_DECREF(dummy_obj); -} - -bool InitProto2MessageModule(PyObject *m) { - // Initialize types and globals in descriptor.cc - if (!InitDescriptor()) { - return false; - } - - // Initialize types and globals in descriptor_pool.cc - if (!InitDescriptorPool()) { - return false; - } - - // Initialize constants defined in this file. - InitGlobals(); - - CMessageClass_Type.tp_base = &PyType_Type; - if (PyType_Ready(&CMessageClass_Type) < 0) { - return false; - } - PyModule_AddObject(m, "MessageMeta", - reinterpret_cast<PyObject*>(&CMessageClass_Type)); - - if (PyType_Ready(&CMessage_Type) < 0) { - return false; - } - - // DESCRIPTOR is set on each protocol buffer message class elsewhere, but set - // it here as well to document that subclasses need to set it. - PyDict_SetItem(CMessage_Type.tp_dict, kDESCRIPTOR, Py_None); - // Subclasses with message extensions will override _extensions_by_name and - // _extensions_by_number with fresh mutable dictionaries in AddDescriptors. - // All other classes can share this same immutable mapping. - ScopedPyObjectPtr empty_dict(PyDict_New()); - if (empty_dict == NULL) { - return false; - } - ScopedPyObjectPtr immutable_dict(PyDictProxy_New(empty_dict.get())); - if (immutable_dict == NULL) { - return false; - } - if (PyDict_SetItem(CMessage_Type.tp_dict, - k_extensions_by_name, immutable_dict.get()) < 0) { - return false; - } - if (PyDict_SetItem(CMessage_Type.tp_dict, - k_extensions_by_number, immutable_dict.get()) < 0) { - return false; - } - - PyModule_AddObject(m, "Message", reinterpret_cast<PyObject*>(&CMessage_Type)); - - // Initialize Repeated container types. - { - if (PyType_Ready(&RepeatedScalarContainer_Type) < 0) { - return false; - } - - PyModule_AddObject(m, "RepeatedScalarContainer", - reinterpret_cast<PyObject*>( - &RepeatedScalarContainer_Type)); - - if (PyType_Ready(&RepeatedCompositeContainer_Type) < 0) { - return false; - } - - PyModule_AddObject( - m, "RepeatedCompositeContainer", - reinterpret_cast<PyObject*>( - &RepeatedCompositeContainer_Type)); - - // Register them as collections.Sequence - ScopedPyObjectPtr collections(PyImport_ImportModule("collections")); - if (collections == NULL) { - return false; - } - ScopedPyObjectPtr mutable_sequence( - PyObject_GetAttrString(collections.get(), "MutableSequence")); - if (mutable_sequence == NULL) { - return false; - } - if (ScopedPyObjectPtr( - PyObject_CallMethod(mutable_sequence.get(), "register", "O", - &RepeatedScalarContainer_Type)) == NULL) { - return false; - } - if (ScopedPyObjectPtr( - PyObject_CallMethod(mutable_sequence.get(), "register", "O", - &RepeatedCompositeContainer_Type)) == NULL) { - return false; - } - } - - // Initialize Map container types. - { - // ScalarMapContainer_Type derives from our MutableMapping type. - ScopedPyObjectPtr containers(PyImport_ImportModule( - "google.protobuf.internal.containers")); - if (containers == NULL) { - return false; - } - - ScopedPyObjectPtr mutable_mapping( - PyObject_GetAttrString(containers.get(), "MutableMapping")); - if (mutable_mapping == NULL) { - return false; - } - - if (!PyObject_TypeCheck(mutable_mapping.get(), &PyType_Type)) { - return false; - } - - Py_INCREF(mutable_mapping.get()); -#if PY_MAJOR_VERSION >= 3 - PyObject* bases = PyTuple_New(1); - PyTuple_SET_ITEM(bases, 0, mutable_mapping.get()); - - ScalarMapContainer_Type = - PyType_FromSpecWithBases(&ScalarMapContainer_Type_spec, bases); - PyModule_AddObject(m, "ScalarMapContainer", ScalarMapContainer_Type); -#else - ScalarMapContainer_Type.tp_base = - reinterpret_cast<PyTypeObject*>(mutable_mapping.get()); - - if (PyType_Ready(&ScalarMapContainer_Type) < 0) { - return false; - } - - PyModule_AddObject(m, "ScalarMapContainer", - reinterpret_cast<PyObject*>(&ScalarMapContainer_Type)); -#endif - - if (PyType_Ready(&MapIterator_Type) < 0) { - return false; - } - - PyModule_AddObject(m, "MapIterator", - reinterpret_cast<PyObject*>(&MapIterator_Type)); - - -#if PY_MAJOR_VERSION >= 3 - MessageMapContainer_Type = - PyType_FromSpecWithBases(&MessageMapContainer_Type_spec, bases); - PyModule_AddObject(m, "MessageMapContainer", MessageMapContainer_Type); -#else - Py_INCREF(mutable_mapping.get()); - MessageMapContainer_Type.tp_base = - reinterpret_cast<PyTypeObject*>(mutable_mapping.get()); - - if (PyType_Ready(&MessageMapContainer_Type) < 0) { - return false; - } - - PyModule_AddObject(m, "MessageMapContainer", - reinterpret_cast<PyObject*>(&MessageMapContainer_Type)); -#endif - } - - if (PyType_Ready(&ExtensionDict_Type) < 0) { - return false; - } - PyModule_AddObject( - m, "ExtensionDict", - reinterpret_cast<PyObject*>(&ExtensionDict_Type)); - - // Expose the DescriptorPool used to hold all descriptors added from generated - // pb2.py files. - // PyModule_AddObject steals a reference. - Py_INCREF(GetDefaultDescriptorPool()); - PyModule_AddObject(m, "default_pool", - reinterpret_cast<PyObject*>(GetDefaultDescriptorPool())); - - PyModule_AddObject(m, "DescriptorPool", reinterpret_cast<PyObject*>( - &PyDescriptorPool_Type)); - - // This implementation provides full Descriptor types, we advertise it so that - // descriptor.py can use them in replacement of the Python classes. - PyModule_AddIntConstant(m, "_USE_C_DESCRIPTORS", 1); - - PyModule_AddObject(m, "Descriptor", reinterpret_cast<PyObject*>( - &PyMessageDescriptor_Type)); - PyModule_AddObject(m, "FieldDescriptor", reinterpret_cast<PyObject*>( - &PyFieldDescriptor_Type)); - PyModule_AddObject(m, "EnumDescriptor", reinterpret_cast<PyObject*>( - &PyEnumDescriptor_Type)); - PyModule_AddObject(m, "EnumValueDescriptor", reinterpret_cast<PyObject*>( - &PyEnumValueDescriptor_Type)); - PyModule_AddObject(m, "FileDescriptor", reinterpret_cast<PyObject*>( - &PyFileDescriptor_Type)); - PyModule_AddObject(m, "OneofDescriptor", reinterpret_cast<PyObject*>( - &PyOneofDescriptor_Type)); - PyModule_AddObject(m, "ServiceDescriptor", reinterpret_cast<PyObject*>( - &PyServiceDescriptor_Type)); - PyModule_AddObject(m, "MethodDescriptor", reinterpret_cast<PyObject*>( - &PyMethodDescriptor_Type)); - - PyObject* enum_type_wrapper = PyImport_ImportModule( - "google.protobuf.internal.enum_type_wrapper"); - if (enum_type_wrapper == NULL) { - return false; - } - EnumTypeWrapper_class = - PyObject_GetAttrString(enum_type_wrapper, "EnumTypeWrapper"); - Py_DECREF(enum_type_wrapper); - - PyObject* message_module = PyImport_ImportModule( - "google.protobuf.message"); - if (message_module == NULL) { - return false; - } - EncodeError_class = PyObject_GetAttrString(message_module, "EncodeError"); - DecodeError_class = PyObject_GetAttrString(message_module, "DecodeError"); - PythonMessage_class = PyObject_GetAttrString(message_module, "Message"); - Py_DECREF(message_module); - - PyObject* pickle_module = PyImport_ImportModule("pickle"); - if (pickle_module == NULL) { - return false; - } - PickleError_class = PyObject_GetAttrString(pickle_module, "PickleError"); - Py_DECREF(pickle_module); - - // Override {Get,Mutable}CProtoInsidePyProto. - GetCProtoInsidePyProtoPtr = GetCProtoInsidePyProtoImpl; - MutableCProtoInsidePyProtoPtr = MutableCProtoInsidePyProtoImpl; - - return true; -} - -} // namespace python -} // namespace protobuf - -} // namespace google diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h deleted file mode 100644 index 8b399e05..00000000 --- a/python/google/protobuf/pyext/message.h +++ /dev/null @@ -1,365 +0,0 @@ -// 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. - -// Author: anuraag@google.com (Anuraag Agrawal) -// Author: tibell@google.com (Johan Tibell) - -#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_H__ -#define GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_H__ - -#include <Python.h> - -#include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif -#include <string> - -namespace google { -namespace protobuf { - -class Message; -class Reflection; -class FieldDescriptor; -class Descriptor; -class DescriptorPool; -class MessageFactory; - -#ifdef _SHARED_PTR_H -using std::shared_ptr; -using std::string; -#else -using internal::shared_ptr; -#endif - -namespace python { - -struct ExtensionDict; -struct PyDescriptorPool; - -typedef struct CMessage { - PyObject_HEAD; - - // This is the top-level C++ Message object that owns the whole - // proto tree. Every Python CMessage holds a reference to it in - // order to keep it alive as long as there's a Python object that - // references any part of the tree. - shared_ptr<Message> owner; - - // Weak reference to a parent CMessage object. This is NULL for any top-level - // message and is set for any child message (i.e. a child submessage or a - // part of a repeated composite field). - // - // Used to make sure all ancestors are also mutable when first modifying - // a child submessage (in other words, turning a default message instance - // into a mutable one). - // - // If a submessage is released (becomes a new top-level message), this field - // MUST be set to NULL. The parent may get deallocated and further attempts - // to use this pointer will result in a crash. - struct CMessage* parent; - - // Pointer to the parent's descriptor that describes this submessage. - // Used together with the parent's message when making a default message - // instance mutable. - // The pointer is owned by the global DescriptorPool. - const FieldDescriptor* parent_field_descriptor; - - // Pointer to the C++ Message object for this CMessage. The - // CMessage does not own this pointer. - Message* message; - - // Indicates this submessage is pointing to a default instance of a message. - // Submessages are always first created as read only messages and are then - // made writable, at which point this field is set to false. - bool read_only; - - // A reference to a Python dictionary containing CMessage, - // RepeatedCompositeContainer, and RepeatedScalarContainer - // objects. Used as a cache to make sure we don't have to make a - // Python wrapper for the C++ Message objects on every access, or - // deal with the synchronization nightmare that could create. - PyObject* composite_fields; - - // A reference to the dictionary containing the message's extensions. - // Similar to composite_fields, acting as a cache, but also contains the - // required extension dict logic. - ExtensionDict* extensions; -} CMessage; - -extern PyTypeObject CMessage_Type; - - -// The (meta) type of all Messages classes. -// It allows us to cache some C++ pointers in the class object itself, they are -// faster to extract than from the type's dictionary. - -struct CMessageClass { - // This is how CPython subclasses C structures: the base structure must be - // the first member of the object. - PyHeapTypeObject super; - - // C++ descriptor of this message. - const Descriptor* message_descriptor; - - // Owned reference, used to keep the pointer above alive. - PyObject* py_message_descriptor; - - // The Python DescriptorPool used to create the class. It is needed to resolve - // fields descriptors, including extensions fields; its C++ MessageFactory is - // used to instantiate submessages. - // This can be different from DESCRIPTOR.file.pool, in the case of a custom - // DescriptorPool which defines new extensions. - // We own the reference, because it's important to keep the descriptors and - // factory alive. - PyDescriptorPool* py_descriptor_pool; - - PyObject* AsPyObject() { - return reinterpret_cast<PyObject*>(this); - } -}; - - -namespace cmessage { - -// Internal function to create a new empty Message Python object, but with empty -// pointers to the C++ objects. -// The caller must fill self->message, self->owner and eventually self->parent. -CMessage* NewEmptyMessage(CMessageClass* type); - -// Release a submessage from its proto tree, making it a new top-level messgae. -// A new message will be created if this is a read-only default instance. -// -// Corresponds to reflection api method ReleaseMessage. -int ReleaseSubMessage(CMessage* self, - const FieldDescriptor* field_descriptor, - CMessage* child_cmessage); - -// Retrieves the C++ descriptor of a Python Extension descriptor. -// On error, return NULL with an exception set. -const FieldDescriptor* GetExtensionDescriptor(PyObject* extension); - -// Initializes a new CMessage instance for a submessage. Only called once per -// submessage as the result is cached in composite_fields. -// -// Corresponds to reflection api method GetMessage. -PyObject* InternalGetSubMessage( - CMessage* self, const FieldDescriptor* field_descriptor); - -// Deletes a range of C++ submessages in a repeated field (following a -// removal in a RepeatedCompositeContainer). -// -// Releases messages to the provided cmessage_list if it is not NULL rather -// than just removing them from the underlying proto. This cmessage_list must -// have a CMessage for each underlying submessage. The CMessages referred to -// by slice will be removed from cmessage_list by this function. -// -// Corresponds to reflection api method RemoveLast. -int InternalDeleteRepeatedField(CMessage* self, - const FieldDescriptor* field_descriptor, - PyObject* slice, PyObject* cmessage_list); - -// Sets the specified scalar value to the message. -int InternalSetScalar(CMessage* self, - const FieldDescriptor* field_descriptor, - PyObject* value); - -// Sets the specified scalar value to the message. Requires it is not a Oneof. -int InternalSetNonOneofScalar(Message* message, - const FieldDescriptor* field_descriptor, - PyObject* arg); - -// Retrieves the specified scalar value from the message. -// -// Returns a new python reference. -PyObject* InternalGetScalar(const Message* message, - const FieldDescriptor* field_descriptor); - -// Clears the message, removing all contained data. Extension dictionary and -// submessages are released first if there are remaining external references. -// -// Corresponds to message api method Clear. -PyObject* Clear(CMessage* self); - -// Clears the data described by the given descriptor. Used to clear extensions -// (which don't have names). Extension release is handled by ExtensionDict -// class, not this function. -// TODO(anuraag): Try to make this discrepancy in release semantics with -// ClearField less confusing. -// -// Corresponds to reflection api method ClearField. -PyObject* ClearFieldByDescriptor( - CMessage* self, const FieldDescriptor* descriptor); - -// Clears the data for the given field name. The message is released if there -// are any external references. -// -// Corresponds to reflection api method ClearField. -PyObject* ClearField(CMessage* self, PyObject* arg); - -// Checks if the message has the field described by the descriptor. Used for -// extensions (which have no name). -// -// Corresponds to reflection api method HasField -PyObject* HasFieldByDescriptor( - CMessage* self, const FieldDescriptor* field_descriptor); - -// Checks if the message has the named field. -// -// Corresponds to reflection api method HasField. -PyObject* HasField(CMessage* self, PyObject* arg); - -// Initializes values of fields on a newly constructed message. -int InitAttributes(CMessage* self, PyObject* kwargs); - -PyObject* MergeFrom(CMessage* self, PyObject* arg); - -// Retrieves an attribute named 'name' from CMessage 'self'. Returns -// the attribute value on success, or NULL on failure. -// -// Returns a new reference. -PyObject* GetAttr(CMessage* self, PyObject* name); - -// Set the value of the attribute named 'name', for CMessage 'self', -// to the value 'value'. Returns -1 on failure. -int SetAttr(CMessage* self, PyObject* name, PyObject* value); - -PyObject* FindInitializationErrors(CMessage* self); - -// Set the owner field of self and any children of self, recursively. -// Used when self is being released and thus has a new owner (the -// released Message.) -int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner); - -int AssureWritable(CMessage* self); - -// Returns the "best" DescriptorPool for the given message. -// This is often equivalent to message.DESCRIPTOR.pool, but not always, when -// the message class was created from a MessageFactory using a custom pool which -// uses the generated pool as an underlay. -// -// The returned pool is suitable for finding fields and building submessages, -// even in the case of extensions. -PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message); - -PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg); - -} // namespace cmessage - - -/* Is 64bit */ -#define IS_64BIT (SIZEOF_LONG == 8) - -#define FIELD_IS_REPEATED(field_descriptor) \ - ((field_descriptor)->label() == FieldDescriptor::LABEL_REPEATED) - -#define GOOGLE_CHECK_GET_INT32(arg, value, err) \ - int32 value; \ - if (!CheckAndGetInteger(arg, &value, kint32min_py, kint32max_py)) { \ - return err; \ - } - -#define GOOGLE_CHECK_GET_INT64(arg, value, err) \ - int64 value; \ - if (!CheckAndGetInteger(arg, &value, kint64min_py, kint64max_py)) { \ - return err; \ - } - -#define GOOGLE_CHECK_GET_UINT32(arg, value, err) \ - uint32 value; \ - if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint32max_py)) { \ - return err; \ - } - -#define GOOGLE_CHECK_GET_UINT64(arg, value, err) \ - uint64 value; \ - if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint64max_py)) { \ - return err; \ - } - -#define GOOGLE_CHECK_GET_FLOAT(arg, value, err) \ - float value; \ - if (!CheckAndGetFloat(arg, &value)) { \ - return err; \ - } \ - -#define GOOGLE_CHECK_GET_DOUBLE(arg, value, err) \ - double value; \ - if (!CheckAndGetDouble(arg, &value)) { \ - return err; \ - } - -#define GOOGLE_CHECK_GET_BOOL(arg, value, err) \ - bool value; \ - if (!CheckAndGetBool(arg, &value)) { \ - return err; \ - } - - -extern PyObject* kPythonZero; -extern PyObject* kint32min_py; -extern PyObject* kint32max_py; -extern PyObject* kuint32max_py; -extern PyObject* kint64min_py; -extern PyObject* kint64max_py; -extern PyObject* kuint64max_py; - -#define FULL_MODULE_NAME "google.protobuf.pyext._message" - -void FormatTypeError(PyObject* arg, char* expected_types); -template<class T> -bool CheckAndGetInteger( - PyObject* arg, T* value, PyObject* min, PyObject* max); -bool CheckAndGetDouble(PyObject* arg, double* value); -bool CheckAndGetFloat(PyObject* arg, float* value); -bool CheckAndGetBool(PyObject* arg, bool* value); -PyObject* CheckString(PyObject* arg, const FieldDescriptor* descriptor); -bool CheckAndSetString( - PyObject* arg, Message* message, - const FieldDescriptor* descriptor, - const Reflection* reflection, - bool append, - int index); -PyObject* ToStringObject(const FieldDescriptor* descriptor, string value); - -// Check if the passed field descriptor belongs to the given message. -// If not, return false and set a Python exception (a KeyError) -bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor, - const Message* message); - -extern PyObject* PickleError_class; - -bool InitProto2MessageModule(PyObject *m); - -} // namespace python -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_H__ diff --git a/python/google/protobuf/pyext/message_module.cc b/python/google/protobuf/pyext/message_module.cc deleted file mode 100644 index d90d9de3..00000000 --- a/python/google/protobuf/pyext/message_module.cc +++ /dev/null @@ -1,88 +0,0 @@ -// 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. - -#include <google/protobuf/pyext/message.h> - -static const char module_docstring[] = -"python-proto2 is a module that can be used to enhance proto2 Python API\n" -"performance.\n" -"\n" -"It provides access to the protocol buffers C++ reflection API that\n" -"implements the basic protocol buffer functions."; - -static PyMethodDef ModuleMethods[] = { - {"SetAllowOversizeProtos", - (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos, - METH_O, "Enable/disable oversize proto parsing."}, - { NULL, NULL} -}; - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef _module = { - PyModuleDef_HEAD_INIT, - "_message", - module_docstring, - -1, - ModuleMethods, /* m_methods */ - NULL, - NULL, - NULL, - NULL -}; -#define INITFUNC PyInit__message -#define INITFUNC_ERRORVAL NULL -#else // Python 2 -#define INITFUNC init_message -#define INITFUNC_ERRORVAL -#endif - -extern "C" { - PyMODINIT_FUNC INITFUNC(void) { - PyObject* m; -#if PY_MAJOR_VERSION >= 3 - m = PyModule_Create(&_module); -#else - m = Py_InitModule3("_message", ModuleMethods, - module_docstring); -#endif - if (m == NULL) { - return INITFUNC_ERRORVAL; - } - - if (!google::protobuf::python::InitProto2MessageModule(m)) { - Py_DECREF(m); - return INITFUNC_ERRORVAL; - } - -#if PY_MAJOR_VERSION >= 3 - return m; -#endif - } -} diff --git a/python/google/protobuf/pyext/proto2_api_test.proto b/python/google/protobuf/pyext/proto2_api_test.proto deleted file mode 100644 index 18aecfb7..00000000 --- a/python/google/protobuf/pyext/proto2_api_test.proto +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -syntax = "proto2"; - -import "google/protobuf/internal/cpp/proto1_api_test.proto"; - -package google.protobuf.python.internal; - -message TestNestedProto1APIMessage { - optional int32 a = 1; - optional TestMessage.NestedMessage b = 2; -} diff --git a/python/google/protobuf/pyext/python.proto b/python/google/protobuf/pyext/python.proto deleted file mode 100644 index cce645d7..00000000 --- a/python/google/protobuf/pyext/python.proto +++ /dev/null @@ -1,68 +0,0 @@ -// 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. - -// Author: tibell@google.com (Johan Tibell) -// -// These message definitions are used to exercises known corner cases -// in the C++ implementation of the Python API. - -syntax = "proto2"; - -package google.protobuf.python.internal; - -// Protos optimized for SPEED use a strict superset of the generated code -// of equivalent ones optimized for CODE_SIZE, so we should optimize all our -// tests for speed unless explicitly testing code size optimization. -option optimize_for = SPEED; - -message TestAllTypes { - message NestedMessage { - optional int32 bb = 1; - optional ForeignMessage cc = 2; - } - - repeated NestedMessage repeated_nested_message = 1; - optional NestedMessage optional_nested_message = 2; - optional int32 optional_int32 = 3; -} - -message ForeignMessage { - optional int32 c = 1; - repeated int32 d = 2; -} - -message TestAllExtensions { - extensions 1 to max; -} - -extend TestAllExtensions { - optional TestAllTypes.NestedMessage optional_nested_message_extension = 1; - repeated TestAllTypes.NestedMessage repeated_nested_message_extension = 2; -} diff --git a/python/google/protobuf/pyext/python_protobuf.h b/python/google/protobuf/pyext/python_protobuf.h deleted file mode 100644 index beb6e460..00000000 --- a/python/google/protobuf/pyext/python_protobuf.h +++ /dev/null @@ -1,57 +0,0 @@ -// 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. - -// Author: qrczak@google.com (Marcin Kowalczyk) -// -// This module exposes the C proto inside the given Python proto, in -// case the Python proto is implemented with a C proto. - -#ifndef GOOGLE_PROTOBUF_PYTHON_PYTHON_PROTOBUF_H__ -#define GOOGLE_PROTOBUF_PYTHON_PYTHON_PROTOBUF_H__ - -#include <Python.h> - -namespace google { -namespace protobuf { - -class Message; - -namespace python { - -// Return the pointer to the C proto inside the given Python proto, -// or NULL when this is not a Python proto implemented with a C proto. -const Message* GetCProtoInsidePyProto(PyObject* msg); -Message* MutableCProtoInsidePyProto(PyObject* msg); - -} // namespace python -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_PYTHON_PYTHON_PROTOBUF_H__ diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc deleted file mode 100644 index 4f339e77..00000000 --- a/python/google/protobuf/pyext/repeated_composite_container.cc +++ /dev/null @@ -1,612 +0,0 @@ -// 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. - -// Author: anuraag@google.com (Anuraag Agrawal) -// Author: tibell@google.com (Johan Tibell) - -#include <google/protobuf/pyext/repeated_composite_container.h> - -#include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif - -#include <google/protobuf/stubs/logging.h> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/dynamic_message.h> -#include <google/protobuf/message.h> -#include <google/protobuf/pyext/descriptor.h> -#include <google/protobuf/pyext/descriptor_pool.h> -#include <google/protobuf/pyext/message.h> -#include <google/protobuf/pyext/scoped_pyobject_ptr.h> - -#if PY_MAJOR_VERSION >= 3 - #define PyInt_Check PyLong_Check - #define PyInt_AsLong PyLong_AsLong - #define PyInt_FromLong PyLong_FromLong -#endif - -namespace google { -namespace protobuf { -namespace python { - -namespace repeated_composite_container { - -// TODO(tibell): We might also want to check: -// GOOGLE_CHECK_NOTNULL((self)->owner.get()); -#define GOOGLE_CHECK_ATTACHED(self) \ - do { \ - GOOGLE_CHECK_NOTNULL((self)->message); \ - GOOGLE_CHECK_NOTNULL((self)->parent_field_descriptor); \ - } while (0); - -#define GOOGLE_CHECK_RELEASED(self) \ - do { \ - GOOGLE_CHECK((self)->owner.get() == NULL); \ - GOOGLE_CHECK((self)->message == NULL); \ - GOOGLE_CHECK((self)->parent_field_descriptor == NULL); \ - GOOGLE_CHECK((self)->parent == NULL); \ - } while (0); - -// --------------------------------------------------------------------- -// len() - -static Py_ssize_t Length(RepeatedCompositeContainer* self) { - Message* message = self->message; - if (message != NULL) { - return message->GetReflection()->FieldSize(*message, - self->parent_field_descriptor); - } else { - // The container has been released (i.e. by a call to Clear() or - // ClearField() on the parent) and thus there's no message. - return PyList_GET_SIZE(self->child_messages); - } -} - -// Returns 0 if successful; returns -1 and sets an exception if -// unsuccessful. -static int UpdateChildMessages(RepeatedCompositeContainer* self) { - if (self->message == NULL) - return 0; - - // A MergeFrom on a parent message could have caused extra messages to be - // added in the underlying protobuf so add them to our list. They can never - // be removed in such a way so there's no need to worry about that. - Py_ssize_t message_length = Length(self); - Py_ssize_t child_length = PyList_GET_SIZE(self->child_messages); - Message* message = self->message; - const Reflection* reflection = message->GetReflection(); - for (Py_ssize_t i = child_length; i < message_length; ++i) { - const Message& sub_message = reflection->GetRepeatedMessage( - *(self->message), self->parent_field_descriptor, i); - CMessage* cmsg = cmessage::NewEmptyMessage(self->child_message_class); - ScopedPyObjectPtr py_cmsg(reinterpret_cast<PyObject*>(cmsg)); - if (cmsg == NULL) { - return -1; - } - cmsg->owner = self->owner; - cmsg->message = const_cast<Message*>(&sub_message); - cmsg->parent = self->parent; - if (PyList_Append(self->child_messages, py_cmsg.get()) < 0) { - return -1; - } - } - return 0; -} - -// --------------------------------------------------------------------- -// add() - -static PyObject* AddToAttached(RepeatedCompositeContainer* self, - PyObject* args, - PyObject* kwargs) { - GOOGLE_CHECK_ATTACHED(self); - - if (UpdateChildMessages(self) < 0) { - return NULL; - } - if (cmessage::AssureWritable(self->parent) == -1) - return NULL; - Message* message = self->message; - Message* sub_message = - message->GetReflection()->AddMessage(message, - self->parent_field_descriptor); - CMessage* cmsg = cmessage::NewEmptyMessage(self->child_message_class); - if (cmsg == NULL) - return NULL; - - cmsg->owner = self->owner; - cmsg->message = sub_message; - cmsg->parent = self->parent; - if (cmessage::InitAttributes(cmsg, kwargs) < 0) { - Py_DECREF(cmsg); - return NULL; - } - - PyObject* py_cmsg = reinterpret_cast<PyObject*>(cmsg); - if (PyList_Append(self->child_messages, py_cmsg) < 0) { - Py_DECREF(py_cmsg); - return NULL; - } - return py_cmsg; -} - -static PyObject* AddToReleased(RepeatedCompositeContainer* self, - PyObject* args, - PyObject* kwargs) { - GOOGLE_CHECK_RELEASED(self); - - // Create a new Message detached from the rest. - PyObject* py_cmsg = PyEval_CallObjectWithKeywords( - self->child_message_class->AsPyObject(), NULL, kwargs); - if (py_cmsg == NULL) - return NULL; - - if (PyList_Append(self->child_messages, py_cmsg) < 0) { - Py_DECREF(py_cmsg); - return NULL; - } - return py_cmsg; -} - -PyObject* Add(RepeatedCompositeContainer* self, - PyObject* args, - PyObject* kwargs) { - if (self->message == NULL) - return AddToReleased(self, args, kwargs); - else - return AddToAttached(self, args, kwargs); -} - -// --------------------------------------------------------------------- -// extend() - -PyObject* Extend(RepeatedCompositeContainer* self, PyObject* value) { - cmessage::AssureWritable(self->parent); - if (UpdateChildMessages(self) < 0) { - return NULL; - } - ScopedPyObjectPtr iter(PyObject_GetIter(value)); - if (iter == NULL) { - PyErr_SetString(PyExc_TypeError, "Value must be iterable"); - return NULL; - } - ScopedPyObjectPtr next; - while ((next.reset(PyIter_Next(iter.get()))) != NULL) { - if (!PyObject_TypeCheck(next.get(), &CMessage_Type)) { - PyErr_SetString(PyExc_TypeError, "Not a cmessage"); - return NULL; - } - ScopedPyObjectPtr new_message(Add(self, NULL, NULL)); - if (new_message == NULL) { - return NULL; - } - CMessage* new_cmessage = reinterpret_cast<CMessage*>(new_message.get()); - if (ScopedPyObjectPtr(cmessage::MergeFrom(new_cmessage, next.get())) == - NULL) { - return NULL; - } - } - if (PyErr_Occurred()) { - return NULL; - } - Py_RETURN_NONE; -} - -PyObject* MergeFrom(RepeatedCompositeContainer* self, PyObject* other) { - if (UpdateChildMessages(self) < 0) { - return NULL; - } - return Extend(self, other); -} - -PyObject* Subscript(RepeatedCompositeContainer* self, PyObject* slice) { - if (UpdateChildMessages(self) < 0) { - return NULL; - } - // Just forward the call to the subscript-handling function of the - // list containing the child messages. - return PyObject_GetItem(self->child_messages, slice); -} - -int AssignSubscript(RepeatedCompositeContainer* self, - PyObject* slice, - PyObject* value) { - if (UpdateChildMessages(self) < 0) { - return -1; - } - if (value != NULL) { - PyErr_SetString(PyExc_TypeError, "does not support assignment"); - return -1; - } - - // Delete from the underlying Message, if any. - if (self->parent != NULL) { - if (cmessage::InternalDeleteRepeatedField(self->parent, - self->parent_field_descriptor, - slice, - self->child_messages) < 0) { - return -1; - } - } else { - Py_ssize_t from; - Py_ssize_t to; - Py_ssize_t step; - Py_ssize_t length = Length(self); - Py_ssize_t slicelength; - if (PySlice_Check(slice)) { -#if PY_MAJOR_VERSION >= 3 - if (PySlice_GetIndicesEx(slice, -#else - if (PySlice_GetIndicesEx(reinterpret_cast<PySliceObject*>(slice), -#endif - length, &from, &to, &step, &slicelength) == -1) { - return -1; - } - return PySequence_DelSlice(self->child_messages, from, to); - } else if (PyInt_Check(slice) || PyLong_Check(slice)) { - from = to = PyLong_AsLong(slice); - if (from < 0) { - from = to = length + from; - } - return PySequence_DelItem(self->child_messages, from); - } - } - - return 0; -} - -static PyObject* Remove(RepeatedCompositeContainer* self, PyObject* value) { - if (UpdateChildMessages(self) < 0) { - return NULL; - } - Py_ssize_t index = PySequence_Index(self->child_messages, value); - if (index == -1) { - return NULL; - } - ScopedPyObjectPtr py_index(PyLong_FromLong(index)); - if (AssignSubscript(self, py_index.get(), NULL) < 0) { - return NULL; - } - Py_RETURN_NONE; -} - -static PyObject* RichCompare(RepeatedCompositeContainer* self, - PyObject* other, - int opid) { - if (UpdateChildMessages(self) < 0) { - return NULL; - } - if (!PyObject_TypeCheck(other, &RepeatedCompositeContainer_Type)) { - PyErr_SetString(PyExc_TypeError, - "Can only compare repeated composite fields " - "against other repeated composite fields."); - return NULL; - } - if (opid == Py_EQ || opid == Py_NE) { - // TODO(anuraag): Don't make new lists just for this... - ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL)); - if (full_slice == NULL) { - return NULL; - } - ScopedPyObjectPtr list(Subscript(self, full_slice.get())); - if (list == NULL) { - return NULL; - } - ScopedPyObjectPtr other_list( - Subscript(reinterpret_cast<RepeatedCompositeContainer*>(other), - full_slice.get())); - if (other_list == NULL) { - return NULL; - } - return PyObject_RichCompare(list.get(), other_list.get(), opid); - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -// --------------------------------------------------------------------- -// sort() - -static void ReorderAttached(RepeatedCompositeContainer* self) { - Message* message = self->message; - const Reflection* reflection = message->GetReflection(); - const FieldDescriptor* descriptor = self->parent_field_descriptor; - const Py_ssize_t length = Length(self); - - // Since Python protobuf objects are never arena-allocated, adding and - // removing message pointers to the underlying array is just updating - // pointers. - for (Py_ssize_t i = 0; i < length; ++i) - reflection->ReleaseLast(message, descriptor); - - for (Py_ssize_t i = 0; i < length; ++i) { - CMessage* py_cmsg = reinterpret_cast<CMessage*>( - PyList_GET_ITEM(self->child_messages, i)); - reflection->AddAllocatedMessage(message, descriptor, py_cmsg->message); - } -} - -// Returns 0 if successful; returns -1 and sets an exception if -// unsuccessful. -static int SortPythonMessages(RepeatedCompositeContainer* self, - PyObject* args, - PyObject* kwds) { - ScopedPyObjectPtr m(PyObject_GetAttrString(self->child_messages, "sort")); - if (m == NULL) - return -1; - if (PyObject_Call(m.get(), args, kwds) == NULL) - return -1; - if (self->message != NULL) { - ReorderAttached(self); - } - return 0; -} - -static PyObject* Sort(RepeatedCompositeContainer* self, - PyObject* args, - PyObject* kwds) { - // Support the old sort_function argument for backwards - // compatibility. - if (kwds != NULL) { - PyObject* sort_func = PyDict_GetItemString(kwds, "sort_function"); - if (sort_func != NULL) { - // Must set before deleting as sort_func is a borrowed reference - // and kwds might be the only thing keeping it alive. - PyDict_SetItemString(kwds, "cmp", sort_func); - PyDict_DelItemString(kwds, "sort_function"); - } - } - - if (UpdateChildMessages(self) < 0) { - return NULL; - } - if (SortPythonMessages(self, args, kwds) < 0) { - return NULL; - } - Py_RETURN_NONE; -} - -// --------------------------------------------------------------------- - -static PyObject* Item(RepeatedCompositeContainer* self, Py_ssize_t index) { - if (UpdateChildMessages(self) < 0) { - return NULL; - } - Py_ssize_t length = Length(self); - if (index < 0) { - index = length + index; - } - PyObject* item = PyList_GetItem(self->child_messages, index); - if (item == NULL) { - return NULL; - } - Py_INCREF(item); - return item; -} - -static PyObject* Pop(RepeatedCompositeContainer* self, - PyObject* args) { - Py_ssize_t index = -1; - if (!PyArg_ParseTuple(args, "|n", &index)) { - return NULL; - } - PyObject* item = Item(self, index); - if (item == NULL) { - PyErr_Format(PyExc_IndexError, - "list index (%zd) out of range", - index); - return NULL; - } - ScopedPyObjectPtr py_index(PyLong_FromSsize_t(index)); - if (AssignSubscript(self, py_index.get(), NULL) < 0) { - return NULL; - } - return item; -} - -// Release field of parent message and transfer the ownership to target. -void ReleaseLastTo(CMessage* parent, - const FieldDescriptor* field, - CMessage* target) { - GOOGLE_CHECK_NOTNULL(parent); - GOOGLE_CHECK_NOTNULL(field); - GOOGLE_CHECK_NOTNULL(target); - - shared_ptr<Message> released_message( - parent->message->GetReflection()->ReleaseLast(parent->message, field)); - // TODO(tibell): Deal with proto1. - - target->parent = NULL; - target->parent_field_descriptor = NULL; - target->message = released_message.get(); - target->read_only = false; - cmessage::SetOwner(target, released_message); -} - -// Called to release a container using -// ClearField('container_field_name') on the parent. -int Release(RepeatedCompositeContainer* self) { - if (UpdateChildMessages(self) < 0) { - PyErr_WriteUnraisable(PyBytes_FromString("Failed to update released " - "messages")); - return -1; - } - - Message* message = self->message; - const FieldDescriptor* field = self->parent_field_descriptor; - - // The reflection API only lets us release the last message in a - // repeated field. Therefore we iterate through the children - // starting with the last one. - const Py_ssize_t size = PyList_GET_SIZE(self->child_messages); - GOOGLE_DCHECK_EQ(size, message->GetReflection()->FieldSize(*message, field)); - for (Py_ssize_t i = size - 1; i >= 0; --i) { - CMessage* child_cmessage = reinterpret_cast<CMessage*>( - PyList_GET_ITEM(self->child_messages, i)); - ReleaseLastTo(self->parent, field, child_cmessage); - } - - // Detach from containing message. - self->parent = NULL; - self->parent_field_descriptor = NULL; - self->message = NULL; - self->owner.reset(); - - return 0; -} - -int SetOwner(RepeatedCompositeContainer* self, - const shared_ptr<Message>& new_owner) { - GOOGLE_CHECK_ATTACHED(self); - - self->owner = new_owner; - const Py_ssize_t n = PyList_GET_SIZE(self->child_messages); - for (Py_ssize_t i = 0; i < n; ++i) { - PyObject* msg = PyList_GET_ITEM(self->child_messages, i); - if (cmessage::SetOwner(reinterpret_cast<CMessage*>(msg), new_owner) == -1) { - return -1; - } - } - return 0; -} - -// The private constructor of RepeatedCompositeContainer objects. -PyObject *NewContainer( - CMessage* parent, - const FieldDescriptor* parent_field_descriptor, - CMessageClass* concrete_class) { - if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) { - return NULL; - } - - RepeatedCompositeContainer* self = - reinterpret_cast<RepeatedCompositeContainer*>( - PyType_GenericAlloc(&RepeatedCompositeContainer_Type, 0)); - if (self == NULL) { - return NULL; - } - - self->message = parent->message; - self->parent = parent; - self->parent_field_descriptor = parent_field_descriptor; - self->owner = parent->owner; - Py_INCREF(concrete_class); - self->child_message_class = concrete_class; - self->child_messages = PyList_New(0); - - return reinterpret_cast<PyObject*>(self); -} - -static void Dealloc(RepeatedCompositeContainer* self) { - Py_CLEAR(self->child_messages); - Py_CLEAR(self->child_message_class); - // TODO(tibell): Do we need to call delete on these objects to make - // sure their destructors are called? - self->owner.reset(); - - Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); -} - -static PySequenceMethods SqMethods = { - (lenfunc)Length, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - (ssizeargfunc)Item /* sq_item */ -}; - -static PyMappingMethods MpMethods = { - (lenfunc)Length, /* mp_length */ - (binaryfunc)Subscript, /* mp_subscript */ - (objobjargproc)AssignSubscript,/* mp_ass_subscript */ -}; - -static PyMethodDef Methods[] = { - { "add", (PyCFunction) Add, METH_VARARGS | METH_KEYWORDS, - "Adds an object to the repeated container." }, - { "extend", (PyCFunction) Extend, METH_O, - "Adds objects to the repeated container." }, - { "pop", (PyCFunction)Pop, METH_VARARGS, - "Removes an object from the repeated container and returns it." }, - { "remove", (PyCFunction) Remove, METH_O, - "Removes an object from the repeated container." }, - { "sort", (PyCFunction) Sort, METH_VARARGS | METH_KEYWORDS, - "Sorts the repeated container." }, - { "MergeFrom", (PyCFunction) MergeFrom, METH_O, - "Adds objects to the repeated container." }, - { NULL, NULL } -}; - -} // namespace repeated_composite_container - -PyTypeObject RepeatedCompositeContainer_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".RepeatedCompositeContainer", // tp_name - sizeof(RepeatedCompositeContainer), // tp_basicsize - 0, // tp_itemsize - (destructor)repeated_composite_container::Dealloc, // tp_dealloc - 0, // tp_print - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_compare - 0, // tp_repr - 0, // tp_as_number - &repeated_composite_container::SqMethods, // tp_as_sequence - &repeated_composite_container::MpMethods, // tp_as_mapping - PyObject_HashNotImplemented, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "A Repeated scalar container", // tp_doc - 0, // tp_traverse - 0, // tp_clear - (richcmpfunc)repeated_composite_container::RichCompare, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - repeated_composite_container::Methods, // 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 -}; - -} // namespace python -} // namespace protobuf -} // namespace google diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h deleted file mode 100644 index a7b56b61..00000000 --- a/python/google/protobuf/pyext/repeated_composite_container.h +++ /dev/null @@ -1,179 +0,0 @@ -// 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. - -// Author: anuraag@google.com (Anuraag Agrawal) -// Author: tibell@google.com (Johan Tibell) - -#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_COMPOSITE_CONTAINER_H__ -#define GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_COMPOSITE_CONTAINER_H__ - -#include <Python.h> - -#include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif -#include <string> -#include <vector> - -namespace google { -namespace protobuf { - -class FieldDescriptor; -class Message; - -#ifdef _SHARED_PTR_H -using std::shared_ptr; -#else -using internal::shared_ptr; -#endif - -namespace python { - -struct CMessage; -struct CMessageClass; - -// A RepeatedCompositeContainer can be in one of two states: attached -// or released. -// -// When in the attached state all modifications to the container are -// done both on the 'message' and on the 'child_messages' -// list. In this state all Messages referred to by the children in -// 'child_messages' are owner by the 'owner'. -// -// When in the released state 'message', 'owner', 'parent', and -// 'parent_field_descriptor' are NULL. -typedef struct RepeatedCompositeContainer { - PyObject_HEAD; - - // This is the top-level C++ Message object that owns the whole - // proto tree. Every Python RepeatedCompositeContainer holds a - // reference to it in order to keep it alive as long as there's a - // Python object that references any part of the tree. - shared_ptr<Message> owner; - - // Weak reference to parent object. May be NULL. Used to make sure - // the parent is writable before modifying the - // RepeatedCompositeContainer. - CMessage* parent; - - // A descriptor used to modify the underlying 'message'. - // The pointer is owned by the global DescriptorPool. - const FieldDescriptor* parent_field_descriptor; - - // Pointer to the C++ Message that contains this container. The - // RepeatedCompositeContainer does not own this pointer. - // - // If NULL, this message has been released from its parent (by - // calling Clear() or ClearField() on the parent. - Message* message; - - // The type used to create new child messages. - CMessageClass* child_message_class; - - // A list of child messages. - PyObject* child_messages; -} RepeatedCompositeContainer; - -extern PyTypeObject RepeatedCompositeContainer_Type; - -namespace repeated_composite_container { - -// Builds a RepeatedCompositeContainer object, from a parent message and a -// field descriptor. -PyObject *NewContainer( - CMessage* parent, - const FieldDescriptor* parent_field_descriptor, - CMessageClass *child_message_class); - -// Appends a new CMessage to the container and returns it. The -// CMessage is initialized using the content of kwargs. -// -// Returns a new reference if successful; returns NULL and sets an -// exception if unsuccessful. -PyObject* Add(RepeatedCompositeContainer* self, - PyObject* args, - PyObject* kwargs); - -// Appends all the CMessages in the input iterator to the container. -// -// Returns None if successful; returns NULL and sets an exception if -// unsuccessful. -PyObject* Extend(RepeatedCompositeContainer* self, PyObject* value); - -// Appends a new message to the container for each message in the -// input iterator, merging each data element in. Equivalent to extend. -// -// Returns None if successful; returns NULL and sets an exception if -// unsuccessful. -PyObject* MergeFrom(RepeatedCompositeContainer* self, PyObject* other); - -// Accesses messages in the container. -// -// Returns a new reference to the message for an integer parameter. -// Returns a new reference to a list of messages for a slice. -PyObject* Subscript(RepeatedCompositeContainer* self, PyObject* slice); - -// Deletes items from the container (cannot be used for assignment). -// -// Returns 0 on success, -1 on failure. -int AssignSubscript(RepeatedCompositeContainer* self, - PyObject* slice, - PyObject* value); - -// Releases the messages in the container to the given message. -// -// Returns 0 on success, -1 on failure. -int ReleaseToMessage(RepeatedCompositeContainer* self, Message* new_message); - -// Releases the messages in the container to a new message. -// -// Returns 0 on success, -1 on failure. -int Release(RepeatedCompositeContainer* self); - -// Returns 0 on success, -1 on failure. -int SetOwner(RepeatedCompositeContainer* self, - const shared_ptr<Message>& new_owner); - -// Removes the last element of the repeated message field 'field' on -// the Message 'parent', and transfers the ownership of the released -// Message to 'target'. -// -// Corresponds to reflection api method ReleaseMessage. -void ReleaseLastTo(CMessage* parent, - const FieldDescriptor* field, - CMessage* target); - -} // namespace repeated_composite_container -} // namespace python -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_COMPOSITE_CONTAINER_H__ diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc deleted file mode 100644 index 95da85f8..00000000 --- a/python/google/protobuf/pyext/repeated_scalar_container.cc +++ /dev/null @@ -1,812 +0,0 @@ -// 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. - -// Author: anuraag@google.com (Anuraag Agrawal) -// Author: tibell@google.com (Johan Tibell) - -#include <google/protobuf/pyext/repeated_scalar_container.h> - -#include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif - -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/logging.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/dynamic_message.h> -#include <google/protobuf/message.h> -#include <google/protobuf/pyext/descriptor.h> -#include <google/protobuf/pyext/descriptor_pool.h> -#include <google/protobuf/pyext/message.h> -#include <google/protobuf/pyext/scoped_pyobject_ptr.h> - -#if PY_MAJOR_VERSION >= 3 - #define PyInt_FromLong PyLong_FromLong - #if PY_VERSION_HEX < 0x03030000 - #error "Python 3.0 - 3.2 are not supported." - #else - #define PyString_AsString(ob) \ - (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AsString(ob)) - #endif -#endif - -namespace google { -namespace protobuf { -namespace python { - -namespace repeated_scalar_container { - -static int InternalAssignRepeatedField( - RepeatedScalarContainer* self, PyObject* list) { - self->message->GetReflection()->ClearField(self->message, - self->parent_field_descriptor); - for (Py_ssize_t i = 0; i < PyList_GET_SIZE(list); ++i) { - PyObject* value = PyList_GET_ITEM(list, i); - if (ScopedPyObjectPtr(Append(self, value)) == NULL) { - return -1; - } - } - return 0; -} - -static Py_ssize_t Len(RepeatedScalarContainer* self) { - Message* message = self->message; - return message->GetReflection()->FieldSize(*message, - self->parent_field_descriptor); -} - -static int AssignItem(RepeatedScalarContainer* self, - Py_ssize_t index, - PyObject* arg) { - cmessage::AssureWritable(self->parent); - Message* message = self->message; - const FieldDescriptor* field_descriptor = self->parent_field_descriptor; - - const Reflection* reflection = message->GetReflection(); - int field_size = reflection->FieldSize(*message, field_descriptor); - if (index < 0) { - index = field_size + index; - } - if (index < 0 || index >= field_size) { - PyErr_Format(PyExc_IndexError, - "list assignment index (%d) out of range", - static_cast<int>(index)); - return -1; - } - - if (arg == NULL) { - ScopedPyObjectPtr py_index(PyLong_FromLong(index)); - return cmessage::InternalDeleteRepeatedField(self->parent, field_descriptor, - py_index.get(), NULL); - } - - if (PySequence_Check(arg) && !(PyBytes_Check(arg) || PyUnicode_Check(arg))) { - PyErr_SetString(PyExc_TypeError, "Value must be scalar"); - return -1; - } - - switch (field_descriptor->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: { - GOOGLE_CHECK_GET_INT32(arg, value, -1); - reflection->SetRepeatedInt32(message, field_descriptor, index, value); - break; - } - case FieldDescriptor::CPPTYPE_INT64: { - GOOGLE_CHECK_GET_INT64(arg, value, -1); - reflection->SetRepeatedInt64(message, field_descriptor, index, value); - break; - } - case FieldDescriptor::CPPTYPE_UINT32: { - GOOGLE_CHECK_GET_UINT32(arg, value, -1); - reflection->SetRepeatedUInt32(message, field_descriptor, index, value); - break; - } - case FieldDescriptor::CPPTYPE_UINT64: { - GOOGLE_CHECK_GET_UINT64(arg, value, -1); - reflection->SetRepeatedUInt64(message, field_descriptor, index, value); - break; - } - case FieldDescriptor::CPPTYPE_FLOAT: { - GOOGLE_CHECK_GET_FLOAT(arg, value, -1); - reflection->SetRepeatedFloat(message, field_descriptor, index, value); - break; - } - case FieldDescriptor::CPPTYPE_DOUBLE: { - GOOGLE_CHECK_GET_DOUBLE(arg, value, -1); - reflection->SetRepeatedDouble(message, field_descriptor, index, value); - break; - } - case FieldDescriptor::CPPTYPE_BOOL: { - GOOGLE_CHECK_GET_BOOL(arg, value, -1); - reflection->SetRepeatedBool(message, field_descriptor, index, value); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - if (!CheckAndSetString( - arg, message, field_descriptor, reflection, false, index)) { - return -1; - } - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - GOOGLE_CHECK_GET_INT32(arg, value, -1); - if (reflection->SupportsUnknownEnumValues()) { - reflection->SetRepeatedEnumValue(message, field_descriptor, index, - value); - } else { - const EnumDescriptor* enum_descriptor = field_descriptor->enum_type(); - const EnumValueDescriptor* enum_value = - enum_descriptor->FindValueByNumber(value); - if (enum_value != NULL) { - reflection->SetRepeatedEnum(message, field_descriptor, index, - enum_value); - } else { - ScopedPyObjectPtr s(PyObject_Str(arg)); - if (s != NULL) { - PyErr_Format(PyExc_ValueError, "Unknown enum value: %s", - PyString_AsString(s.get())); - } - return -1; - } - } - break; - } - default: - PyErr_Format( - PyExc_SystemError, "Adding value to a field of unknown type %d", - field_descriptor->cpp_type()); - return -1; - } - return 0; -} - -static PyObject* Item(RepeatedScalarContainer* self, Py_ssize_t index) { - Message* message = self->message; - const FieldDescriptor* field_descriptor = self->parent_field_descriptor; - const Reflection* reflection = message->GetReflection(); - - int field_size = reflection->FieldSize(*message, field_descriptor); - if (index < 0) { - index = field_size + index; - } - if (index < 0 || index >= field_size) { - PyErr_Format(PyExc_IndexError, - "list index (%zd) out of range", - index); - return NULL; - } - - PyObject* result = NULL; - switch (field_descriptor->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: { - int32 value = reflection->GetRepeatedInt32( - *message, field_descriptor, index); - result = PyInt_FromLong(value); - break; - } - case FieldDescriptor::CPPTYPE_INT64: { - int64 value = reflection->GetRepeatedInt64( - *message, field_descriptor, index); - result = PyLong_FromLongLong(value); - break; - } - case FieldDescriptor::CPPTYPE_UINT32: { - uint32 value = reflection->GetRepeatedUInt32( - *message, field_descriptor, index); - result = PyLong_FromLongLong(value); - break; - } - case FieldDescriptor::CPPTYPE_UINT64: { - uint64 value = reflection->GetRepeatedUInt64( - *message, field_descriptor, index); - result = PyLong_FromUnsignedLongLong(value); - break; - } - case FieldDescriptor::CPPTYPE_FLOAT: { - float value = reflection->GetRepeatedFloat( - *message, field_descriptor, index); - result = PyFloat_FromDouble(value); - break; - } - case FieldDescriptor::CPPTYPE_DOUBLE: { - double value = reflection->GetRepeatedDouble( - *message, field_descriptor, index); - result = PyFloat_FromDouble(value); - break; - } - case FieldDescriptor::CPPTYPE_BOOL: { - bool value = reflection->GetRepeatedBool( - *message, field_descriptor, index); - result = PyBool_FromLong(value ? 1 : 0); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - const EnumValueDescriptor* enum_value = - message->GetReflection()->GetRepeatedEnum( - *message, field_descriptor, index); - result = PyInt_FromLong(enum_value->number()); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - string value = reflection->GetRepeatedString( - *message, field_descriptor, index); - result = ToStringObject(field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_MESSAGE: { - PyObject* py_cmsg = PyObject_CallObject(reinterpret_cast<PyObject*>( - &CMessage_Type), NULL); - if (py_cmsg == NULL) { - return NULL; - } - CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg); - const Message& msg = reflection->GetRepeatedMessage( - *message, field_descriptor, index); - cmsg->owner = self->owner; - cmsg->parent = self->parent; - cmsg->message = const_cast<Message*>(&msg); - cmsg->read_only = false; - result = reinterpret_cast<PyObject*>(py_cmsg); - break; - } - default: - PyErr_Format( - PyExc_SystemError, - "Getting value from a repeated field of unknown type %d", - field_descriptor->cpp_type()); - } - - return result; -} - -static PyObject* Subscript(RepeatedScalarContainer* self, PyObject* slice) { - Py_ssize_t from; - Py_ssize_t to; - Py_ssize_t step; - Py_ssize_t length; - Py_ssize_t slicelength; - bool return_list = false; -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(slice)) { - from = to = PyInt_AsLong(slice); - } else // NOLINT -#endif - if (PyLong_Check(slice)) { - from = to = PyLong_AsLong(slice); - } else if (PySlice_Check(slice)) { - length = Len(self); -#if PY_MAJOR_VERSION >= 3 - if (PySlice_GetIndicesEx(slice, -#else - if (PySlice_GetIndicesEx(reinterpret_cast<PySliceObject*>(slice), -#endif - length, &from, &to, &step, &slicelength) == -1) { - return NULL; - } - return_list = true; - } else { - PyErr_SetString(PyExc_TypeError, "list indices must be integers"); - return NULL; - } - - if (!return_list) { - return Item(self, from); - } - - PyObject* list = PyList_New(0); - if (list == NULL) { - return NULL; - } - if (from <= to) { - if (step < 0) { - return list; - } - for (Py_ssize_t index = from; index < to; index += step) { - if (index < 0 || index >= length) { - break; - } - ScopedPyObjectPtr s(Item(self, index)); - PyList_Append(list, s.get()); - } - } else { - if (step > 0) { - return list; - } - for (Py_ssize_t index = from; index > to; index += step) { - if (index < 0 || index >= length) { - break; - } - ScopedPyObjectPtr s(Item(self, index)); - PyList_Append(list, s.get()); - } - } - return list; -} - -PyObject* Append(RepeatedScalarContainer* self, PyObject* item) { - cmessage::AssureWritable(self->parent); - Message* message = self->message; - const FieldDescriptor* field_descriptor = self->parent_field_descriptor; - - const Reflection* reflection = message->GetReflection(); - switch (field_descriptor->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: { - GOOGLE_CHECK_GET_INT32(item, value, NULL); - reflection->AddInt32(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_INT64: { - GOOGLE_CHECK_GET_INT64(item, value, NULL); - reflection->AddInt64(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_UINT32: { - GOOGLE_CHECK_GET_UINT32(item, value, NULL); - reflection->AddUInt32(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_UINT64: { - GOOGLE_CHECK_GET_UINT64(item, value, NULL); - reflection->AddUInt64(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_FLOAT: { - GOOGLE_CHECK_GET_FLOAT(item, value, NULL); - reflection->AddFloat(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_DOUBLE: { - GOOGLE_CHECK_GET_DOUBLE(item, value, NULL); - reflection->AddDouble(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_BOOL: { - GOOGLE_CHECK_GET_BOOL(item, value, NULL); - reflection->AddBool(message, field_descriptor, value); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - if (!CheckAndSetString( - item, message, field_descriptor, reflection, true, -1)) { - return NULL; - } - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - GOOGLE_CHECK_GET_INT32(item, value, NULL); - if (reflection->SupportsUnknownEnumValues()) { - reflection->AddEnumValue(message, field_descriptor, value); - } else { - const EnumDescriptor* enum_descriptor = field_descriptor->enum_type(); - const EnumValueDescriptor* enum_value = - enum_descriptor->FindValueByNumber(value); - if (enum_value != NULL) { - reflection->AddEnum(message, field_descriptor, enum_value); - } else { - ScopedPyObjectPtr s(PyObject_Str(item)); - if (s != NULL) { - PyErr_Format(PyExc_ValueError, "Unknown enum value: %s", - PyString_AsString(s.get())); - } - return NULL; - } - } - break; - } - default: - PyErr_Format( - PyExc_SystemError, "Adding value to a field of unknown type %d", - field_descriptor->cpp_type()); - return NULL; - } - - Py_RETURN_NONE; -} - -static int AssSubscript(RepeatedScalarContainer* self, - PyObject* slice, - PyObject* value) { - Py_ssize_t from; - Py_ssize_t to; - Py_ssize_t step; - Py_ssize_t length; - Py_ssize_t slicelength; - bool create_list = false; - - cmessage::AssureWritable(self->parent); - Message* message = self->message; - const FieldDescriptor* field_descriptor = - self->parent_field_descriptor; - -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(slice)) { - from = to = PyInt_AsLong(slice); - } else -#endif - if (PyLong_Check(slice)) { - from = to = PyLong_AsLong(slice); - } else if (PySlice_Check(slice)) { - const Reflection* reflection = message->GetReflection(); - length = reflection->FieldSize(*message, field_descriptor); -#if PY_MAJOR_VERSION >= 3 - if (PySlice_GetIndicesEx(slice, -#else - if (PySlice_GetIndicesEx(reinterpret_cast<PySliceObject*>(slice), -#endif - length, &from, &to, &step, &slicelength) == -1) { - return -1; - } - create_list = true; - } else { - PyErr_SetString(PyExc_TypeError, "list indices must be integers"); - return -1; - } - - if (value == NULL) { - return cmessage::InternalDeleteRepeatedField( - self->parent, field_descriptor, slice, NULL); - } - - if (!create_list) { - return AssignItem(self, from, value); - } - - ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL)); - if (full_slice == NULL) { - return -1; - } - ScopedPyObjectPtr new_list(Subscript(self, full_slice.get())); - if (new_list == NULL) { - return -1; - } - if (PySequence_SetSlice(new_list.get(), from, to, value) < 0) { - return -1; - } - - return InternalAssignRepeatedField(self, new_list.get()); -} - -PyObject* Extend(RepeatedScalarContainer* self, PyObject* value) { - cmessage::AssureWritable(self->parent); - - // TODO(ptucker): Deprecate this behavior. b/18413862 - if (value == Py_None) { - Py_RETURN_NONE; - } - if ((Py_TYPE(value)->tp_as_sequence == NULL) && PyObject_Not(value)) { - Py_RETURN_NONE; - } - - ScopedPyObjectPtr iter(PyObject_GetIter(value)); - if (iter == NULL) { - PyErr_SetString(PyExc_TypeError, "Value must be iterable"); - return NULL; - } - ScopedPyObjectPtr next; - while ((next.reset(PyIter_Next(iter.get()))) != NULL) { - if (ScopedPyObjectPtr(Append(self, next.get())) == NULL) { - return NULL; - } - } - if (PyErr_Occurred()) { - return NULL; - } - Py_RETURN_NONE; -} - -static PyObject* Insert(RepeatedScalarContainer* self, PyObject* args) { - Py_ssize_t index; - PyObject* value; - if (!PyArg_ParseTuple(args, "lO", &index, &value)) { - return NULL; - } - ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL)); - ScopedPyObjectPtr new_list(Subscript(self, full_slice.get())); - if (PyList_Insert(new_list.get(), index, value) < 0) { - return NULL; - } - int ret = InternalAssignRepeatedField(self, new_list.get()); - if (ret < 0) { - return NULL; - } - Py_RETURN_NONE; -} - -static PyObject* Remove(RepeatedScalarContainer* self, PyObject* value) { - Py_ssize_t match_index = -1; - for (Py_ssize_t i = 0; i < Len(self); ++i) { - ScopedPyObjectPtr elem(Item(self, i)); - if (PyObject_RichCompareBool(elem.get(), value, Py_EQ)) { - match_index = i; - break; - } - } - if (match_index == -1) { - PyErr_SetString(PyExc_ValueError, "remove(x): x not in container"); - return NULL; - } - if (AssignItem(self, match_index, NULL) < 0) { - return NULL; - } - Py_RETURN_NONE; -} - -static PyObject* RichCompare(RepeatedScalarContainer* self, - PyObject* other, - int opid) { - if (opid != Py_EQ && opid != Py_NE) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Copy the contents of this repeated scalar container, and other if it is - // also a repeated scalar container, into Python lists so we can delegate - // to the list's compare method. - - ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL)); - if (full_slice == NULL) { - return NULL; - } - - ScopedPyObjectPtr other_list_deleter; - if (PyObject_TypeCheck(other, &RepeatedScalarContainer_Type)) { - other_list_deleter.reset(Subscript( - reinterpret_cast<RepeatedScalarContainer*>(other), full_slice.get())); - other = other_list_deleter.get(); - } - - ScopedPyObjectPtr list(Subscript(self, full_slice.get())); - if (list == NULL) { - return NULL; - } - return PyObject_RichCompare(list.get(), other, opid); -} - -PyObject* Reduce(RepeatedScalarContainer* unused_self) { - PyErr_Format( - PickleError_class, - "can't pickle repeated message fields, convert to list first"); - return NULL; -} - -static PyObject* Sort(RepeatedScalarContainer* self, - PyObject* args, - PyObject* kwds) { - // Support the old sort_function argument for backwards - // compatibility. - if (kwds != NULL) { - PyObject* sort_func = PyDict_GetItemString(kwds, "sort_function"); - if (sort_func != NULL) { - // Must set before deleting as sort_func is a borrowed reference - // and kwds might be the only thing keeping it alive. - if (PyDict_SetItemString(kwds, "cmp", sort_func) == -1) - return NULL; - if (PyDict_DelItemString(kwds, "sort_function") == -1) - return NULL; - } - } - - ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL)); - if (full_slice == NULL) { - return NULL; - } - ScopedPyObjectPtr list(Subscript(self, full_slice.get())); - if (list == NULL) { - return NULL; - } - ScopedPyObjectPtr m(PyObject_GetAttrString(list.get(), "sort")); - if (m == NULL) { - return NULL; - } - ScopedPyObjectPtr res(PyObject_Call(m.get(), args, kwds)); - if (res == NULL) { - return NULL; - } - int ret = InternalAssignRepeatedField(self, list.get()); - if (ret < 0) { - return NULL; - } - Py_RETURN_NONE; -} - -static PyObject* Pop(RepeatedScalarContainer* self, - PyObject* args) { - Py_ssize_t index = -1; - if (!PyArg_ParseTuple(args, "|n", &index)) { - return NULL; - } - PyObject* item = Item(self, index); - if (item == NULL) { - PyErr_Format(PyExc_IndexError, - "list index (%zd) out of range", - index); - return NULL; - } - if (AssignItem(self, index, NULL) < 0) { - return NULL; - } - return item; -} - -// The private constructor of RepeatedScalarContainer objects. -PyObject *NewContainer( - CMessage* parent, const FieldDescriptor* parent_field_descriptor) { - if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) { - return NULL; - } - - RepeatedScalarContainer* self = reinterpret_cast<RepeatedScalarContainer*>( - PyType_GenericAlloc(&RepeatedScalarContainer_Type, 0)); - if (self == NULL) { - return NULL; - } - - self->message = parent->message; - self->parent = parent; - self->parent_field_descriptor = parent_field_descriptor; - self->owner = parent->owner; - - return reinterpret_cast<PyObject*>(self); -} - -// Initializes the underlying Message object of "to" so it becomes a new parent -// repeated scalar, and copies all the values from "from" to it. A child scalar -// container can be released by passing it as both from and to (e.g. making it -// the recipient of the new parent message and copying the values from itself). -static int InitializeAndCopyToParentContainer( - RepeatedScalarContainer* from, - RepeatedScalarContainer* to) { - ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL)); - if (full_slice == NULL) { - return -1; - } - ScopedPyObjectPtr values(Subscript(from, full_slice.get())); - if (values == NULL) { - return -1; - } - Message* new_message = from->message->New(); - to->parent = NULL; - to->parent_field_descriptor = from->parent_field_descriptor; - to->message = new_message; - to->owner.reset(new_message); - if (InternalAssignRepeatedField(to, values.get()) < 0) { - return -1; - } - return 0; -} - -int Release(RepeatedScalarContainer* self) { - return InitializeAndCopyToParentContainer(self, self); -} - -PyObject* DeepCopy(RepeatedScalarContainer* self, PyObject* arg) { - RepeatedScalarContainer* clone = reinterpret_cast<RepeatedScalarContainer*>( - PyType_GenericAlloc(&RepeatedScalarContainer_Type, 0)); - if (clone == NULL) { - return NULL; - } - - if (InitializeAndCopyToParentContainer(self, clone) < 0) { - Py_DECREF(clone); - return NULL; - } - return reinterpret_cast<PyObject*>(clone); -} - -static void Dealloc(RepeatedScalarContainer* self) { - self->owner.reset(); - Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); -} - -void SetOwner(RepeatedScalarContainer* self, - const shared_ptr<Message>& new_owner) { - self->owner = new_owner; -} - -static PySequenceMethods SqMethods = { - (lenfunc)Len, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - (ssizeargfunc)Item, /* sq_item */ - 0, /* sq_slice */ - (ssizeobjargproc)AssignItem /* sq_ass_item */ -}; - -static PyMappingMethods MpMethods = { - (lenfunc)Len, /* mp_length */ - (binaryfunc)Subscript, /* mp_subscript */ - (objobjargproc)AssSubscript, /* mp_ass_subscript */ -}; - -static PyMethodDef Methods[] = { - { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS, - "Makes a deep copy of the class." }, - { "__reduce__", (PyCFunction)Reduce, METH_NOARGS, - "Outputs picklable representation of the repeated field." }, - { "append", (PyCFunction)Append, METH_O, - "Appends an object to the repeated container." }, - { "extend", (PyCFunction)Extend, METH_O, - "Appends objects to the repeated container." }, - { "insert", (PyCFunction)Insert, METH_VARARGS, - "Appends objects to the repeated container." }, - { "pop", (PyCFunction)Pop, METH_VARARGS, - "Removes an object from the repeated container and returns it." }, - { "remove", (PyCFunction)Remove, METH_O, - "Removes an object from the repeated container." }, - { "sort", (PyCFunction)Sort, METH_VARARGS | METH_KEYWORDS, - "Sorts the repeated container."}, - { NULL, NULL } -}; - -} // namespace repeated_scalar_container - -PyTypeObject RepeatedScalarContainer_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - FULL_MODULE_NAME ".RepeatedScalarContainer", // tp_name - sizeof(RepeatedScalarContainer), // tp_basicsize - 0, // tp_itemsize - (destructor)repeated_scalar_container::Dealloc, // tp_dealloc - 0, // tp_print - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_compare - 0, // tp_repr - 0, // tp_as_number - &repeated_scalar_container::SqMethods, // tp_as_sequence - &repeated_scalar_container::MpMethods, // tp_as_mapping - PyObject_HashNotImplemented, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "A Repeated scalar container", // tp_doc - 0, // tp_traverse - 0, // tp_clear - (richcmpfunc)repeated_scalar_container::RichCompare, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - repeated_scalar_container::Methods, // 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 -}; - -} // namespace python -} // namespace protobuf -} // namespace google diff --git a/python/google/protobuf/pyext/repeated_scalar_container.h b/python/google/protobuf/pyext/repeated_scalar_container.h deleted file mode 100644 index 555e621c..00000000 --- a/python/google/protobuf/pyext/repeated_scalar_container.h +++ /dev/null @@ -1,122 +0,0 @@ -// 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. - -// Author: anuraag@google.com (Anuraag Agrawal) -// Author: tibell@google.com (Johan Tibell) - -#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_SCALAR_CONTAINER_H__ -#define GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_SCALAR_CONTAINER_H__ - -#include <Python.h> - -#include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif - -#include <google/protobuf/descriptor.h> - -namespace google { -namespace protobuf { - -class Message; - -#ifdef _SHARED_PTR_H -using std::shared_ptr; -#else -using internal::shared_ptr; -#endif - -namespace python { - -struct CMessage; - -typedef struct RepeatedScalarContainer { - PyObject_HEAD; - - // This is the top-level C++ Message object that owns the whole - // proto tree. Every Python RepeatedScalarContainer holds a - // reference to it in order to keep it alive as long as there's a - // Python object that references any part of the tree. - shared_ptr<Message> owner; - - // Pointer to the C++ Message that contains this container. The - // RepeatedScalarContainer does not own this pointer. - Message* message; - - // Weak reference to a parent CMessage object (i.e. may be NULL.) - // - // Used to make sure all ancestors are also mutable when first - // modifying the container. - CMessage* parent; - - // Pointer to the parent's descriptor that describes this - // field. Used together with the parent's message when making a - // default message instance mutable. - // The pointer is owned by the global DescriptorPool. - const FieldDescriptor* parent_field_descriptor; -} RepeatedScalarContainer; - -extern PyTypeObject RepeatedScalarContainer_Type; - -namespace repeated_scalar_container { - -// Builds a RepeatedScalarContainer object, from a parent message and a -// field descriptor. -extern PyObject *NewContainer( - CMessage* parent, const FieldDescriptor* parent_field_descriptor); - -// Appends the scalar 'item' to the end of the container 'self'. -// -// Returns None if successful; returns NULL and sets an exception if -// unsuccessful. -PyObject* Append(RepeatedScalarContainer* self, PyObject* item); - -// Releases the messages in the container to a new message. -// -// Returns 0 on success, -1 on failure. -int Release(RepeatedScalarContainer* self); - -// Appends all the elements in the input iterator to the container. -// -// Returns None if successful; returns NULL and sets an exception if -// unsuccessful. -PyObject* Extend(RepeatedScalarContainer* self, PyObject* value); - -// Set the owner field of self and any children of self. -void SetOwner(RepeatedScalarContainer* self, - const shared_ptr<Message>& new_owner); - -} // namespace repeated_scalar_container -} // namespace python -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_SCALAR_CONTAINER_H__ diff --git a/python/google/protobuf/pyext/scoped_pyobject_ptr.h b/python/google/protobuf/pyext/scoped_pyobject_ptr.h deleted file mode 100644 index a128cd4c..00000000 --- a/python/google/protobuf/pyext/scoped_pyobject_ptr.h +++ /dev/null @@ -1,96 +0,0 @@ -// 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. - -// Author: tibell@google.com (Johan Tibell) - -#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__ -#define GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__ - -#include <google/protobuf/stubs/common.h> - -#include <Python.h> - -namespace google { -class ScopedPyObjectPtr { - public: - // Constructor. Defaults to initializing with NULL. - // There is no way to create an uninitialized ScopedPyObjectPtr. - explicit ScopedPyObjectPtr(PyObject* p = NULL) : ptr_(p) { } - - // Destructor. If there is a PyObject object, delete it. - ~ScopedPyObjectPtr() { - Py_XDECREF(ptr_); - } - - // Reset. Deletes the current owned object, if any. - // Then takes ownership of a new object, if given. - // This function must be called with a reference that you own. - // this->reset(this->get()) is wrong! - // this->reset(this->release()) is OK. - PyObject* reset(PyObject* p = NULL) { - Py_XDECREF(ptr_); - ptr_ = p; - return ptr_; - } - - // Releases ownership of the object. - // The caller now owns the returned reference. - PyObject* release() { - PyObject* p = ptr_; - ptr_ = NULL; - return p; - } - - PyObject* operator->() const { - assert(ptr_ != NULL); - return ptr_; - } - - PyObject* get() const { return ptr_; } - - Py_ssize_t refcnt() const { return Py_REFCNT(ptr_); } - - void inc() const { Py_INCREF(ptr_); } - - // Comparison operators. - // These return whether a ScopedPyObjectPtr and a raw pointer - // refer to the same object, not just to two different but equal - // objects. - bool operator==(const PyObject* p) const { return ptr_ == p; } - bool operator!=(const PyObject* p) const { return ptr_ != p; } - - private: - PyObject* ptr_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ScopedPyObjectPtr); -}; - -} // namespace google -#endif // GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__ |