root/third_party/protobuf/python/google/protobuf/pyext/python-proto2.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. AddConstants
  2. FormatTypeError
  3. CheckAndGetInteger
  4. CheckAndGetDouble
  5. CheckAndGetFloat
  6. CheckAndGetBool
  7. CreateMessage
  8. ReleaseSubMessage
  9. CheckAndSetString
  10. ToStringObject
  11. AssureWritable
  12. InternalGetScalar
  13. InternalSetScalar
  14. InternalAddRepeatedScalar
  15. InternalGetRepeatedScalar
  16. InternalGetRepeatedScalarSlice
  17. CMessageInit
  18. CMessageDealloc
  19. CMessage_Clear
  20. CMessage_IsInitialized
  21. CMessage_HasField
  22. CMessage_HasFieldByDescriptor
  23. CMessage_ClearFieldByDescriptor
  24. CMessage_ClearField
  25. CMessage_GetScalar
  26. CMessage_GetRepeatedScalar
  27. CMessage_AssignRepeatedScalar
  28. CMessage_DeleteRepeatedField
  29. CMessage_SetScalar
  30. CMessage_AddRepeatedScalar
  31. CMessage_FieldLength
  32. CMessage_DebugString
  33. CMessage_SerializeToString
  34. CMessage_SerializePartialToString
  35. CMessageStr
  36. CMessage_MergeFrom
  37. CMessage_CopyFrom
  38. CMessage_MergeFromString
  39. CMessage_ByteSize
  40. CMessage_SetInParent
  41. CMessage_SwapRepeatedFieldElements
  42. CMessage_AddMessage
  43. CMessage_GetRepeatedMessage
  44. CMessage_NewSubMessage
  45. CMessage_MutableMessage
  46. CMessage_Equals
  47. CMessage_ListFields
  48. CMessage_FindInitializationErrors
  49. Python_NewCMessage
  50. GetCProtoInsidePyProtoImpl
  51. MutableCProtoInsidePyProtoImpl
  52. init_net_proto2___python

// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// http://code.google.com/p/protobuf/
//
// 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 <map>
#include <string>
#include <vector>

#include <google/protobuf/stubs/common.h>
#include <google/protobuf/pyext/python_descriptor.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/message.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/pyext/python_protobuf.h>

/* Is 64bit */
#define IS_64BIT (SIZEOF_LONG == 8)

#define FIELD_BELONGS_TO_MESSAGE(field_descriptor, message) \
    ((message)->GetDescriptor() == (field_descriptor)->containing_type())

#define FIELD_IS_REPEATED(field_descriptor)                 \
    ((field_descriptor)->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED)

#define GOOGLE_CHECK_GET_INT32(arg, value)                         \
    int32 value;                                            \
    if (!CheckAndGetInteger(arg, &value, kint32min_py, kint32max_py)) { \
      return NULL;                                          \
    }

#define GOOGLE_CHECK_GET_INT64(arg, value)                         \
    int64 value;                                            \
    if (!CheckAndGetInteger(arg, &value, kint64min_py, kint64max_py)) { \
      return NULL;                                          \
    }

#define GOOGLE_CHECK_GET_UINT32(arg, value)                        \
    uint32 value;                                           \
    if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint32max_py)) { \
      return NULL;                                          \
    }

#define GOOGLE_CHECK_GET_UINT64(arg, value)                        \
    uint64 value;                                           \
    if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint64max_py)) { \
      return NULL;                                          \
    }

#define GOOGLE_CHECK_GET_FLOAT(arg, value)                         \
    float value;                                            \
    if (!CheckAndGetFloat(arg, &value)) {                   \
      return NULL;                                          \
    }                                                       \

#define GOOGLE_CHECK_GET_DOUBLE(arg, value)                        \
    double value;                                           \
    if (!CheckAndGetDouble(arg, &value)) {                  \
      return NULL;                                          \
    }

#define GOOGLE_CHECK_GET_BOOL(arg, value)                          \
    bool value;                                             \
    if (!CheckAndGetBool(arg, &value)) {                    \
      return NULL;                                          \
    }

#define C(str) const_cast<char*>(str)

// --- Globals:

// Constants used for integer type range checking.
static PyObject* kPythonZero;
static PyObject* kint32min_py;
static PyObject* kint32max_py;
static PyObject* kuint32max_py;
static PyObject* kint64min_py;
static PyObject* kint64max_py;
static PyObject* kuint64max_py;

