Initial commit of Python+upb.
diff --git a/python/descriptor_pool.c b/python/descriptor_pool.c
new file mode 100644
index 0000000..8dbae53
--- /dev/null
+++ b/python/descriptor_pool.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2009-2021, Google LLC
+ * All rights reserved.
+ *
+ * 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 LLC 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 Google LLC BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "python/descriptor_pool.h"
+
+#include "python/descriptor.h"
+#include "python/protobuf.h"
+#include "upb/def.h"
+
+// -----------------------------------------------------------------------------
+// DescriptorPool
+// -----------------------------------------------------------------------------
+
+typedef struct {
+ PyObject_HEAD
+ upb_symtab* symtab;
+ PyObject* db;
+} PyUpb_DescriptorPool;
+
+static PyObject* PyUpb_DescriptorPool_DoCreate(PyTypeObject* type, PyObject* db) {
+ PyUpb_DescriptorPool* pool = PyObject_New(PyUpb_DescriptorPool, type);
+ pool->symtab = upb_symtab_new();
+ pool->db = db;
+ return &pool->ob_base;
+}
+
+static void PyUpb_DescriptorPool_Dealloc(PyUpb_DescriptorPool *self) {
+ upb_symtab_free(self->symtab);
+ Py_CLEAR(self->db);
+ PyObject_Del(self);
+}
+
+/*
+ * DescriptorPool.__new__()
+ *
+ * Implements:
+ * DescriptorPool(descriptor_db=None)
+ */
+static PyObject* PyUpb_DescriptorPool_New(PyTypeObject* type, PyObject* args,
+ PyObject* kwargs) {
+ char* kwlist[] = {"descriptor_db", 0};
+ PyObject* db = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &db)) {
+ return NULL;
+ }
+
+ return PyUpb_DescriptorPool_DoCreate(type, db);
+}
+
+/*
+ * PyUpb_DescriptorPool_AddSerializedFile()
+ *
+ * Implements:
+ * DescriptorPool.AddSerializedFile(self, serialized_file_descriptor)
+ *
+ * Adds the given serialized FileDescriptorProto to the pool.
+ */
+static PyObject* PyUpb_DescriptorPool_AddSerializedFile(
+ PyObject* _self, PyObject* serialized_pb) {
+ PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+ char* buf;
+ Py_ssize_t size;
+ upb_arena* arena = upb_arena_new();
+ PyObject* result = NULL;
+
+ if (self->db) {
+ PyErr_SetString(
+ PyExc_ValueError,
+ "Cannot call Add on a DescriptorPool that uses a DescriptorDatabase. "
+ "Add your file to the underlying database.");
+ return NULL;
+ }
+
+ if (PyBytes_AsStringAndSize(serialized_pb, &buf, &size) < 0) {
+ goto done;
+ }
+
+ google_protobuf_FileDescriptorProto* proto =
+ google_protobuf_FileDescriptorProto_parse(buf, size, arena);
+ if (!proto) {
+ PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
+ return NULL;
+ }
+
+ upb_status status;
+ upb_status_clear(&status);
+
+ const upb_filedef* filedef = upb_symtab_addfile(self->symtab, proto, &status);
+ if (!filedef) {
+ PyErr_Format(PyExc_TypeError,
+ "Couldn't build proto file into descriptor pool: %s",
+ upb_status_errmsg(&status));
+ return NULL;
+ }
+
+ result = PyUpb_FileDescriptor_GetOrCreateWrapper(filedef, _self);
+
+done:
+ upb_arena_free(arena);
+ return result;
+}
+
+/*
+ * PyUpb_DescriptorPool_FindExtensionByName()
+ *
+ * Implements:
+ * DescriptorPool.FindExtensionByName(self, name)
+ */
+static PyObject* PyUpb_DescriptorPool_FindExtensionByName(PyObject* _self,
+ PyObject* arg) {
+ PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+
+ const char* name = PyUpb_GetStrData(arg);
+ if (!name) {
+ return NULL;
+ }
+
+ const upb_fielddef* field = upb_symtab_lookupext(self->symtab, name);
+ if (field == NULL) {
+ return PyErr_Format(PyExc_KeyError, "Couldn't find extension %.200s", name);
+ }
+
+ return PyUpb_FieldDescriptor_GetOrCreateWrapper(field, _self);
+}
+
+static PyMethodDef PyUpb_DescriptorPool_Methods[] = {
+ /*
+ TODO: implement remaining methods.
+ { "Add", Add, METH_O,
+ "Adds the FileDescriptorProto and its types to this pool." },
+ */
+ {"AddSerializedFile", PyUpb_DescriptorPool_AddSerializedFile, METH_O,
+ "Adds a serialized FileDescriptorProto to this pool."},
+ /*
+ { "FindFileByName", FindFileByName, METH_O,
+ "Searches for a file descriptor by its .proto name." },
+ { "FindMessageTypeByName", FindMessageByName, METH_O,
+ "Searches for a message descriptor by full name." },
+ { "FindFieldByName", FindFieldByNameMethod, METH_O,
+ "Searches for a field descriptor by full name." },
+ */
+ {"FindExtensionByName", PyUpb_DescriptorPool_FindExtensionByName, METH_O,
+ "Searches for extension descriptor by full name."},
+ /*
+ { "FindEnumTypeByName", FindEnumTypeByNameMethod, METH_O,
+ "Searches for enum type descriptor by full name." },
+ { "FindOneofByName", FindOneofByNameMethod, METH_O,
+ "Searches for oneof descriptor by full name." },
+ { "FindServiceByName", FindServiceByName, METH_O,
+ "Searches for service descriptor by full name." },
+ { "FindMethodByName", FindMethodByName, METH_O,
+ "Searches for method descriptor by full name." },
+ { "FindFileContainingSymbol", FindFileContainingSymbol, METH_O,
+ "Gets the FileDescriptor containing the specified symbol." },
+ { "FindExtensionByNumber", FindExtensionByNumber, METH_VARARGS,
+ "Gets the extension descriptor for the given number." },
+ { "FindAllExtensions", FindAllExtensions, METH_O,
+ "Gets all known extensions of the given message descriptor." },
+ */
+ {NULL}};
+
+static PyType_Slot PyUpb_DescriptorPool_Slots[] = {
+ {Py_tp_new, PyUpb_DescriptorPool_New},
+ {Py_tp_dealloc, PyUpb_DescriptorPool_Dealloc},
+ {Py_tp_methods, PyUpb_DescriptorPool_Methods},
+ {0, NULL}};
+
+static PyType_Spec PyUpb_DescriptorPool_Spec = {
+ PYUPB_MODULE_NAME ".DescriptorPool", // tp_name
+ sizeof(PyUpb_DescriptorPool), // tp_basicsize
+ 0, // tp_itemsize
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ PyUpb_DescriptorPool_Slots,
+};
+
+// -----------------------------------------------------------------------------
+// Top Level
+// -----------------------------------------------------------------------------
+
+bool PyUpb_InitDescriptorPool(PyObject* m) {
+ PyTypeObject* descriptor_pool_type =
+ AddObject(m, "DescriptorPool", &PyUpb_DescriptorPool_Spec);
+
+ if (!descriptor_pool_type) return false;
+
+ PyObject* default_pool =
+ PyUpb_DescriptorPool_DoCreate(descriptor_pool_type, NULL);
+ return default_pool &&
+ PyModule_AddObject(m, "default_pool", default_pool) == 0;
+}