1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9//     * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11//     * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15//     * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// Mappings and Sequences of descriptors.
32// Used by Descriptor.fields_by_name, EnumDescriptor.values...
33//
34// They avoid the allocation of a full dictionary or a full list: they simply
35// store a pointer to the parent descriptor, use the C++ Descriptor methods (see
36// google/protobuf/descriptor.h) to retrieve other descriptors, and create
37// Python objects on the fly.
38//
39// The containers fully conform to abc.Mapping and abc.Sequence, and behave just
40// like read-only dictionaries and lists.
41//
42// Because the interface of C++ Descriptors is quite regular, this file actually
43// defines only three types, the exact behavior of a container is controlled by
44// a DescriptorContainerDef structure, which contains functions that uses the
45// public Descriptor API.
46//
47// Note: This DescriptorContainerDef is similar to the "virtual methods table"
48// that a C++ compiler generates for a class. We have to make it explicit
49// because the Python API is based on C, and does not play well with C++
50// inheritance.
51
52#include <Python.h>
53
54#include <google/protobuf/descriptor.h>
55#include <google/protobuf/pyext/descriptor_containers.h>
56#include <google/protobuf/pyext/descriptor_pool.h>
57#include <google/protobuf/pyext/descriptor.h>
58#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
59
60#if PY_MAJOR_VERSION >= 3
61  #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
62  #define PyString_FromFormat PyUnicode_FromFormat
63  #define PyInt_FromLong PyLong_FromLong
64  #if PY_VERSION_HEX < 0x03030000
65    #error "Python 3.0 - 3.2 are not supported."
66  #endif
67  #define PyString_AsStringAndSize(ob, charpp, sizep) \
68    (PyUnicode_Check(ob)? \
69       ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \
70       PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
71#endif
72
73namespace google {
74namespace protobuf {
75namespace python {
76
77struct PyContainer;
78
79typedef int (*CountMethod)(PyContainer* self);
80typedef const void* (*GetByIndexMethod)(PyContainer* self, int index);
81typedef const void* (*GetByNameMethod)(PyContainer* self, const string& name);
82typedef const void* (*GetByCamelcaseNameMethod)(PyContainer* self,
83                                                const string& name);
84typedef const void* (*GetByNumberMethod)(PyContainer* self, int index);
85typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor);
86typedef const string& (*GetItemNameMethod)(const void* descriptor);
87typedef const string& (*GetItemCamelcaseNameMethod)(const void* descriptor);
88typedef int (*GetItemNumberMethod)(const void* descriptor);
89typedef int (*GetItemIndexMethod)(const void* descriptor);
90
91struct DescriptorContainerDef {
92  const char* mapping_name;
93  // Returns the number of items in the container.
94  CountMethod count_fn;
95  // Retrieve item by index (usually the order of declaration in the proto file)
96  // Used by sequences, but also iterators. 0 <= index < Count().
97  GetByIndexMethod get_by_index_fn;
98  // Retrieve item by name (usually a call to some 'FindByName' method).
99  // Used by "by_name" mappings.
100  GetByNameMethod get_by_name_fn;
101  // Retrieve item by camelcase name (usually a call to some
102  // 'FindByCamelcaseName' method). Used by "by_camelcase_name" mappings.
103  GetByCamelcaseNameMethod get_by_camelcase_name_fn;
104  // Retrieve item by declared number (field tag, or enum value).
105  // Used by "by_number" mappings.
106  GetByNumberMethod get_by_number_fn;
107  // Converts a item C++ descriptor to a Python object. Returns a new reference.
108  NewObjectFromItemMethod new_object_from_item_fn;
109  // Retrieve the name of an item. Used by iterators on "by_name" mappings.
110  GetItemNameMethod get_item_name_fn;
111  // Retrieve the camelcase name of an item. Used by iterators on
112  // "by_camelcase_name" mappings.
113  GetItemCamelcaseNameMethod get_item_camelcase_name_fn;
114  // Retrieve the number of an item. Used by iterators on "by_number" mappings.
115  GetItemNumberMethod get_item_number_fn;
116  // Retrieve the index of an item for the container type.
117  // Used by "__contains__".
118  // If not set, "x in sequence" will do a linear search.
119  GetItemIndexMethod get_item_index_fn;
120};
121
122struct PyContainer {
123  PyObject_HEAD
124
125  // The proto2 descriptor this container belongs to the global DescriptorPool.
126  const void* descriptor;
127
128  // A pointer to a static structure with function pointers that control the
129  // behavior of the container. Very similar to the table of virtual functions
130  // of a C++ class.
131  const DescriptorContainerDef* container_def;
132
133  // The kind of container: list, or dict by name or value.
134  enum ContainerKind {
135    KIND_SEQUENCE,
136    KIND_BYNAME,
137    KIND_BYCAMELCASENAME,
138    KIND_BYNUMBER,
139  } kind;
140};
141
142struct PyContainerIterator {
143  PyObject_HEAD
144
145  // The container we are iterating over. Own a reference.
146  PyContainer* container;
147
148  // The current index in the iterator.
149  int index;
150
151  // The kind of container: list, or dict by name or value.
152  enum IterKind {
153    KIND_ITERKEY,
154    KIND_ITERVALUE,
155    KIND_ITERITEM,
156    KIND_ITERVALUE_REVERSED,  // For sequences
157  } kind;
158};
159
160namespace descriptor {
161
162// Returns the C++ item descriptor for a given Python key.
163// When the descriptor is found, return true and set *item.
164// When the descriptor is not found, return true, but set *item to NULL.
165// On error, returns false with an exception set.
166static bool _GetItemByKey(PyContainer* self, PyObject* key, const void** item) {
167  switch (self->kind) {
168    case PyContainer::KIND_BYNAME:
169      {
170        char* name;
171        Py_ssize_t name_size;
172        if (PyString_AsStringAndSize(key, &name, &name_size) < 0) {
173          if (PyErr_ExceptionMatches(PyExc_TypeError)) {
174            // Not a string, cannot be in the container.
175            PyErr_Clear();
176            *item = NULL;
177            return true;
178          }
179          return false;
180        }
181        *item = self->container_def->get_by_name_fn(
182            self, string(name, name_size));
183        return true;
184      }
185    case PyContainer::KIND_BYCAMELCASENAME:
186      {
187        char* camelcase_name;
188        Py_ssize_t name_size;
189        if (PyString_AsStringAndSize(key, &camelcase_name, &name_size) < 0) {
190          if (PyErr_ExceptionMatches(PyExc_TypeError)) {
191            // Not a string, cannot be in the container.
192            PyErr_Clear();
193            *item = NULL;
194            return true;
195          }
196          return false;
197        }
198        *item = self->container_def->get_by_camelcase_name_fn(
199            self, string(camelcase_name, name_size));
200        return true;
201      }
202    case PyContainer::KIND_BYNUMBER:
203      {
204        Py_ssize_t number = PyNumber_AsSsize_t(key, NULL);
205        if (number == -1 && PyErr_Occurred()) {
206          if (PyErr_ExceptionMatches(PyExc_TypeError)) {
207            // Not a number, cannot be in the container.
208            PyErr_Clear();
209            *item = NULL;
210            return true;
211          }
212          return false;
213        }
214        *item = self->container_def->get_by_number_fn(self, number);
215        return true;
216      }
217    default:
218      PyErr_SetNone(PyExc_NotImplementedError);
219      return false;
220  }
221}
222
223// Returns the key of the object at the given index.
224// Used when iterating over mappings.
225static PyObject* _NewKey_ByIndex(PyContainer* self, Py_ssize_t index) {
226  const void* item = self->container_def->get_by_index_fn(self, index);
227  switch (self->kind) {
228    case PyContainer::KIND_BYNAME:
229      {
230        const string& name(self->container_def->get_item_name_fn(item));
231        return PyString_FromStringAndSize(name.c_str(), name.size());
232      }
233    case PyContainer::KIND_BYCAMELCASENAME:
234      {
235        const string& name(
236            self->container_def->get_item_camelcase_name_fn(item));
237        return PyString_FromStringAndSize(name.c_str(), name.size());
238      }
239    case PyContainer::KIND_BYNUMBER:
240      {
241        int value = self->container_def->get_item_number_fn(item);
242        return PyInt_FromLong(value);
243      }
244    default:
245      PyErr_SetNone(PyExc_NotImplementedError);
246      return NULL;
247  }
248}
249
250// Returns the object at the given index.
251// Also used when iterating over mappings.
252static PyObject* _NewObj_ByIndex(PyContainer* self, Py_ssize_t index) {
253  return self->container_def->new_object_from_item_fn(
254      self->container_def->get_by_index_fn(self, index));
255}
256
257static Py_ssize_t Length(PyContainer* self) {
258  return self->container_def->count_fn(self);
259}
260
261// The DescriptorMapping type.
262
263static PyObject* Subscript(PyContainer* self, PyObject* key) {
264  const void* item = NULL;
265  if (!_GetItemByKey(self, key, &item)) {
266    return NULL;
267  }
268  if (!item) {
269    PyErr_SetObject(PyExc_KeyError, key);
270    return NULL;
271  }
272  return self->container_def->new_object_from_item_fn(item);
273}
274
275static int AssSubscript(PyContainer* self, PyObject* key, PyObject* value) {
276  if (_CalledFromGeneratedFile(0)) {
277    return 0;
278  }
279  PyErr_Format(PyExc_TypeError,
280               "'%.200s' object does not support item assignment",
281               Py_TYPE(self)->tp_name);
282  return -1;
283}
284
285static PyMappingMethods MappingMappingMethods = {
286  (lenfunc)Length,               // mp_length
287  (binaryfunc)Subscript,         // mp_subscript
288  (objobjargproc)AssSubscript,   // mp_ass_subscript
289};
290
291static int Contains(PyContainer* self, PyObject* key) {
292  const void* item = NULL;
293  if (!_GetItemByKey(self, key, &item)) {
294    return -1;
295  }
296  if (item) {
297    return 1;
298  } else {
299    return 0;
300  }
301}
302
303static PyObject* ContainerRepr(PyContainer* self) {
304  const char* kind = "";
305  switch (self->kind) {
306    case PyContainer::KIND_SEQUENCE:
307      kind = "sequence";
308      break;
309    case PyContainer::KIND_BYNAME:
310      kind = "mapping by name";
311      break;
312    case PyContainer::KIND_BYCAMELCASENAME:
313      kind = "mapping by camelCase name";
314      break;
315    case PyContainer::KIND_BYNUMBER:
316      kind = "mapping by number";
317      break;
318  }
319  return PyString_FromFormat(
320      "<%s %s>", self->container_def->mapping_name, kind);
321}
322
323extern PyTypeObject DescriptorMapping_Type;
324extern PyTypeObject DescriptorSequence_Type;
325
326// A sequence container can only be equal to another sequence container, or (for
327// backward compatibility) to a list containing the same items.
328// Returns 1 if equal, 0 if unequal, -1 on error.
329static int DescriptorSequence_Equal(PyContainer* self, PyObject* other) {
330  // Check the identity of C++ pointers.
331  if (PyObject_TypeCheck(other, &DescriptorSequence_Type)) {
332    PyContainer* other_container = reinterpret_cast<PyContainer*>(other);
333    if (self->descriptor == other_container->descriptor &&
334        self->container_def == other_container->container_def &&
335        self->kind == other_container->kind) {
336      return 1;
337    } else {
338      return 0;
339    }
340  }
341
342  // If other is a list
343  if (PyList_Check(other)) {
344    // return list(self) == other
345    int size = Length(self);
346    if (size != PyList_Size(other)) {
347      return false;
348    }
349    for (int index = 0; index < size; index++) {
350      ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index));
351      if (value1 == NULL) {
352        return -1;
353      }
354      PyObject* value2 = PyList_GetItem(other, index);
355      if (value2 == NULL) {
356        return -1;
357      }
358      int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ);
359      if (cmp != 1)  // error or not equal
360          return cmp;
361    }
362    // All items were found and equal
363    return 1;
364  }
365
366  // Any other object is different.
367  return 0;
368}
369
370// A mapping container can only be equal to another mapping container, or (for
371// backward compatibility) to a dict containing the same items.
372// Returns 1 if equal, 0 if unequal, -1 on error.
373static int DescriptorMapping_Equal(PyContainer* self, PyObject* other) {
374  // Check the identity of C++ pointers.
375  if (PyObject_TypeCheck(other, &DescriptorMapping_Type)) {
376    PyContainer* other_container = reinterpret_cast<PyContainer*>(other);
377    if (self->descriptor == other_container->descriptor &&
378        self->container_def == other_container->container_def &&
379        self->kind == other_container->kind) {
380      return 1;
381    } else {
382      return 0;
383    }
384  }
385
386  // If other is a dict
387  if (PyDict_Check(other)) {
388    // equivalent to dict(self.items()) == other
389    int size = Length(self);
390    if (size != PyDict_Size(other)) {
391      return false;
392    }
393    for (int index = 0; index < size; index++) {
394      ScopedPyObjectPtr key(_NewKey_ByIndex(self, index));
395      if (key == NULL) {
396        return -1;
397      }
398      ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index));
399      if (value1 == NULL) {
400        return -1;
401      }
402      PyObject* value2 = PyDict_GetItem(other, key.get());
403      if (value2 == NULL) {
404        // Not found in the other dictionary
405        return 0;
406      }
407      int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ);
408      if (cmp != 1)  // error or not equal
409          return cmp;
410    }
411    // All items were found and equal
412    return 1;
413  }
414
415  // Any other object is different.
416  return 0;
417}
418
419static PyObject* RichCompare(PyContainer* self, PyObject* other, int opid) {
420  if (opid != Py_EQ && opid != Py_NE) {
421    Py_INCREF(Py_NotImplemented);
422    return Py_NotImplemented;
423  }
424
425  int result;
426
427  if (self->kind == PyContainer::KIND_SEQUENCE) {
428    result = DescriptorSequence_Equal(self, other);
429  } else {
430    result = DescriptorMapping_Equal(self, other);
431  }
432  if (result < 0) {
433    return NULL;
434  }
435  if (result ^ (opid == Py_NE)) {
436    Py_RETURN_TRUE;
437  } else {
438    Py_RETURN_FALSE;
439  }
440}
441
442static PySequenceMethods MappingSequenceMethods = {
443    0,                      // sq_length
444    0,                      // sq_concat
445    0,                      // sq_repeat
446    0,                      // sq_item
447    0,                      // sq_slice
448    0,                      // sq_ass_item
449    0,                      // sq_ass_slice
450    (objobjproc)Contains,   // sq_contains
451};
452
453static PyObject* Get(PyContainer* self, PyObject* args) {
454  PyObject* key;
455  PyObject* default_value = Py_None;
456  if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_value)) {
457    return NULL;
458  }
459
460  const void* item;
461  if (!_GetItemByKey(self, key, &item)) {
462    return NULL;
463  }
464  if (item == NULL) {
465    Py_INCREF(default_value);
466    return default_value;
467  }
468  return self->container_def->new_object_from_item_fn(item);
469}
470
471static PyObject* Keys(PyContainer* self, PyObject* args) {
472  Py_ssize_t count = Length(self);
473  ScopedPyObjectPtr list(PyList_New(count));
474  if (list == NULL) {
475    return NULL;
476  }
477  for (Py_ssize_t index = 0; index < count; ++index) {
478    PyObject* key = _NewKey_ByIndex(self, index);
479    if (key == NULL) {
480      return NULL;
481    }
482    PyList_SET_ITEM(list.get(), index, key);
483  }
484  return list.release();
485}
486
487static PyObject* Values(PyContainer* self, PyObject* args) {
488  Py_ssize_t count = Length(self);
489  ScopedPyObjectPtr list(PyList_New(count));
490  if (list == NULL) {
491    return NULL;
492  }
493  for (Py_ssize_t index = 0; index < count; ++index) {
494    PyObject* value = _NewObj_ByIndex(self, index);
495    if (value == NULL) {
496      return NULL;
497    }
498    PyList_SET_ITEM(list.get(), index, value);
499  }
500  return list.release();
501}
502
503static PyObject* Items(PyContainer* self, PyObject* args) {
504  Py_ssize_t count = Length(self);
505  ScopedPyObjectPtr list(PyList_New(count));
506  if (list == NULL) {
507    return NULL;
508  }
509  for (Py_ssize_t index = 0; index < count; ++index) {
510    ScopedPyObjectPtr obj(PyTuple_New(2));
511    if (obj == NULL) {
512      return NULL;
513    }
514    PyObject* key = _NewKey_ByIndex(self, index);
515    if (key == NULL) {
516      return NULL;
517    }
518    PyTuple_SET_ITEM(obj.get(), 0, key);
519    PyObject* value = _NewObj_ByIndex(self, index);
520    if (value == NULL) {
521      return NULL;
522    }
523    PyTuple_SET_ITEM(obj.get(), 1, value);
524    PyList_SET_ITEM(list.get(), index, obj.release());
525  }
526  return list.release();
527}
528
529static PyObject* NewContainerIterator(PyContainer* mapping,
530                                      PyContainerIterator::IterKind kind);
531
532static PyObject* Iter(PyContainer* self) {
533  return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY);
534}
535static PyObject* IterKeys(PyContainer* self, PyObject* args) {
536  return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY);
537}
538static PyObject* IterValues(PyContainer* self, PyObject* args) {
539  return NewContainerIterator(self, PyContainerIterator::KIND_ITERVALUE);
540}
541static PyObject* IterItems(PyContainer* self, PyObject* args) {
542  return NewContainerIterator(self, PyContainerIterator::KIND_ITERITEM);
543}
544
545static PyMethodDef MappingMethods[] = {
546  { "get", (PyCFunction)Get, METH_VARARGS, },
547  { "keys", (PyCFunction)Keys, METH_NOARGS, },
548  { "values", (PyCFunction)Values, METH_NOARGS, },
549  { "items", (PyCFunction)Items, METH_NOARGS, },
550  { "iterkeys", (PyCFunction)IterKeys, METH_NOARGS, },
551  { "itervalues", (PyCFunction)IterValues, METH_NOARGS, },
552  { "iteritems", (PyCFunction)IterItems, METH_NOARGS, },
553  {NULL}
554};
555
556PyTypeObject DescriptorMapping_Type = {
557  PyVarObject_HEAD_INIT(&PyType_Type, 0)
558  "DescriptorMapping",                  // tp_name
559  sizeof(PyContainer),                  // tp_basicsize
560  0,                                    // tp_itemsize
561  0,                                    // tp_dealloc
562  0,                                    // tp_print
563  0,                                    // tp_getattr
564  0,                                    // tp_setattr
565  0,                                    // tp_compare
566  (reprfunc)ContainerRepr,              // tp_repr
567  0,                                    // tp_as_number
568  &MappingSequenceMethods,              // tp_as_sequence
569  &MappingMappingMethods,               // tp_as_mapping
570  0,                                    // tp_hash
571  0,                                    // tp_call
572  0,                                    // tp_str
573  0,                                    // tp_getattro
574  0,                                    // tp_setattro
575  0,                                    // tp_as_buffer
576  Py_TPFLAGS_DEFAULT,                   // tp_flags
577  0,                                    // tp_doc
578  0,                                    // tp_traverse
579  0,                                    // tp_clear
580  (richcmpfunc)RichCompare,             // tp_richcompare
581  0,                                    // tp_weaklistoffset
582  (getiterfunc)Iter,                    // tp_iter
583  0,                                    // tp_iternext
584  MappingMethods,                       // tp_methods
585  0,                                    // tp_members
586  0,                                    // tp_getset
587  0,                                    // tp_base
588  0,                                    // tp_dict
589  0,                                    // tp_descr_get
590  0,                                    // tp_descr_set
591  0,                                    // tp_dictoffset
592  0,                                    // tp_init
593  0,                                    // tp_alloc
594  0,                                    // tp_new
595  0,                                    // tp_free
596};
597
598// The DescriptorSequence type.
599
600static PyObject* GetItem(PyContainer* self, Py_ssize_t index) {
601  if (index < 0) {
602    index += Length(self);
603  }
604  if (index < 0 || index >= Length(self)) {
605    PyErr_SetString(PyExc_IndexError, "index out of range");
606    return NULL;
607  }
608  return _NewObj_ByIndex(self, index);
609}
610
611// Returns the position of the item in the sequence, of -1 if not found.
612// This function never fails.
613int Find(PyContainer* self, PyObject* item) {
614  // The item can only be in one position: item.index.
615  // Check that self[item.index] == item, it's faster than a linear search.
616  //
617  // This assumes that sequences are only defined by syntax of the .proto file:
618  // a specific item belongs to only one sequence, depending on its position in
619  // the .proto file definition.
620  const void* descriptor_ptr = PyDescriptor_AsVoidPtr(item);
621  if (descriptor_ptr == NULL) {
622    // Not a descriptor, it cannot be in the list.
623    return -1;
624  }
625  if (self->container_def->get_item_index_fn) {
626    int index = self->container_def->get_item_index_fn(descriptor_ptr);
627    if (index < 0 || index >= Length(self)) {
628      // This index is not from this collection.
629      return -1;
630    }
631    if (self->container_def->get_by_index_fn(self, index) != descriptor_ptr) {
632      // The descriptor at this index is not the same.
633      return -1;
634    }
635    // self[item.index] == item, so return the index.
636    return index;
637  } else {
638    // Fall back to linear search.
639    int length = Length(self);
640    for (int index=0; index < length; index++) {
641      if (self->container_def->get_by_index_fn(self, index) == descriptor_ptr) {
642        return index;
643      }
644    }
645    // Not found
646    return -1;
647  }
648}
649
650// Implements list.index(): the position of the item is in the sequence.
651static PyObject* Index(PyContainer* self, PyObject* item) {
652  int position = Find(self, item);
653  if (position < 0) {
654    // Not found
655    PyErr_SetNone(PyExc_ValueError);
656    return NULL;
657  } else {
658    return PyInt_FromLong(position);
659  }
660}
661// Implements "list.__contains__()": is the object in the sequence.
662static int SeqContains(PyContainer* self, PyObject* item) {
663  int position = Find(self, item);
664  if (position < 0) {
665    return 0;
666  } else {
667    return 1;
668  }
669}
670
671// Implements list.count(): number of occurrences of the item in the sequence.
672// An item can only appear once in a sequence. If it exists, return 1.
673static PyObject* Count(PyContainer* self, PyObject* item) {
674  int position = Find(self, item);
675  if (position < 0) {
676    return PyInt_FromLong(0);
677  } else {
678    return PyInt_FromLong(1);
679  }
680}
681
682static PyObject* Append(PyContainer* self, PyObject* args) {
683  if (_CalledFromGeneratedFile(0)) {
684    Py_RETURN_NONE;
685  }
686  PyErr_Format(PyExc_TypeError,
687               "'%.200s' object is not a mutable sequence",
688               Py_TYPE(self)->tp_name);
689  return NULL;
690}
691
692static PyObject* Reversed(PyContainer* self, PyObject* args) {
693  return NewContainerIterator(self,
694                              PyContainerIterator::KIND_ITERVALUE_REVERSED);
695}
696
697static PyMethodDef SeqMethods[] = {
698  { "index", (PyCFunction)Index, METH_O, },
699  { "count", (PyCFunction)Count, METH_O, },
700  { "append", (PyCFunction)Append, METH_O, },
701  { "__reversed__", (PyCFunction)Reversed, METH_NOARGS, },
702  {NULL}
703};
704
705static PySequenceMethods SeqSequenceMethods = {
706    (lenfunc)Length,          // sq_length
707    0,                        // sq_concat
708    0,                        // sq_repeat
709    (ssizeargfunc)GetItem,    // sq_item
710    0,                        // sq_slice
711    0,                        // sq_ass_item
712    0,                        // sq_ass_slice
713    (objobjproc)SeqContains,  // sq_contains
714};
715
716PyTypeObject DescriptorSequence_Type = {
717  PyVarObject_HEAD_INIT(&PyType_Type, 0)
718  "DescriptorSequence",                 // tp_name
719  sizeof(PyContainer),                  // tp_basicsize
720  0,                                    // tp_itemsize
721  0,                                    // tp_dealloc
722  0,                                    // tp_print
723  0,                                    // tp_getattr
724  0,                                    // tp_setattr
725  0,                                    // tp_compare
726  (reprfunc)ContainerRepr,              // tp_repr
727  0,                                    // tp_as_number
728  &SeqSequenceMethods,                  // tp_as_sequence
729  0,                                    // tp_as_mapping
730  0,                                    // tp_hash
731  0,                                    // tp_call
732  0,                                    // tp_str
733  0,                                    // tp_getattro
734  0,                                    // tp_setattro
735  0,                                    // tp_as_buffer
736  Py_TPFLAGS_DEFAULT,                   // tp_flags
737  0,                                    // tp_doc
738  0,                                    // tp_traverse
739  0,                                    // tp_clear
740  (richcmpfunc)RichCompare,             // tp_richcompare
741  0,                                    // tp_weaklistoffset
742  0,                                    // tp_iter
743  0,                                    // tp_iternext
744  SeqMethods,                           // tp_methods
745  0,                                    // tp_members
746  0,                                    // tp_getset
747  0,                                    // tp_base
748  0,                                    // tp_dict
749  0,                                    // tp_descr_get
750  0,                                    // tp_descr_set
751  0,                                    // tp_dictoffset
752  0,                                    // tp_init
753  0,                                    // tp_alloc
754  0,                                    // tp_new
755  0,                                    // tp_free
756};
757
758static PyObject* NewMappingByName(
759    DescriptorContainerDef* container_def, const void* descriptor) {
760  PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
761  if (self == NULL) {
762    return NULL;
763  }
764  self->descriptor = descriptor;
765  self->container_def = container_def;
766  self->kind = PyContainer::KIND_BYNAME;
767  return reinterpret_cast<PyObject*>(self);
768}
769
770static PyObject* NewMappingByCamelcaseName(
771    DescriptorContainerDef* container_def, const void* descriptor) {
772  PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
773  if (self == NULL) {
774    return NULL;
775  }
776  self->descriptor = descriptor;
777  self->container_def = container_def;
778  self->kind = PyContainer::KIND_BYCAMELCASENAME;
779  return reinterpret_cast<PyObject*>(self);
780}
781
782static PyObject* NewMappingByNumber(
783    DescriptorContainerDef* container_def, const void* descriptor) {
784  if (container_def->get_by_number_fn == NULL ||
785      container_def->get_item_number_fn == NULL) {
786    PyErr_SetNone(PyExc_NotImplementedError);
787    return NULL;
788  }
789  PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
790  if (self == NULL) {
791    return NULL;
792  }
793  self->descriptor = descriptor;
794  self->container_def = container_def;
795  self->kind = PyContainer::KIND_BYNUMBER;
796  return reinterpret_cast<PyObject*>(self);
797}
798
799static PyObject* NewSequence(
800    DescriptorContainerDef* container_def, const void* descriptor) {
801  PyContainer* self = PyObject_New(PyContainer, &DescriptorSequence_Type);
802  if (self == NULL) {
803    return NULL;
804  }
805  self->descriptor = descriptor;
806  self->container_def = container_def;
807  self->kind = PyContainer::KIND_SEQUENCE;
808  return reinterpret_cast<PyObject*>(self);
809}
810
811// Implement iterators over PyContainers.
812
813static void Iterator_Dealloc(PyContainerIterator* self) {
814  Py_CLEAR(self->container);
815  Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
816}
817
818static PyObject* Iterator_Next(PyContainerIterator* self) {
819  int count = self->container->container_def->count_fn(self->container);
820  if (self->index >= count) {
821    // Return NULL with no exception to indicate the end.
822    return NULL;
823  }
824  int index = self->index;
825  self->index += 1;
826  switch (self->kind) {
827    case PyContainerIterator::KIND_ITERKEY:
828      return _NewKey_ByIndex(self->container, index);
829    case PyContainerIterator::KIND_ITERVALUE:
830      return _NewObj_ByIndex(self->container, index);
831    case PyContainerIterator::KIND_ITERVALUE_REVERSED:
832      return _NewObj_ByIndex(self->container, count - index - 1);
833    case PyContainerIterator::KIND_ITERITEM:
834      {
835        PyObject* obj = PyTuple_New(2);
836        if (obj == NULL) {
837          return NULL;
838        }
839        PyObject* key = _NewKey_ByIndex(self->container, index);
840        if (key == NULL) {
841          Py_DECREF(obj);
842          return NULL;
843        }
844        PyTuple_SET_ITEM(obj, 0, key);
845        PyObject* value = _NewObj_ByIndex(self->container, index);
846        if (value == NULL) {
847          Py_DECREF(obj);
848          return NULL;
849        }
850        PyTuple_SET_ITEM(obj, 1, value);
851        return obj;
852      }
853    default:
854      PyErr_SetNone(PyExc_NotImplementedError);
855      return NULL;
856  }
857}
858
859static PyTypeObject ContainerIterator_Type = {
860  PyVarObject_HEAD_INIT(&PyType_Type, 0)
861  "DescriptorContainerIterator",        // tp_name
862  sizeof(PyContainerIterator),          // tp_basicsize
863  0,                                    // tp_itemsize
864  (destructor)Iterator_Dealloc,         // tp_dealloc
865  0,                                    // tp_print
866  0,                                    // tp_getattr
867  0,                                    // tp_setattr
868  0,                                    // tp_compare
869  0,                                    // tp_repr
870  0,                                    // tp_as_number
871  0,                                    // tp_as_sequence
872  0,                                    // tp_as_mapping
873  0,                                    // tp_hash
874  0,                                    // tp_call
875  0,                                    // tp_str
876  0,                                    // tp_getattro
877  0,                                    // tp_setattro
878  0,                                    // tp_as_buffer
879  Py_TPFLAGS_DEFAULT,                   // tp_flags
880  0,                                    // tp_doc
881  0,                                    // tp_traverse
882  0,                                    // tp_clear
883  0,                                    // tp_richcompare
884  0,                                    // tp_weaklistoffset
885  PyObject_SelfIter,                    // tp_iter
886  (iternextfunc)Iterator_Next,          // tp_iternext
887  0,                                    // tp_methods
888  0,                                    // tp_members
889  0,                                    // tp_getset
890  0,                                    // tp_base
891  0,                                    // tp_dict
892  0,                                    // tp_descr_get
893  0,                                    // tp_descr_set
894  0,                                    // tp_dictoffset
895  0,                                    // tp_init
896  0,                                    // tp_alloc
897  0,                                    // tp_new
898  0,                                    // tp_free
899};
900
901static PyObject* NewContainerIterator(PyContainer* container,
902                                      PyContainerIterator::IterKind kind) {
903  PyContainerIterator* self = PyObject_New(PyContainerIterator,
904                                           &ContainerIterator_Type);
905  if (self == NULL) {
906    return NULL;
907  }
908  Py_INCREF(container);
909  self->container = container;
910  self->kind = kind;
911  self->index = 0;
912
913  return reinterpret_cast<PyObject*>(self);
914}
915
916}  // namespace descriptor
917
918// Now define the real collections!
919
920namespace message_descriptor {
921
922typedef const Descriptor* ParentDescriptor;
923
924static ParentDescriptor GetDescriptor(PyContainer* self) {
925  return reinterpret_cast<ParentDescriptor>(self->descriptor);
926}
927
928namespace fields {
929
930typedef const FieldDescriptor* ItemDescriptor;
931
932static int Count(PyContainer* self) {
933  return GetDescriptor(self)->field_count();
934}
935
936static ItemDescriptor GetByName(PyContainer* self, const string& name) {
937  return GetDescriptor(self)->FindFieldByName(name);
938}
939
940static ItemDescriptor GetByCamelcaseName(PyContainer* self,
941                                         const string& name) {
942  return GetDescriptor(self)->FindFieldByCamelcaseName(name);
943}
944
945static ItemDescriptor GetByNumber(PyContainer* self, int number) {
946  return GetDescriptor(self)->FindFieldByNumber(number);
947}
948
949static ItemDescriptor GetByIndex(PyContainer* self, int index) {
950  return GetDescriptor(self)->field(index);
951}
952
953static PyObject* NewObjectFromItem(ItemDescriptor item) {
954  return PyFieldDescriptor_FromDescriptor(item);
955}
956
957static const string& GetItemName(ItemDescriptor item) {
958  return item->name();
959}
960
961static const string& GetItemCamelcaseName(ItemDescriptor item) {
962  return item->camelcase_name();
963}
964
965static int GetItemNumber(ItemDescriptor item) {
966  return item->number();
967}
968
969static int GetItemIndex(ItemDescriptor item) {
970  return item->index();
971}
972
973static DescriptorContainerDef ContainerDef = {
974  "MessageFields",
975  (CountMethod)Count,
976  (GetByIndexMethod)GetByIndex,
977  (GetByNameMethod)GetByName,
978  (GetByCamelcaseNameMethod)GetByCamelcaseName,
979  (GetByNumberMethod)GetByNumber,
980  (NewObjectFromItemMethod)NewObjectFromItem,
981  (GetItemNameMethod)GetItemName,
982  (GetItemCamelcaseNameMethod)GetItemCamelcaseName,
983  (GetItemNumberMethod)GetItemNumber,
984  (GetItemIndexMethod)GetItemIndex,
985};
986
987}  // namespace fields
988
989PyObject* NewMessageFieldsByName(ParentDescriptor descriptor) {
990  return descriptor::NewMappingByName(&fields::ContainerDef, descriptor);
991}
992
993PyObject* NewMessageFieldsByCamelcaseName(ParentDescriptor descriptor) {
994  return descriptor::NewMappingByCamelcaseName(&fields::ContainerDef,
995                                               descriptor);
996}
997
998PyObject* NewMessageFieldsByNumber(ParentDescriptor descriptor) {
999  return descriptor::NewMappingByNumber(&fields::ContainerDef, descriptor);
1000}
1001
1002PyObject* NewMessageFieldsSeq(ParentDescriptor descriptor) {
1003  return descriptor::NewSequence(&fields::ContainerDef, descriptor);
1004}
1005
1006namespace nested_types {
1007
1008typedef const Descriptor* ItemDescriptor;
1009
1010static int Count(PyContainer* self) {
1011  return GetDescriptor(self)->nested_type_count();
1012}
1013
1014static ItemDescriptor GetByName(PyContainer* self, const string& name) {
1015  return GetDescriptor(self)->FindNestedTypeByName(name);
1016}
1017
1018static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1019  return GetDescriptor(self)->nested_type(index);
1020}
1021
1022static PyObject* NewObjectFromItem(ItemDescriptor item) {
1023  return PyMessageDescriptor_FromDescriptor(item);
1024}
1025
1026static const string& GetItemName(ItemDescriptor item) {
1027  return item->name();
1028}
1029
1030static int GetItemIndex(ItemDescriptor item) {
1031  return item->index();
1032}
1033
1034static DescriptorContainerDef ContainerDef = {
1035  "MessageNestedTypes",
1036  (CountMethod)Count,
1037  (GetByIndexMethod)GetByIndex,
1038  (GetByNameMethod)GetByName,
1039  (GetByCamelcaseNameMethod)NULL,
1040  (GetByNumberMethod)NULL,
1041  (NewObjectFromItemMethod)NewObjectFromItem,
1042  (GetItemNameMethod)GetItemName,
1043  (GetItemCamelcaseNameMethod)NULL,
1044  (GetItemNumberMethod)NULL,
1045  (GetItemIndexMethod)GetItemIndex,
1046};
1047
1048}  // namespace nested_types
1049
1050PyObject* NewMessageNestedTypesSeq(ParentDescriptor descriptor) {
1051  return descriptor::NewSequence(&nested_types::ContainerDef, descriptor);
1052}
1053
1054PyObject* NewMessageNestedTypesByName(ParentDescriptor descriptor) {
1055  return descriptor::NewMappingByName(&nested_types::ContainerDef, descriptor);
1056}
1057
1058namespace enums {
1059
1060typedef const EnumDescriptor* ItemDescriptor;
1061
1062static int Count(PyContainer* self) {
1063  return GetDescriptor(self)->enum_type_count();
1064}
1065
1066static ItemDescriptor GetByName(PyContainer* self, const string& name) {
1067  return GetDescriptor(self)->FindEnumTypeByName(name);
1068}
1069
1070static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1071  return GetDescriptor(self)->enum_type(index);
1072}
1073
1074static PyObject* NewObjectFromItem(ItemDescriptor item) {
1075  return PyEnumDescriptor_FromDescriptor(item);
1076}
1077
1078static const string& GetItemName(ItemDescriptor item) {
1079  return item->name();
1080}
1081
1082static int GetItemIndex(ItemDescriptor item) {
1083  return item->index();
1084}
1085
1086static DescriptorContainerDef ContainerDef = {
1087  "MessageNestedEnums",
1088  (CountMethod)Count,
1089  (GetByIndexMethod)GetByIndex,
1090  (GetByNameMethod)GetByName,
1091  (GetByCamelcaseNameMethod)NULL,
1092  (GetByNumberMethod)NULL,
1093  (NewObjectFromItemMethod)NewObjectFromItem,
1094  (GetItemNameMethod)GetItemName,
1095  (GetItemCamelcaseNameMethod)NULL,
1096  (GetItemNumberMethod)NULL,
1097  (GetItemIndexMethod)GetItemIndex,
1098};
1099
1100}  // namespace enums
1101
1102PyObject* NewMessageEnumsByName(ParentDescriptor descriptor) {
1103  return descriptor::NewMappingByName(&enums::ContainerDef, descriptor);
1104}
1105
1106PyObject* NewMessageEnumsSeq(ParentDescriptor descriptor) {
1107  return descriptor::NewSequence(&enums::ContainerDef, descriptor);
1108}
1109
1110namespace enumvalues {
1111
1112// This is the "enum_values_by_name" mapping, which collects values from all
1113// enum types in a message.
1114//
1115// Note that the behavior of the C++ descriptor is different: it will search and
1116// return the first value that matches the name, whereas the Python
1117// implementation retrieves the last one.
1118
1119typedef const EnumValueDescriptor* ItemDescriptor;
1120
1121static int Count(PyContainer* self) {
1122  int count = 0;
1123  for (int i = 0; i < GetDescriptor(self)->enum_type_count(); ++i) {
1124    count += GetDescriptor(self)->enum_type(i)->value_count();
1125  }
1126  return count;
1127}
1128
1129static ItemDescriptor GetByName(PyContainer* self, const string& name) {
1130  return GetDescriptor(self)->FindEnumValueByName(name);
1131}
1132
1133static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1134  // This is not optimal, but the number of enums *types* in a given message
1135  // is small.  This function is only used when iterating over the mapping.
1136  const EnumDescriptor* enum_type = NULL;
1137  int enum_type_count = GetDescriptor(self)->enum_type_count();
1138  for (int i = 0; i < enum_type_count; ++i) {
1139    enum_type = GetDescriptor(self)->enum_type(i);
1140    int enum_value_count = enum_type->value_count();
1141    if (index < enum_value_count) {
1142      // Found it!
1143      break;
1144    }
1145    index -= enum_value_count;
1146  }
1147  // The next statement cannot overflow, because this function is only called by
1148  // internal iterators which ensure that 0 <= index < Count().
1149  return enum_type->value(index);
1150}
1151
1152static PyObject* NewObjectFromItem(ItemDescriptor item) {
1153  return PyEnumValueDescriptor_FromDescriptor(item);
1154}
1155
1156static const string& GetItemName(ItemDescriptor item) {
1157  return item->name();
1158}
1159
1160static DescriptorContainerDef ContainerDef = {
1161  "MessageEnumValues",
1162  (CountMethod)Count,
1163  (GetByIndexMethod)GetByIndex,
1164  (GetByNameMethod)GetByName,
1165  (GetByCamelcaseNameMethod)NULL,
1166  (GetByNumberMethod)NULL,
1167  (NewObjectFromItemMethod)NewObjectFromItem,
1168  (GetItemNameMethod)GetItemName,
1169  (GetItemCamelcaseNameMethod)NULL,
1170  (GetItemNumberMethod)NULL,
1171  (GetItemIndexMethod)NULL,
1172};
1173
1174}  // namespace enumvalues
1175
1176PyObject* NewMessageEnumValuesByName(ParentDescriptor descriptor) {
1177  return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor);
1178}
1179
1180namespace extensions {
1181
1182typedef const FieldDescriptor* ItemDescriptor;
1183
1184static int Count(PyContainer* self) {
1185  return GetDescriptor(self)->extension_count();
1186}
1187
1188static ItemDescriptor GetByName(PyContainer* self, const string& name) {
1189  return GetDescriptor(self)->FindExtensionByName(name);
1190}
1191
1192static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1193  return GetDescriptor(self)->extension(index);
1194}
1195
1196static PyObject* NewObjectFromItem(ItemDescriptor item) {
1197  return PyFieldDescriptor_FromDescriptor(item);
1198}
1199
1200static const string& GetItemName(ItemDescriptor item) {
1201  return item->name();
1202}
1203
1204static int GetItemIndex(ItemDescriptor item) {
1205  return item->index();
1206}
1207
1208static DescriptorContainerDef ContainerDef = {
1209  "MessageExtensions",
1210  (CountMethod)Count,
1211  (GetByIndexMethod)GetByIndex,
1212  (GetByNameMethod)GetByName,
1213  (GetByCamelcaseNameMethod)NULL,
1214  (GetByNumberMethod)NULL,
1215  (NewObjectFromItemMethod)NewObjectFromItem,
1216  (GetItemNameMethod)GetItemName,
1217  (GetItemCamelcaseNameMethod)NULL,
1218  (GetItemNumberMethod)NULL,
1219  (GetItemIndexMethod)GetItemIndex,
1220};
1221
1222}  // namespace extensions
1223
1224PyObject* NewMessageExtensionsByName(ParentDescriptor descriptor) {
1225  return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor);
1226}
1227
1228PyObject* NewMessageExtensionsSeq(ParentDescriptor descriptor) {
1229  return descriptor::NewSequence(&extensions::ContainerDef, descriptor);
1230}
1231
1232namespace oneofs {
1233
1234typedef const OneofDescriptor* ItemDescriptor;
1235
1236static int Count(PyContainer* self) {
1237  return GetDescriptor(self)->oneof_decl_count();
1238}
1239
1240static ItemDescriptor GetByName(PyContainer* self, const string& name) {
1241  return GetDescriptor(self)->FindOneofByName(name);
1242}
1243
1244static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1245  return GetDescriptor(self)->oneof_decl(index);
1246}
1247
1248static PyObject* NewObjectFromItem(ItemDescriptor item) {
1249  return PyOneofDescriptor_FromDescriptor(item);
1250}
1251
1252static const string& GetItemName(ItemDescriptor item) {
1253  return item->name();
1254}
1255
1256static int GetItemIndex(ItemDescriptor item) {
1257  return item->index();
1258}
1259
1260static DescriptorContainerDef ContainerDef = {
1261  "MessageOneofs",
1262  (CountMethod)Count,
1263  (GetByIndexMethod)GetByIndex,
1264  (GetByNameMethod)GetByName,
1265  (GetByCamelcaseNameMethod)NULL,
1266  (GetByNumberMethod)NULL,
1267  (NewObjectFromItemMethod)NewObjectFromItem,
1268  (GetItemNameMethod)GetItemName,
1269  (GetItemCamelcaseNameMethod)NULL,
1270  (GetItemNumberMethod)NULL,
1271  (GetItemIndexMethod)GetItemIndex,
1272};
1273
1274}  // namespace oneofs
1275
1276PyObject* NewMessageOneofsByName(ParentDescriptor descriptor) {
1277  return descriptor::NewMappingByName(&oneofs::ContainerDef, descriptor);
1278}
1279
1280PyObject* NewMessageOneofsSeq(ParentDescriptor descriptor) {
1281  return descriptor::NewSequence(&oneofs::ContainerDef, descriptor);
1282}
1283
1284}  // namespace message_descriptor
1285
1286namespace enum_descriptor {
1287
1288typedef const EnumDescriptor* ParentDescriptor;
1289
1290static ParentDescriptor GetDescriptor(PyContainer* self) {
1291  return reinterpret_cast<ParentDescriptor>(self->descriptor);
1292}
1293
1294namespace enumvalues {
1295
1296typedef const EnumValueDescriptor* ItemDescriptor;
1297
1298static int Count(PyContainer* self) {
1299  return GetDescriptor(self)->value_count();
1300}
1301
1302static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1303  return GetDescriptor(self)->value(index);
1304}
1305
1306static ItemDescriptor GetByName(PyContainer* self, const string& name) {
1307  return GetDescriptor(self)->FindValueByName(name);
1308}
1309
1310static ItemDescriptor GetByNumber(PyContainer* self, int number) {
1311  return GetDescriptor(self)->FindValueByNumber(number);
1312}
1313
1314static PyObject* NewObjectFromItem(ItemDescriptor item) {
1315  return PyEnumValueDescriptor_FromDescriptor(item);
1316}
1317
1318static const string& GetItemName(ItemDescriptor item) {
1319  return item->name();
1320}
1321
1322static int GetItemNumber(ItemDescriptor item) {
1323  return item->number();
1324}
1325
1326static int GetItemIndex(ItemDescriptor item) {
1327  return item->index();
1328}
1329
1330static DescriptorContainerDef ContainerDef = {
1331  "EnumValues",
1332  (CountMethod)Count,
1333  (GetByIndexMethod)GetByIndex,
1334  (GetByNameMethod)GetByName,
1335  (GetByCamelcaseNameMethod)NULL,
1336  (GetByNumberMethod)GetByNumber,
1337  (NewObjectFromItemMethod)NewObjectFromItem,
1338  (GetItemNameMethod)GetItemName,
1339  (GetItemCamelcaseNameMethod)NULL,
1340  (GetItemNumberMethod)GetItemNumber,
1341  (GetItemIndexMethod)GetItemIndex,
1342};
1343
1344}  // namespace enumvalues
1345
1346PyObject* NewEnumValuesByName(ParentDescriptor descriptor) {
1347  return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor);
1348}
1349
1350PyObject* NewEnumValuesByNumber(ParentDescriptor descriptor) {
1351  return descriptor::NewMappingByNumber(&enumvalues::ContainerDef, descriptor);
1352}
1353
1354PyObject* NewEnumValuesSeq(ParentDescriptor descriptor) {
1355  return descriptor::NewSequence(&enumvalues::ContainerDef, descriptor);
1356}
1357
1358}  // namespace enum_descriptor
1359
1360namespace oneof_descriptor {
1361
1362typedef const OneofDescriptor* ParentDescriptor;
1363
1364static ParentDescriptor GetDescriptor(PyContainer* self) {
1365  return reinterpret_cast<ParentDescriptor>(self->descriptor);
1366}
1367
1368namespace fields {
1369
1370typedef const FieldDescriptor* ItemDescriptor;
1371
1372static int Count(PyContainer* self) {
1373  return GetDescriptor(self)->field_count();
1374}
1375
1376static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1377  return GetDescriptor(self)->field(index);
1378}
1379
1380static PyObject* NewObjectFromItem(ItemDescriptor item) {
1381  return PyFieldDescriptor_FromDescriptor(item);
1382}
1383
1384static int GetItemIndex(ItemDescriptor item) {
1385  return item->index_in_oneof();
1386}
1387
1388static DescriptorContainerDef ContainerDef = {
1389  "OneofFields",
1390  (CountMethod)Count,
1391  (GetByIndexMethod)GetByIndex,
1392  (GetByNameMethod)NULL,
1393  (GetByCamelcaseNameMethod)NULL,
1394  (GetByNumberMethod)NULL,
1395  (NewObjectFromItemMethod)NewObjectFromItem,
1396  (GetItemNameMethod)NULL,
1397  (GetItemCamelcaseNameMethod)NULL,
1398  (GetItemNumberMethod)NULL,
1399  (GetItemIndexMethod)GetItemIndex,
1400};
1401
1402}  // namespace fields
1403
1404PyObject* NewOneofFieldsSeq(ParentDescriptor descriptor) {
1405  return descriptor::NewSequence(&fields::ContainerDef, descriptor);
1406}
1407
1408}  // namespace oneof_descriptor
1409
1410namespace file_descriptor {
1411
1412typedef const FileDescriptor* ParentDescriptor;
1413
1414static ParentDescriptor GetDescriptor(PyContainer* self) {
1415  return reinterpret_cast<ParentDescriptor>(self->descriptor);
1416}
1417
1418namespace messages {
1419
1420typedef const Descriptor* ItemDescriptor;
1421
1422static int Count(PyContainer* self) {
1423  return GetDescriptor(self)->message_type_count();
1424}
1425
1426static ItemDescriptor GetByName(PyContainer* self, const string& name) {
1427  return GetDescriptor(self)->FindMessageTypeByName(name);
1428}
1429
1430static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1431  return GetDescriptor(self)->message_type(index);
1432}
1433
1434static PyObject* NewObjectFromItem(ItemDescriptor item) {
1435  return PyMessageDescriptor_FromDescriptor(item);
1436}
1437
1438static const string& GetItemName(ItemDescriptor item) {
1439  return item->name();
1440}
1441
1442static int GetItemIndex(ItemDescriptor item) {
1443  return item->index();
1444}
1445
1446static DescriptorContainerDef ContainerDef = {
1447  "FileMessages",
1448  (CountMethod)Count,
1449  (GetByIndexMethod)GetByIndex,
1450  (GetByNameMethod)GetByName,
1451  (GetByCamelcaseNameMethod)NULL,
1452  (GetByNumberMethod)NULL,
1453  (NewObjectFromItemMethod)NewObjectFromItem,
1454  (GetItemNameMethod)GetItemName,
1455  (GetItemCamelcaseNameMethod)NULL,
1456  (GetItemNumberMethod)NULL,
1457  (GetItemIndexMethod)GetItemIndex,
1458};
1459
1460}  // namespace messages
1461
1462PyObject* NewFileMessageTypesByName(const FileDescriptor* descriptor) {
1463  return descriptor::NewMappingByName(&messages::ContainerDef, descriptor);
1464}
1465
1466namespace enums {
1467
1468typedef const EnumDescriptor* ItemDescriptor;
1469
1470static int Count(PyContainer* self) {
1471  return GetDescriptor(self)->enum_type_count();
1472}
1473
1474static ItemDescriptor GetByName(PyContainer* self, const string& name) {
1475  return GetDescriptor(self)->FindEnumTypeByName(name);
1476}
1477
1478static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1479  return GetDescriptor(self)->enum_type(index);
1480}
1481
1482static PyObject* NewObjectFromItem(ItemDescriptor item) {
1483  return PyEnumDescriptor_FromDescriptor(item);
1484}
1485
1486static const string& GetItemName(ItemDescriptor item) {
1487  return item->name();
1488}
1489
1490static int GetItemIndex(ItemDescriptor item) {
1491  return item->index();
1492}
1493
1494static DescriptorContainerDef ContainerDef = {
1495  "FileEnums",
1496  (CountMethod)Count,
1497  (GetByIndexMethod)GetByIndex,
1498  (GetByNameMethod)GetByName,
1499  (GetByCamelcaseNameMethod)NULL,
1500  (GetByNumberMethod)NULL,
1501  (NewObjectFromItemMethod)NewObjectFromItem,
1502  (GetItemNameMethod)GetItemName,
1503  (GetItemCamelcaseNameMethod)NULL,
1504  (GetItemNumberMethod)NULL,
1505  (GetItemIndexMethod)GetItemIndex,
1506};
1507
1508}  // namespace enums
1509
1510PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor) {
1511  return descriptor::NewMappingByName(&enums::ContainerDef, descriptor);
1512}
1513
1514namespace extensions {
1515
1516typedef const FieldDescriptor* ItemDescriptor;
1517
1518static int Count(PyContainer* self) {
1519  return GetDescriptor(self)->extension_count();
1520}
1521
1522static ItemDescriptor GetByName(PyContainer* self, const string& name) {
1523  return GetDescriptor(self)->FindExtensionByName(name);
1524}
1525
1526static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1527  return GetDescriptor(self)->extension(index);
1528}
1529
1530static PyObject* NewObjectFromItem(ItemDescriptor item) {
1531  return PyFieldDescriptor_FromDescriptor(item);
1532}
1533
1534static const string& GetItemName(ItemDescriptor item) {
1535  return item->name();
1536}
1537
1538static int GetItemIndex(ItemDescriptor item) {
1539  return item->index();
1540}
1541
1542static DescriptorContainerDef ContainerDef = {
1543  "FileExtensions",
1544  (CountMethod)Count,
1545  (GetByIndexMethod)GetByIndex,
1546  (GetByNameMethod)GetByName,
1547  (GetByCamelcaseNameMethod)NULL,
1548  (GetByNumberMethod)NULL,
1549  (NewObjectFromItemMethod)NewObjectFromItem,
1550  (GetItemNameMethod)GetItemName,
1551  (GetItemCamelcaseNameMethod)NULL,
1552  (GetItemNumberMethod)NULL,
1553  (GetItemIndexMethod)GetItemIndex,
1554};
1555
1556}  // namespace extensions
1557
1558PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor) {
1559  return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor);
1560}
1561
1562namespace dependencies {
1563
1564typedef const FileDescriptor* ItemDescriptor;
1565
1566static int Count(PyContainer* self) {
1567  return GetDescriptor(self)->dependency_count();
1568}
1569
1570static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1571  return GetDescriptor(self)->dependency(index);
1572}
1573
1574static PyObject* NewObjectFromItem(ItemDescriptor item) {
1575  return PyFileDescriptor_FromDescriptor(item);
1576}
1577
1578static DescriptorContainerDef ContainerDef = {
1579  "FileDependencies",
1580  (CountMethod)Count,
1581  (GetByIndexMethod)GetByIndex,
1582  (GetByNameMethod)NULL,
1583  (GetByCamelcaseNameMethod)NULL,
1584  (GetByNumberMethod)NULL,
1585  (NewObjectFromItemMethod)NewObjectFromItem,
1586  (GetItemNameMethod)NULL,
1587  (GetItemCamelcaseNameMethod)NULL,
1588  (GetItemNumberMethod)NULL,
1589  (GetItemIndexMethod)NULL,
1590};
1591
1592}  // namespace dependencies
1593
1594PyObject* NewFileDependencies(const FileDescriptor* descriptor) {
1595  return descriptor::NewSequence(&dependencies::ContainerDef, descriptor);
1596}
1597
1598namespace public_dependencies {
1599
1600typedef const FileDescriptor* ItemDescriptor;
1601
1602static int Count(PyContainer* self) {
1603  return GetDescriptor(self)->public_dependency_count();
1604}
1605
1606static ItemDescriptor GetByIndex(PyContainer* self, int index) {
1607  return GetDescriptor(self)->public_dependency(index);
1608}
1609
1610static PyObject* NewObjectFromItem(ItemDescriptor item) {
1611  return PyFileDescriptor_FromDescriptor(item);
1612}
1613
1614static DescriptorContainerDef ContainerDef = {
1615  "FilePublicDependencies",
1616  (CountMethod)Count,
1617  (GetByIndexMethod)GetByIndex,
1618  (GetByNameMethod)NULL,
1619  (GetByCamelcaseNameMethod)NULL,
1620  (GetByNumberMethod)NULL,
1621  (NewObjectFromItemMethod)NewObjectFromItem,
1622  (GetItemNameMethod)NULL,
1623  (GetItemCamelcaseNameMethod)NULL,
1624  (GetItemNumberMethod)NULL,
1625  (GetItemIndexMethod)NULL,
1626};
1627
1628}  // namespace public_dependencies
1629
1630PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor) {
1631  return descriptor::NewSequence(&public_dependencies::ContainerDef,
1632                                 descriptor);
1633}
1634
1635}  // namespace file_descriptor
1636
1637
1638// Register all implementations
1639
1640bool InitDescriptorMappingTypes() {
1641  if (PyType_Ready(&descriptor::DescriptorMapping_Type) < 0)
1642    return false;
1643  if (PyType_Ready(&descriptor::DescriptorSequence_Type) < 0)
1644    return false;
1645  if (PyType_Ready(&descriptor::ContainerIterator_Type) < 0)
1646    return false;
1647  return true;
1648}
1649
1650}  // namespace python
1651}  // namespace protobuf
1652}  // namespace google
1653