namespace google {
namespace protobuf {
namespace python {

// --- Support Routines:

static void AddConstants(PyObject* module) {
  struct NameValue {
    char* name;
    int32 value;
  } constants[] = {
    // Labels:
    {"LABEL_OPTIONAL", google::protobuf::FieldDescriptor::LABEL_OPTIONAL},
    {"LABEL_REQUIRED", google::protobuf::FieldDescriptor::LABEL_REQUIRED},
    {"LABEL_REPEATED", google::protobuf::FieldDescriptor::LABEL_REPEATED},
    // CPP types:
    {"CPPTYPE_MESSAGE", google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE},
    // Field Types:
    {"TYPE_MESSAGE", google::protobuf::FieldDescriptor::TYPE_MESSAGE},
    // End.
    {NULL, 0}
  };

  for (NameValue* constant = constants;
       constant->name != NULL; constant++) {
    PyModule_AddIntConstant(module, constant->name, constant->value);
  }
}

// --- CMessage Custom Type:

// ------ Type Forward Declaration:

struct CMessage;
struct CMessage_Type;

static void CMessageDealloc(CMessage* self);
static int CMessageInit(CMessage* self, PyObject *args, PyObject *kwds);
static PyObject* CMessageStr(CMessage* self);

static PyObject* CMessage_AddMessage(CMessage* self, PyObject* args);
static PyObject* CMessage_AddRepeatedScalar(CMessage* self, PyObject* args);
static PyObject* CMessage_AssignRepeatedScalar(CMessage* self, PyObject* args);
static PyObject* CMessage_ByteSize(CMessage* self, PyObject* args);
static PyObject* CMessage_Clear(CMessage* self, PyObject* args);
static PyObject* CMessage_ClearField(CMessage* self, PyObject* args);
static PyObject* CMessage_ClearFieldByDescriptor(
    CMessage* self, PyObject* args);
static PyObject* CMessage_CopyFrom(CMessage* self, PyObject* args);
static PyObject* CMessage_DebugString(CMessage* self, PyObject* args);
static PyObject* CMessage_DeleteRepeatedField(CMessage* self, PyObject* args);
static PyObject* CMessage_Equals(CMessage* self, PyObject* args);
static PyObject* CMessage_FieldLength(CMessage* self, PyObject* args);
static PyObject* CMessage_FindInitializationErrors(CMessage* self);
static PyObject* CMessage_GetRepeatedMessage(CMessage* self, PyObject* args);
static PyObject* CMessage_GetRepeatedScalar(CMessage* self, PyObject* args);
static PyObject* CMessage_GetScalar(CMessage* self, PyObject* args);
static PyObject* CMessage_HasField(CMessage* self, PyObject* args);
static PyObject* CMessage_HasFieldByDescriptor(CMessage* self, PyObject* args);
static PyObject* CMessage_IsInitialized(CMessage* self, PyObject* args);
static PyObject* CMessage_ListFields(CMessage* self, PyObject* args);
static PyObject* CMessage_MergeFrom(CMessage* self, PyObject* args);
static PyObject* CMessage_MergeFromString(CMessage* self, PyObject* args);
static PyObject* CMessage_MutableMessage(CMessage* self, PyObject* args);
static PyObject* CMessage_NewSubMessage(CMessage* self, PyObject* args);
static PyObject* CMessage_SetScalar(CMessage* self, PyObject* args);
static PyObject* CMessage_SerializePartialToString(
    CMessage* self, PyObject* args);
static PyObject* CMessage_SerializeToString(CMessage* self, PyObject* args);
static PyObject* CMessage_SetInParent(CMessage* self, PyObject* args);
static PyObject* CMessage_SwapRepeatedFieldElements(
    CMessage* self, PyObject* args);

// ------ Object Definition:

typedef struct CMessage {
  PyObject_HEAD

  struct CMessage* parent;  // NULL if wasn't created from another message.
  CFieldDescriptor* parent_field;
  const char* full_name;
  google::protobuf::Message* message;
  bool free_message;
  bool read_only;
} CMessage;

// ------ Method Table:

#define CMETHOD(name, args, doc)   \
  { C(#name), (PyCFunction)CMessage_##name, args, C(doc) }
static PyMethodDef CMessageMethods[] = {
  CMETHOD(AddMessage, METH_O,
          "Adds a new message to a repeated composite field."),
  CMETHOD(AddRepeatedScalar, METH_VARARGS,
          "Adds a scalar to a repeated scalar field."),
  CMETHOD(AssignRepeatedScalar, METH_VARARGS,
          "Clears and sets the values of a repeated scalar field."),
  CMETHOD(ByteSize, METH_NOARGS,
          "Returns the size of the message in bytes."),
  CMETHOD(Clear, METH_O,
          "Clears a protocol message."),
  CMETHOD(ClearField, METH_VARARGS,
          "Clears a protocol message field by name."),
  CMETHOD(ClearFieldByDescriptor, METH_O,
          "Clears a protocol message field by descriptor."),
  CMETHOD(CopyFrom, METH_O,
          "Copies a protocol message into the current message."),
  CMETHOD(DebugString, METH_NOARGS,
          "Returns the debug string of a protocol message."),
  CMETHOD(DeleteRepeatedField, METH_VARARGS,
          "Deletes a slice of values from a repeated field."),
  CMETHOD(Equals, METH_O,
          "Checks if two protocol messages are equal (by identity)."),
  CMETHOD(FieldLength, METH_O,
          "Returns the number of elements in a repeated field."),
  CMETHOD(FindInitializationErrors, METH_NOARGS,
          "Returns the initialization errors of a message."),
  CMETHOD(GetRepeatedMessage, METH_VARARGS,
          "Returns a message from a repeated composite field."),
  CMETHOD(GetRepeatedScalar, METH_VARARGS,
          "Returns a scalar value from a repeated scalar field."),
  CMETHOD(GetScalar, METH_O,
          "Returns the scalar value of a field."),
  CMETHOD(HasField, METH_O,
          "Checks if a message field is set."),
  CMETHOD(HasFieldByDescriptor, METH_O,
          "Checks if a message field is set by given its descriptor"),
  CMETHOD(IsInitialized, METH_NOARGS,
          "Checks if all required fields of a protocol message are set."),
  CMETHOD(ListFields, METH_NOARGS,
          "Lists all set fields of a message."),
  CMETHOD(MergeFrom, METH_O,
          "Merges a protocol message into the current message."),
  CMETHOD(MergeFromString, METH_O,
          "Merges a serialized message into the current message."),
  CMETHOD(MutableMessage, METH_O,
          "Returns a new instance of a nested protocol message."),
  CMETHOD(NewSubMessage, METH_O,
          "Creates and returns a python message given the descriptor of a "
          "composite field of the current message."),
  CMETHOD(SetScalar, METH_VARARGS,
          "Sets the value of a singular scalar field."),
  CMETHOD(SerializePartialToString, METH_VARARGS,
          "Serializes the message to a string, even if it isn't initialized."),
  CMETHOD(SerializeToString, METH_NOARGS,
          "Serializes the message to a string, only for initialized messages."),
  CMETHOD(SetInParent, METH_NOARGS,
          "Sets the has bit of the given field in its parent message."),
  CMETHOD(SwapRepeatedFieldElements, METH_VARARGS,
          "Swaps the elements in two positions in a repeated field."),
  { NULL, NULL }
};
#undef CMETHOD

static PyMemberDef CMessageMembers[] = {
  { C("full_name"), T_STRING, offsetof(CMessage, full_name), 0, "Full name" },
  { NULL }
};

// ------ Type Definition:

// The definition for the type object that captures the type of CMessage
// in Python.
PyTypeObject CMessage_Type = {
  PyObject_HEAD_INIT(&PyType_Type)
  0,
  C("google.protobuf.internal."
    "_net_proto2___python."
    "CMessage"),                       // tp_name
  sizeof(CMessage),                    //  tp_basicsize
  0,                                   //  tp_itemsize
  (destructor)CMessageDealloc,         //  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
  (reprfunc)CMessageStr,               //  tp_str
  0,                                   //  tp_getattro
  0,                                   //  tp_setattro
  0,                                   //  tp_as_buffer
  Py_TPFLAGS_DEFAULT,                  //  tp_flags
  C("A ProtocolMessage"),              //  tp_doc
  0,                                   //  tp_traverse
  0,                                   //  tp_clear
  0,                                   //  tp_richcompare
  0,                                   //  tp_weaklistoffset
  0,                                   //  tp_iter
  0,                                   //  tp_iternext
  CMessageMethods,                     //  tp_methods
  CMessageMembers,                     //  tp_members
  0,                                   //  tp_getset
  0,                                   //  tp_base
  0,                                   //  tp_dict
  0,                                   //  tp_descr_get
  0,                                   //  tp_descr_set
  0,                                   //  tp_dictoffset
  (initproc)CMessageInit,              //  tp_init
  PyType_GenericAlloc,                 //  tp_alloc
  PyType_GenericNew,                   //  tp_new
  PyObject_Del,                        //  tp_free
};

// ------ Helper Functions:

static void FormatTypeError(PyObject* arg, char* expected_types) {
  PyObject* repr = PyObject_Repr(arg);
  PyErr_Format(PyExc_TypeError,
               "%.100s has type %.100s, but expected one of: %s",
               PyString_AS_STRING(repr),
               arg->ob_type->tp_name,
               expected_types);
  Py_DECREF(repr);
}

template <class T>
static bool CheckAndGetInteger(
    PyObject* arg, T* value, PyObject* min, PyObject* max) {
  bool is_long = PyLong_Check(arg);
  if (!PyInt_Check(arg) && !is_long) {
    FormatTypeError(arg, "int, long");
    return false;
  }

  if (PyObject_Compare(min, arg) > 0 || PyObject_Compare(max, arg) < 0) {
    PyObject* s = PyObject_Str(arg);
    PyErr_Format(PyExc_ValueError,
                 "Value out of range: %s",
                 PyString_AS_STRING(s));
    Py_DECREF(s);
    return false;
  }
  if (is_long) {
    if (min == kPythonZero) {
      *value = static_cast<T>(PyLong_AsUnsignedLongLong(arg));
    } else {
      *value = static_cast<T>(PyLong_AsLongLong(arg));
    }
  } else {
    *value = static_cast<T>(PyInt_AsLong(arg));
  }
  return true;
}

static 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;
}

static bool CheckAndGetFloat(PyObject* arg, float* value) {
  double double_value;
  if (!CheckAndGetDouble(arg, &double_value)) {
    return false;
  }
  *value = static_cast<float>(double_value);
  return true;
}

static 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;
}

google::protobuf::DynamicMessageFactory* global_message_factory = NULL;
static const google::protobuf::Message* CreateMessage(const char* message_type) {
  string message_name(message_type);
  const google::protobuf::Descriptor* descriptor =
      GetDescriptorPool()->FindMessageTypeByName(message_name);
  if (descriptor == NULL) {
    return NULL;
  }
  return global_message_factory->GetPrototype(descriptor);
}

static void ReleaseSubMessage(google::protobuf::Message* message,
                           const google::protobuf::FieldDescriptor* field_descriptor,
                           CMessage* child_cmessage) {
  Message* released_message = message->GetReflection()->ReleaseMessage(
      message, field_descriptor, global_message_factory);
  GOOGLE_DCHECK(child_cmessage->message != NULL);
  // 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 = global_message_factory->GetPrototype(
        child_cmessage->message->GetDescriptor());
    GOOGLE_DCHECK(prototype != NULL);
    child_cmessage->message = prototype->New();
  }
  child_cmessage->parent = NULL;
  child_cmessage->parent_field = NULL;
  child_cmessage->free_message = true;
  child_cmessage->read_only = false;
}

static bool CheckAndSetString(
    PyObject* arg, google::protobuf::Message* message,
    const google::protobuf::FieldDescriptor* descriptor,
    const google::protobuf::Reflection* reflection,
    bool append,
    int index) {
  GOOGLE_DCHECK(descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING ||
         descriptor->type() == google::protobuf::FieldDescriptor::TYPE_BYTES);
  if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
    if (!PyString_Check(arg) && !PyUnicode_Check(arg)) {
      FormatTypeError(arg, "str, unicode");
      return false;
    }

    if (PyString_Check(arg)) {
      PyObject* unicode = PyUnicode_FromEncodedObject(arg, "ascii", NULL);
      if (unicode == NULL) {
        PyObject* repr = PyObject_Repr(arg);
        PyErr_Format(PyExc_ValueError,
                     "%s has type str, but isn't in 7-bit ASCII "
                     "encoding. Non-ASCII strings must be converted to "
                     "unicode objects before being added.",
                     PyString_AS_STRING(repr));
        Py_DECREF(repr);
        return false;
      } else {
        Py_DECREF(unicode);
      }
    }
  } else if (!PyString_Check(arg)) {
    FormatTypeError(arg, "str");
    return false;
  }

  PyObject* encoded_string = NULL;
  if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
    if (PyString_Check(arg)) {
      encoded_string = PyString_AsEncodedObject(arg, "utf-8", NULL);
    } else {
      encoded_string = PyUnicode_AsEncodedObject(arg, "utf-8", NULL);
    }
  } else {
    // In this case field type is "bytes".
    encoded_string = arg;
    Py_INCREF(encoded_string);
  }

  if (encoded_string == NULL) {
    return false;
  }

  char* value;
  Py_ssize_t value_len;
  if (PyString_AsStringAndSize(encoded_string, &value, &value_len) < 0) {
    Py_DECREF(encoded_string);
    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);
  }
  Py_DECREF(encoded_string);
  return true;
}

static PyObject* ToStringObject(
    const google::protobuf::FieldDescriptor* descriptor, string value) {
  if (descriptor->type() != google::protobuf::FieldDescriptor::TYPE_STRING) {
    return PyString_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 = PyString_FromStringAndSize(value.c_str(), value.length());
  }
  return result;
}

static void AssureWritable(CMessage* self) {
  if (self == NULL ||
      self->parent == NULL ||
      self->parent_field == NULL) {
    return;
  }

  if (!self->read_only) {
    return;
  }

  AssureWritable(self->parent);

  google::protobuf::Message* message = self->parent->message;
  const google::protobuf::Reflection* reflection = message->GetReflection();
  self->message = reflection->MutableMessage(
      message, self->parent_field->descriptor, global_message_factory);
  self->read_only = false;
}

static PyObject* InternalGetScalar(
    google::protobuf::Message* message,
    const google::protobuf::FieldDescriptor* field_descriptor) {
  const google::protobuf::Reflection* reflection = message->GetReflection();

  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
    PyErr_SetString(
        PyExc_KeyError, "Field does not belong to message!");
    return NULL;
  }

  PyObject* result = NULL;
  switch (field_descriptor->cpp_type()) {
    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
      int32 value = reflection->GetInt32(*message, field_descriptor);
      result = PyInt_FromLong(value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
      int64 value = reflection->GetInt64(*message, field_descriptor);
#if IS_64BIT
      result = PyInt_FromLong(value);
#else
      result = PyLong_FromLongLong(value);
#endif
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
      uint32 value = reflection->GetUInt32(*message, field_descriptor);
#if IS_64BIT
      result = PyInt_FromLong(value);
#else
      result = PyLong_FromLongLong(value);
#endif
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
      uint64 value = reflection->GetUInt64(*message, field_descriptor);
#if IS_64BIT
      if (value <= static_cast<uint64>(kint64max)) {
        result = PyInt_FromLong(static_cast<uint64>(value));
      }
#else
      if (value <= static_cast<uint32>(kint32max)) {
        result = PyInt_FromLong(static_cast<uint32>(value));
      }
#endif
      else {  // NOLINT
        result = PyLong_FromUnsignedLongLong(value);
      }
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
      float value = reflection->GetFloat(*message, field_descriptor);
      result = PyFloat_FromDouble(value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
      double value = reflection->GetDouble(*message, field_descriptor);
      result = PyFloat_FromDouble(value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
      bool value = reflection->GetBool(*message, field_descriptor);
      result = PyBool_FromLong(value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
      string value = reflection->GetString(*message, field_descriptor);
      result = ToStringObject(field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
      if (!message->GetReflection()->HasField(*message, field_descriptor)) {
        // Look for the value in the unknown fields.
        google::protobuf::UnknownFieldSet* unknown_field_set =
            message->GetReflection()->MutableUnknownFields(message);
        for (int i = 0; i < unknown_field_set->field_count(); ++i) {
          if (unknown_field_set->field(i).number() ==
              field_descriptor->number()) {
            result = PyInt_FromLong(unknown_field_set->field(i).varint());
            break;
          }
        }
      }

      if (result == NULL) {
        const google::protobuf::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;
}

static PyObject* InternalSetScalar(
    google::protobuf::Message* message, const google::protobuf::FieldDescriptor* field_descriptor,
    PyObject* arg) {
  const google::protobuf::Reflection* reflection = message->GetReflection();

  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
    PyErr_SetString(
        PyExc_KeyError, "Field does not belong to message!");
    return NULL;
  }

  switch (field_descriptor->cpp_type()) {
    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
      GOOGLE_CHECK_GET_INT32(arg, value);
      reflection->SetInt32(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
      GOOGLE_CHECK_GET_INT64(arg, value);
      reflection->SetInt64(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
      GOOGLE_CHECK_GET_UINT32(arg, value);
      reflection->SetUInt32(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
      GOOGLE_CHECK_GET_UINT64(arg, value);
      reflection->SetUInt64(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
      GOOGLE_CHECK_GET_FLOAT(arg, value);
      reflection->SetFloat(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
      GOOGLE_CHECK_GET_DOUBLE(arg, value);
      reflection->SetDouble(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
      GOOGLE_CHECK_GET_BOOL(arg, value);
      reflection->SetBool(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
      if (!CheckAndSetString(
          arg, message, field_descriptor, reflection, false, -1)) {
        return NULL;
      }
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
      GOOGLE_CHECK_GET_INT32(arg, value);
      const google::protobuf::EnumDescriptor* enum_descriptor =
          field_descriptor->enum_type();
      const google::protobuf::EnumValueDescriptor* enum_value =
          enum_descriptor->FindValueByNumber(value);
      if (enum_value != NULL) {
        reflection->SetEnum(message, field_descriptor, enum_value);
      } else {
        bool added = false;
        // Add the value to the unknown fields.
        google::protobuf::UnknownFieldSet* unknown_field_set =
            message->GetReflection()->MutableUnknownFields(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->mutable_field(i)->set_varint(value);
            added = true;
            break;
          }
        }

        if (!added) {
          unknown_field_set->AddVarint(field_descriptor->number(), value);
        }
        reflection->ClearField(message, field_descriptor);
      }
      break;
    }
    default:
      PyErr_Format(
          PyExc_SystemError, "Setting value to a field of unknown type %d",
          field_descriptor->cpp_type());
  }

  Py_RETURN_NONE;
}

static PyObject* InternalAddRepeatedScalar(
    google::protobuf::Message* message, const google::protobuf::FieldDescriptor* field_descriptor,
    PyObject* arg) {

  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
    PyErr_SetString(
        PyExc_KeyError, "Field does not belong to message!");
    return NULL;
  }

  const google::protobuf::Reflection* reflection = message->GetReflection();
  switch (field_descriptor->cpp_type()) {
    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
      GOOGLE_CHECK_GET_INT32(arg, value);
      reflection->AddInt32(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
      GOOGLE_CHECK_GET_INT64(arg, value);
      reflection->AddInt64(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
      GOOGLE_CHECK_GET_UINT32(arg, value);
      reflection->AddUInt32(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
      GOOGLE_CHECK_GET_UINT64(arg, value);
      reflection->AddUInt64(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
      GOOGLE_CHECK_GET_FLOAT(arg, value);
      reflection->AddFloat(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
      GOOGLE_CHECK_GET_DOUBLE(arg, value);
      reflection->AddDouble(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
      GOOGLE_CHECK_GET_BOOL(arg, value);
      reflection->AddBool(message, field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
      if (!CheckAndSetString(
          arg, message, field_descriptor, reflection, true, -1)) {
        return NULL;
      }
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
      GOOGLE_CHECK_GET_INT32(arg, value);
      const google::protobuf::EnumDescriptor* enum_descriptor =
          field_descriptor->enum_type();
      const google::protobuf::EnumValueDescriptor* enum_value =
          enum_descriptor->FindValueByNumber(value);
      if (enum_value != NULL) {
        reflection->AddEnum(message, field_descriptor, enum_value);
      } else {
        PyObject* s = PyObject_Str(arg);
        PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
                     PyString_AS_STRING(s));
        Py_DECREF(s);
        return NULL;
      }
      break;
    }
    default:
      PyErr_Format(
          PyExc_SystemError, "Adding value to a field of unknown type %d",
          field_descriptor->cpp_type());
  }

  Py_RETURN_NONE;
}

static PyObject* InternalGetRepeatedScalar(
    CMessage* cmessage, const google::protobuf::FieldDescriptor* field_descriptor,
    int index) {
  google::protobuf::Message* message = cmessage->message;
  const google::protobuf::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", index);
    return NULL;
  }

  PyObject* result = NULL;
  switch (field_descriptor->cpp_type()) {
    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
      int32 value = reflection->GetRepeatedInt32(
          *message, field_descriptor, index);
      result = PyInt_FromLong(value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
      int64 value = reflection->GetRepeatedInt64(
          *message, field_descriptor, index);
      result = PyLong_FromLongLong(value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
      uint32 value = reflection->GetRepeatedUInt32(
          *message, field_descriptor, index);
      result = PyLong_FromLongLong(value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
      uint64 value = reflection->GetRepeatedUInt64(
          *message, field_descriptor, index);
      result = PyLong_FromUnsignedLongLong(value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
      float value = reflection->GetRepeatedFloat(
          *message, field_descriptor, index);
      result = PyFloat_FromDouble(value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
      double value = reflection->GetRepeatedDouble(
          *message, field_descriptor, index);
      result = PyFloat_FromDouble(value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
      bool value = reflection->GetRepeatedBool(
          *message, field_descriptor, index);
      result = PyBool_FromLong(value ? 1 : 0);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
      const google::protobuf::EnumValueDescriptor* enum_value =
          message->GetReflection()->GetRepeatedEnum(
              *message, field_descriptor, index);
      result = PyInt_FromLong(enum_value->number());
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
      string value = reflection->GetRepeatedString(
          *message, field_descriptor, index);
      result = ToStringObject(field_descriptor, value);
      break;
    }
    case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
      CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
      if (py_cmsg == NULL) {
        return NULL;
      }
      const google::protobuf::Message& msg = reflection->GetRepeatedMessage(
          *message, field_descriptor, index);
      py_cmsg->parent = cmessage;
      py_cmsg->full_name = field_descriptor->full_name().c_str();
      py_cmsg->message = const_cast<google::protobuf::Message*>(&msg);
      py_cmsg->free_message = false;
      py_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* InternalGetRepeatedScalarSlice(
    CMessage* cmessage, const google::protobuf::FieldDescriptor* field_descriptor,
    PyObject* slice) {
  Py_ssize_t from;
  Py_ssize_t to;
  Py_ssize_t step;
  Py_ssize_t length;
  bool return_list = false;
  google::protobuf::Message* message = cmessage->message;

  if (PyInt_Check(slice)) {
    from = to = PyInt_AsLong(slice);
  } else if (PyLong_Check(slice)) {
    from = to = PyLong_AsLong(slice);
  } else if (PySlice_Check(slice)) {
    const google::protobuf::Reflection* reflection = message->GetReflection();
    length = reflection->FieldSize(*message, field_descriptor);
    PySlice_GetIndices(
        reinterpret_cast<PySliceObject*>(slice), length, &from, &to, &step);
    return_list = true;
  } else {
    PyErr_SetString(PyExc_TypeError, "list indices must be integers");
    return NULL;
  }

  if (!return_list) {
    return InternalGetRepeatedScalar(cmessage, field_descriptor, 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;
      PyObject* s = InternalGetRepeatedScalar(
          cmessage, field_descriptor, index);
      PyList_Append(list, s);
      Py_DECREF(s);
    }
  } else {
    if (step > 0) return list;
    for (Py_ssize_t index = from; index > to; index += step) {
      if (index < 0 || index >= length) break;
      PyObject* s = InternalGetRepeatedScalar(
          cmessage, field_descriptor, index);
      PyList_Append(list, s);
      Py_DECREF(s);
    }
  }
  return list;
}

// ------ C Constructor/Destructor:

static int CMessageInit(CMessage* self, PyObject *args, PyObject *kwds) {
  self->message = NULL;
  return 0;
}

static void CMessageDealloc(CMessage* self) {
  if (self->free_message) {
    if (self->read_only) {
      PyErr_WriteUnraisable(reinterpret_cast<PyObject*>(self));
    }
    delete self->message;
  }
  self->ob_type->tp_free(reinterpret_cast<PyObject*>(self));
}

// ------ Methods:

static PyObject* CMessage_Clear(CMessage* self, PyObject* arg) {
  AssureWritable(self);
  google::protobuf::Message* message = self->message;

  // This block of code is equivalent to the following:
  // for cfield_descriptor, child_cmessage in arg:
  //   ReleaseSubMessage(cfield_descriptor, child_cmessage)
  if (!PyList_Check(arg)) {
    PyErr_SetString(PyExc_TypeError, "Must be a list");
    return NULL;
  }
  PyObject* messages_to_clear = arg;
  Py_ssize_t num_messages_to_clear = PyList_GET_SIZE(messages_to_clear);
  for(int i = 0; i < num_messages_to_clear; ++i) {
    PyObject* message_tuple = PyList_GET_ITEM(messages_to_clear, i);
    if (!PyTuple_Check(message_tuple) || PyTuple_GET_SIZE(message_tuple) != 2) {
      PyErr_SetString(PyExc_TypeError, "Must be a tuple of size 2");
      return NULL;
    }

    PyObject* py_cfield_descriptor = PyTuple_GET_ITEM(message_tuple, 0);
    PyObject* py_child_cmessage = PyTuple_GET_ITEM(message_tuple, 1);
    if (!PyObject_TypeCheck(py_cfield_descriptor, &CFieldDescriptor_Type) ||
        !PyObject_TypeCheck(py_child_cmessage, &CMessage_Type)) {
      PyErr_SetString(PyExc_ValueError, "Invalid Tuple");
      return NULL;
    }

    CFieldDescriptor* cfield_descriptor = reinterpret_cast<CFieldDescriptor *>(
        py_cfield_descriptor);
    CMessage* child_cmessage = reinterpret_cast<CMessage *>(py_child_cmessage);
    ReleaseSubMessage(message, cfield_descriptor->descriptor, child_cmessage);
  }

  message->Clear();
  Py_RETURN_NONE;
}

static PyObject* CMessage_IsInitialized(CMessage* self, PyObject* args) {
  return PyBool_FromLong(self->message->IsInitialized() ? 1 : 0);
}

static PyObject* CMessage_HasField(CMessage* self, PyObject* arg) {
  char* field_name;
  if (PyString_AsStringAndSize(arg, &field_name, NULL) < 0) {
    return NULL;
  }

  google::protobuf::Message* message = self->message;
  const google::protobuf::Descriptor* descriptor = message->GetDescriptor();
  const google::protobuf::FieldDescriptor* field_descriptor =
      descriptor->FindFieldByName(field_name);
  if (field_descriptor == NULL) {
    PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name);
    return NULL;
  }

  bool has_field =
      message->GetReflection()->HasField(*message, field_descriptor);
  return PyBool_FromLong(has_field ? 1 : 0);
}

static PyObject* CMessage_HasFieldByDescriptor(CMessage* self, PyObject* arg) {
  CFieldDescriptor* cfield_descriptor = NULL;
  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
                          &CFieldDescriptor_Type)) {
    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
    return NULL;
  }
  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);

  google::protobuf::Message* message = self->message;
  const google::protobuf::FieldDescriptor* field_descriptor =
      cfield_descriptor->descriptor;

  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
    PyErr_SetString(PyExc_KeyError,
                    "Field does not belong to message!");
    return NULL;
  }

  if (FIELD_IS_REPEATED(field_descriptor)) {
    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);
}

static PyObject* CMessage_ClearFieldByDescriptor(
    CMessage* self, PyObject* arg) {
  CFieldDescriptor* cfield_descriptor = NULL;
  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
                          &CFieldDescriptor_Type)) {
    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
    return NULL;
  }
  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);

  google::protobuf::Message* message = self->message;
  const google::protobuf::FieldDescriptor* field_descriptor =
      cfield_descriptor->descriptor;

  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
    PyErr_SetString(PyExc_KeyError,
                    "Field does not belong to message!");
    return NULL;
  }

  message->GetReflection()->ClearField(message, field_descriptor);
  Py_RETURN_NONE;
}

static PyObject* CMessage_ClearField(CMessage* self, PyObject* args) {
  char* field_name;
  CMessage* child_cmessage = NULL;
  if (!PyArg_ParseTuple(args, C("s|O!:ClearField"), &field_name,
                        &CMessage_Type, &child_cmessage)) {
    return NULL;
  }

  google::protobuf::Message* message = self->message;
  const google::protobuf::Descriptor* descriptor = message->GetDescriptor();
  const google::protobuf::FieldDescriptor* field_descriptor =
      descriptor->FindFieldByName(field_name);
  if (field_descriptor == NULL) {
    PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name);
    return NULL;
  }

  if (child_cmessage != NULL && !FIELD_IS_REPEATED(field_descriptor)) {
    ReleaseSubMessage(message, field_descriptor, child_cmessage);
  } else {
    message->GetReflection()->ClearField(message, field_descriptor);
  }
  Py_RETURN_NONE;
}

static PyObject* CMessage_GetScalar(CMessage* self, PyObject* arg) {
  CFieldDescriptor* cdescriptor = NULL;
  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
                          &CFieldDescriptor_Type)) {
    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
    return NULL;
  }
  cdescriptor = reinterpret_cast<CFieldDescriptor*>(arg);

  google::protobuf::Message* message = self->message;
  return InternalGetScalar(message, cdescriptor->descriptor);
}

static PyObject* CMessage_GetRepeatedScalar(CMessage* self, PyObject* args) {
  CFieldDescriptor* cfield_descriptor;
  PyObject* slice;
  if (!PyArg_ParseTuple(args, C("O!O:GetRepeatedScalar"),
                        &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
    return NULL;
  }

  return InternalGetRepeatedScalarSlice(
      self, cfield_descriptor->descriptor, slice);
}

static PyObject* CMessage_AssignRepeatedScalar(CMessage* self, PyObject* args) {
  CFieldDescriptor* cfield_descriptor;
  PyObject* slice;
  if (!PyArg_ParseTuple(args, C("O!O:AssignRepeatedScalar"),
                        &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
    return NULL;
  }

  AssureWritable(self);
  google::protobuf::Message* message = self->message;
  message->GetReflection()->ClearField(message, cfield_descriptor->descriptor);

  PyObject* iter = PyObject_GetIter(slice);
  PyObject* next;
  while ((next = PyIter_Next(iter)) != NULL) {
    if (InternalAddRepeatedScalar(
            message, cfield_descriptor->descriptor, next) == NULL) {
      Py_DECREF(next);
      Py_DECREF(iter);
      return NULL;
    }
    Py_DECREF(next);
  }
  Py_DECREF(iter);
  Py_RETURN_NONE;
}

static PyObject* CMessage_DeleteRepeatedField(CMessage* self, PyObject* args) {
  CFieldDescriptor* cfield_descriptor;
  PyObject* slice;
  if (!PyArg_ParseTuple(args, C("O!O:DeleteRepeatedField"),
                        &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
    return NULL;
  }
  AssureWritable(self);

  Py_ssize_t length, from, to, step, slice_length;
  google::protobuf::Message* message = self->message;
  const google::protobuf::FieldDescriptor* field_descriptor =
      cfield_descriptor->descriptor;
  const google::protobuf::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 NULL;
    }
  } else if (PySlice_Check(slice)) {
    from = to = step = slice_length = 0;
    PySlice_GetIndicesEx(
        reinterpret_cast<PySliceObject*>(slice),
        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 NULL;
  }

  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);
      }
      ++to;
    }
  }

  while (i > to) {
    reflection->RemoveLast(message, field_descriptor);
    --i;
  }

  Py_RETURN_NONE;
}


static PyObject* CMessage_SetScalar(CMessage* self, PyObject* args) {
  CFieldDescriptor* cfield_descriptor;
  PyObject* arg;
  if (!PyArg_ParseTuple(args, C("O!O:SetScalar"),
                        &CFieldDescriptor_Type, &cfield_descriptor, &arg)) {
    return NULL;
  }
  AssureWritable(self);

  return InternalSetScalar(self->message, cfield_descriptor->descriptor, arg);
}

static PyObject* CMessage_AddRepeatedScalar(CMessage* self, PyObject* args) {
  CFieldDescriptor* cfield_descriptor;
  PyObject* value;
  if (!PyArg_ParseTuple(args, C("O!O:AddRepeatedScalar"),
                        &CFieldDescriptor_Type, &cfield_descriptor, &value)) {
    return NULL;
  }
  AssureWritable(self);

  return InternalAddRepeatedScalar(
      self->message, cfield_descriptor->descriptor, value);
}

static PyObject* CMessage_FieldLength(CMessage* self, PyObject* arg) {
  CFieldDescriptor* cfield_descriptor;
  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
                          &CFieldDescriptor_Type)) {
    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
    return NULL;
  }
  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);

  google::protobuf::Message* message = self->message;
  int length = message->GetReflection()->FieldSize(
      *message, cfield_descriptor->descriptor);
  return PyInt_FromLong(length);
}

static PyObject* CMessage_DebugString(CMessage* self, PyObject* args) {
  return PyString_FromString(self->message->DebugString().c_str());
}

static PyObject* CMessage_SerializeToString(CMessage* self, PyObject* args) {
  int size = self->message->ByteSize();
  if (size <= 0) {
    return PyString_FromString("");
  }
  PyObject* result = PyString_FromStringAndSize(NULL, size);
  if (result == NULL) {
    return NULL;
  }
  char* buffer = PyString_AS_STRING(result);
  self->message->SerializeWithCachedSizesToArray(
      reinterpret_cast<uint8*>(buffer));
  return result;
}

static PyObject* CMessage_SerializePartialToString(
    CMessage* self, PyObject* args) {
  string contents;
  self->message->SerializePartialToString(&contents);
  return PyString_FromStringAndSize(contents.c_str(), contents.size());
}

static PyObject* CMessageStr(CMessage* self) {
  char str[1024];
  str[sizeof(str) - 1] = 0;
  snprintf(str, sizeof(str) - 1, "CMessage: <%p>", self->message);
  return PyString_FromString(str);
}

static PyObject* CMessage_MergeFrom(CMessage* self, PyObject* arg) {
  CMessage* other_message;
  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
    PyErr_SetString(PyExc_TypeError, "Must be a message");
    return NULL;
  }

  other_message = reinterpret_cast<CMessage*>(arg);
  if (other_message->message->GetDescriptor() !=
      self->message->GetDescriptor()) {
    PyErr_Format(PyExc_TypeError,
                 "Tried to merge from a message with a different type. "
                 "to: %s, from: %s",
                 self->message->GetDescriptor()->full_name().c_str(),
                 other_message->message->GetDescriptor()->full_name().c_str());
    return NULL;
  }
  AssureWritable(self);

  self->message->MergeFrom(*other_message->message);
  Py_RETURN_NONE;
}

static PyObject* CMessage_CopyFrom(CMessage* self, PyObject* arg) {
  CMessage* other_message;
  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
    PyErr_SetString(PyExc_TypeError, "Must be a message");
    return NULL;
  }

  other_message = reinterpret_cast<CMessage*>(arg);
  if (other_message->message->GetDescriptor() !=
      self->message->GetDescriptor()) {
    PyErr_Format(PyExc_TypeError,
                 "Tried to copy from a message with a different type. "
                 "to: %s, from: %s",
                 self->message->GetDescriptor()->full_name().c_str(),
                 other_message->message->GetDescriptor()->full_name().c_str());
    return NULL;
  }

  AssureWritable(self);

  self->message->CopyFrom(*other_message->message);
  Py_RETURN_NONE;
}

static PyObject* CMessage_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);
  google::protobuf::io::CodedInputStream input(
      reinterpret_cast<const uint8*>(data), data_length);
  input.SetExtensionRegistry(GetDescriptorPool(), global_message_factory);
  bool success = self->message->MergePartialFromCodedStream(&input);
  if (success) {
    return PyInt_FromLong(self->message->ByteSize());
  } else {
    return PyInt_FromLong(-1);
  }
}

static PyObject* CMessage_ByteSize(CMessage* self, PyObject* args) {
  return PyLong_FromLong(self->message->ByteSize());
}

static PyObject* CMessage_SetInParent(CMessage* self, PyObject* args) {
  AssureWritable(self);
  Py_RETURN_NONE;
}

static PyObject* CMessage_SwapRepeatedFieldElements(
    CMessage* self, PyObject* args) {
  CFieldDescriptor* cfield_descriptor;
  int index1, index2;
  if (!PyArg_ParseTuple(args, C("O!ii:SwapRepeatedFieldElements"),
                        &CFieldDescriptor_Type, &cfield_descriptor,
                        &index1, &index2)) {
    return NULL;
  }

  google::protobuf::Message* message = self->message;
  const google::protobuf::Reflection* reflection = message->GetReflection();

  reflection->SwapElements(
      message, cfield_descriptor->descriptor, index1, index2);
  Py_RETURN_NONE;
}

static PyObject* CMessage_AddMessage(CMessage* self, PyObject* arg) {
  CFieldDescriptor* cfield_descriptor;
  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
                          &CFieldDescriptor_Type)) {
    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
    return NULL;
  }
  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
  AssureWritable(self);

  CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
  if (py_cmsg == NULL) {
    return NULL;
  }

  google::protobuf::Message* message = self->message;
  const google::protobuf::Reflection* reflection = message->GetReflection();
  google::protobuf::Message* sub_message =
      reflection->AddMessage(message, cfield_descriptor->descriptor);

  py_cmsg->parent = NULL;
  py_cmsg->full_name = sub_message->GetDescriptor()->full_name().c_str();
  py_cmsg->message = sub_message;
  py_cmsg->free_message = false;
  py_cmsg->read_only = false;
  return reinterpret_cast<PyObject*>(py_cmsg);
}

static PyObject* CMessage_GetRepeatedMessage(CMessage* self, PyObject* args) {
  CFieldDescriptor* cfield_descriptor;
  PyObject* slice;
  if (!PyArg_ParseTuple(args, C("O!O:GetRepeatedMessage"),
                        &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
    return NULL;
  }

  return InternalGetRepeatedScalarSlice(
      self, cfield_descriptor->descriptor, slice);
}

static PyObject* CMessage_NewSubMessage(CMessage* self, PyObject* arg) {
  CFieldDescriptor* cfield_descriptor;
  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
                          &CFieldDescriptor_Type)) {
    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
    return NULL;
  }
  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);

  CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
  if (py_cmsg == NULL) {
    return NULL;
  }

  google::protobuf::Message* message = self->message;
  const google::protobuf::Reflection* reflection = message->GetReflection();
  const google::protobuf::Message& sub_message =
      reflection->GetMessage(*message, cfield_descriptor->descriptor,
                             global_message_factory);

  py_cmsg->full_name = sub_message.GetDescriptor()->full_name().c_str();
  py_cmsg->parent = self;
  py_cmsg->parent_field = cfield_descriptor;
  py_cmsg->message = const_cast<google::protobuf::Message*>(&sub_message);
  py_cmsg->free_message = false;
  py_cmsg->read_only = true;
  return reinterpret_cast<PyObject*>(py_cmsg);
}

static PyObject* CMessage_MutableMessage(CMessage* self, PyObject* arg) {
  CFieldDescriptor* cfield_descriptor;
  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
                          &CFieldDescriptor_Type)) {
    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
    return NULL;
  }
  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
  AssureWritable(self);

  CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
  if (py_cmsg == NULL) {
    return NULL;
  }

  google::protobuf::Message* message = self->message;
  const google::protobuf::Reflection* reflection = message->GetReflection();
  google::protobuf::Message* mutable_message =
      reflection->MutableMessage(message, cfield_descriptor->descriptor,
                                 global_message_factory);

  py_cmsg->full_name = mutable_message->GetDescriptor()->full_name().c_str();
  py_cmsg->message = mutable_message;
  py_cmsg->free_message = false;
  py_cmsg->read_only = false;
  return reinterpret_cast<PyObject*>(py_cmsg);
}

static PyObject* CMessage_Equals(CMessage* self, PyObject* arg) {
  CMessage* other_message;
  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
    PyErr_SetString(PyExc_TypeError, "Must be a message");
    return NULL;
  }
  other_message = reinterpret_cast<CMessage*>(arg);

  if (other_message->message == self->message) {
    return PyBool_FromLong(1);
  }

  if (other_message->message->GetDescriptor() !=
      self->message->GetDescriptor()) {
    return PyBool_FromLong(0);
  }

  return PyBool_FromLong(1);
}

static PyObject* CMessage_ListFields(CMessage* self, PyObject* args) {
  google::protobuf::Message* message = self->message;
  const google::protobuf::Reflection* reflection = message->GetReflection();
  vector<const google::protobuf::FieldDescriptor*> fields;
  reflection->ListFields(*message, &fields);

  PyObject* list = PyList_New(fields.size());
  if (list == NULL) {
    return NULL;
  }

  for (unsigned int i = 0; i < fields.size(); ++i) {
    bool is_extension = fields[i]->is_extension();
    PyObject* t = PyTuple_New(2);
    if (t == NULL) {
      Py_DECREF(list);
      return NULL;
    }

    PyObject* is_extension_object = PyBool_FromLong(is_extension ? 1 : 0);

    PyObject* field_name;
    const string* s;
    if (is_extension) {
      s = &fields[i]->full_name();
    } else {
      s = &fields[i]->name();
    }
    field_name = PyString_FromStringAndSize(s->c_str(), s->length());
    if (field_name == NULL) {
      Py_DECREF(list);
      Py_DECREF(t);
      return NULL;
    }

    PyTuple_SET_ITEM(t, 0, is_extension_object);
    PyTuple_SET_ITEM(t, 1, field_name);
    PyList_SET_ITEM(list, i, t);
  }

  return list;
}

static PyObject* CMessage_FindInitializationErrors(CMessage* self) {
  google::protobuf::Message* message = self->message;
  vector<string> errors;
  message->FindInitializationErrors(&errors);

  PyObject* error_list = PyList_New(errors.size());
  if (error_list == NULL) {
    return NULL;
  }
  for (unsigned int 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;
}

// ------ Python Constructor:

PyObject* Python_NewCMessage(PyObject* ignored, PyObject* arg) {
  const char* message_type = PyString_AsString(arg);
  if (message_type == NULL) {
    return NULL;
  }

  const google::protobuf::Message* message = CreateMessage(message_type);
  if (message == NULL) {
    PyErr_Format(PyExc_TypeError, "Couldn't create message of type %s!",
                 message_type);
    return NULL;
  }

  CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
  if (py_cmsg == NULL) {
    return NULL;
  }
  py_cmsg->message = message->New();
  py_cmsg->free_message = true;
  py_cmsg->full_name = message->GetDescriptor()->full_name().c_str();
  py_cmsg->read_only = false;
  py_cmsg->parent = NULL;
  py_cmsg->parent_field = NULL;
  return reinterpret_cast<PyObject*>(py_cmsg);
}

// --- Module Functions (exposed to Python):

PyMethodDef methods[] = {
  { C("NewCMessage"), (PyCFunction)Python_NewCMessage,
    METH_O,
    C("Creates a new C++ protocol message, given its full name.") },
  { C("NewCDescriptorPool"), (PyCFunction)Python_NewCDescriptorPool,
    METH_NOARGS,
    C("Creates a new C++ descriptor pool.") },
  { C("BuildFile"), (PyCFunction)Python_BuildFile,
    METH_O,
    C("Registers a new protocol buffer file in the global C++ descriptor "
      "pool.") },
  {NULL}
};

// --- Exposing the C proto living inside Python proto to C code:

extern const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg);
extern Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg);

static const google::protobuf::Message* GetCProtoInsidePyProtoImpl(PyObject* msg) {
  PyObject* c_msg_obj = PyObject_GetAttrString(msg, "_cmsg");
  if (c_msg_obj == NULL) {
    PyErr_Clear();
    return NULL;
  }
  Py_DECREF(c_msg_obj);
  if (!PyObject_TypeCheck(c_msg_obj, &CMessage_Type)) {
    return NULL;
  }
  CMessage* c_msg = reinterpret_cast<CMessage*>(c_msg_obj);
  return c_msg->message;
}

static google::protobuf::Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) {
  PyObject* c_msg_obj = PyObject_GetAttrString(msg, "_cmsg");
  if (c_msg_obj == NULL) {
    PyErr_Clear();
    return NULL;
  }
  Py_DECREF(c_msg_obj);
  if (!PyObject_TypeCheck(c_msg_obj, &CMessage_Type)) {
    return NULL;
  }
  CMessage* c_msg = reinterpret_cast<CMessage*>(c_msg_obj);
  AssureWritable(c_msg);
  return c_msg->message;
}

// --- Module Init Function:

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.";

extern "C" {
  void init_net_proto2___python() {
    // Initialize constants.
    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);

    global_message_factory = new DynamicMessageFactory(GetDescriptorPool());
    global_message_factory->SetDelegateToGeneratedFactory(true);

    // Export our functions to Python.
    PyObject *m;
    m = Py_InitModule3(C("_net_proto2___python"), methods, C(module_docstring));
    if (m == NULL) {
      return;
    }

    AddConstants(m);

    CMessage_Type.tp_new = PyType_GenericNew;
    if (PyType_Ready(&CMessage_Type) < 0) {
      return;
    }

    if (!InitDescriptor()) {
      return;
    }

    // Override {Get,Mutable}CProtoInsidePyProto.
    GetCProtoInsidePyProtoPtr = GetCProtoInsidePyProtoImpl;
    MutableCProtoInsidePyProtoPtr = MutableCProtoInsidePyProtoImpl;
  }
}

}  // namespace python
}  // namespace protobuf
}  // namespace google

/* [<][>][^][v][top][bottom][index][help] */