blob: 7a394031949b7dd0bdabbb11febb4af37686b06d [file] [log] [blame]
Joshua Haberman94ece042021-08-18 12:38:26 -07001/*
2 * Copyright (c) 2009-2021, Google LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Google LLC nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "python/descriptor_pool.h"
29
Joshua Haberman8f0a2cd2022-01-07 17:43:53 -080030#include "python/convert.h"
Joshua Haberman94ece042021-08-18 12:38:26 -070031#include "python/descriptor.h"
Joshua Haberman55e5da52021-12-28 21:42:50 -080032#include "python/message.h"
Joshua Haberman94ece042021-08-18 12:38:26 -070033#include "python/protobuf.h"
34#include "upb/def.h"
Joshua Haberman8f0a2cd2022-01-07 17:43:53 -080035#include "upb/util/def_to_proto.h"
36#include "google/protobuf/descriptor.upbdefs.h"
Joshua Haberman94ece042021-08-18 12:38:26 -070037
38// -----------------------------------------------------------------------------
39// DescriptorPool
40// -----------------------------------------------------------------------------
41
42typedef struct {
43 PyObject_HEAD
44 upb_symtab* symtab;
Joshua Habermancc9b4862021-12-29 11:48:23 -080045 PyObject* db; // The DescriptorDatabase underlying this pool. May be NULL.
Joshua Haberman94ece042021-08-18 12:38:26 -070046} PyUpb_DescriptorPool;
47
Joshua Habermane3cd0582021-12-02 15:00:55 -080048PyObject* PyUpb_DescriptorPool_GetDefaultPool() {
49 PyUpb_ModuleState* s = PyUpb_ModuleState_Get();
Joshua Habermandeddc202021-12-01 15:11:12 -080050 return s->default_pool;
51}
52
Joshua Haberman8f0a2cd2022-01-07 17:43:53 -080053const upb_msgdef* PyUpb_DescriptorPool_GetFileProtoDef(void) {
54 PyUpb_ModuleState* s = PyUpb_ModuleState_Get();
55 if (!s->c_descriptor_symtab) {
56 s->c_descriptor_symtab = upb_symtab_new();
57 }
58 return google_protobuf_FileDescriptorProto_getmsgdef(s->c_descriptor_symtab);
59}
60
Joshua Haberman55e5da52021-12-28 21:42:50 -080061static PyObject* PyUpb_DescriptorPool_DoCreateWithCache(
62 PyTypeObject* type, PyObject* db, PyUpb_WeakMap* obj_cache) {
Joshua Habermaneb38a2a2021-12-05 23:54:34 -080063 PyUpb_DescriptorPool* pool = (void*)PyType_GenericAlloc(type, 0);
Joshua Haberman94ece042021-08-18 12:38:26 -070064 pool->symtab = upb_symtab_new();
65 pool->db = db;
Joshua Habermancdc9fcd2021-08-23 16:57:40 -070066 Py_XINCREF(pool->db);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -080067 PyUpb_WeakMap_Add(obj_cache, pool->symtab, &pool->ob_base);
Joshua Haberman94ece042021-08-18 12:38:26 -070068 return &pool->ob_base;
69}
70
Joshua Habermaneb38a2a2021-12-05 23:54:34 -080071static PyObject* PyUpb_DescriptorPool_DoCreate(PyTypeObject* type,
72 PyObject* db) {
73 return PyUpb_DescriptorPool_DoCreateWithCache(type, db,
74 PyUpb_ObjCache_Instance());
75}
76
Joshua Habermane3cd0582021-12-02 15:00:55 -080077upb_symtab* PyUpb_DescriptorPool_GetSymtab(PyObject* pool) {
Joshua Habermandeddc202021-12-01 15:11:12 -080078 return ((PyUpb_DescriptorPool*)pool)->symtab;
79}
80
Joshua Habermancdc9fcd2021-08-23 16:57:40 -070081static int PyUpb_DescriptorPool_Traverse(PyUpb_DescriptorPool* self,
82 visitproc visit, void* arg) {
83 Py_VISIT(self->db);
84 return 0;
85}
86
87static int PyUpb_DescriptorPool_Clear(PyUpb_DescriptorPool* self) {
88 Py_CLEAR(self->db);
89 return 0;
90}
91
Joshua Habermane3cd0582021-12-02 15:00:55 -080092PyObject* PyUpb_DescriptorPool_Get(const upb_symtab* symtab) {
93 PyObject* pool = PyUpb_ObjCache_Get(symtab);
Joshua Habermandeddc202021-12-01 15:11:12 -080094 assert(pool);
95 return pool;
96}
97
Joshua Habermaneec1a452021-08-18 15:23:57 -070098static void PyUpb_DescriptorPool_Dealloc(PyUpb_DescriptorPool* self) {
Joshua Habermancdc9fcd2021-08-23 16:57:40 -070099 PyUpb_DescriptorPool_Clear(self);
Joshua Haberman55e5da52021-12-28 21:42:50 -0800100 upb_symtab_free(self->symtab);
Joshua Habermandeddc202021-12-01 15:11:12 -0800101 PyUpb_ObjCache_Delete(self->symtab);
102 PyUpb_Dealloc(self);
Joshua Haberman94ece042021-08-18 12:38:26 -0700103}
104
105/*
106 * DescriptorPool.__new__()
107 *
108 * Implements:
109 * DescriptorPool(descriptor_db=None)
110 */
111static PyObject* PyUpb_DescriptorPool_New(PyTypeObject* type, PyObject* args,
112 PyObject* kwargs) {
113 char* kwlist[] = {"descriptor_db", 0};
114 PyObject* db = NULL;
115
116 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &db)) {
117 return NULL;
118 }
119
Joshua Haberman55e5da52021-12-28 21:42:50 -0800120 if (db == Py_None) db = NULL;
Joshua Haberman94ece042021-08-18 12:38:26 -0700121 return PyUpb_DescriptorPool_DoCreate(type, db);
122}
123
Joshua Habermana754a372022-01-08 12:19:08 -0800124static PyObject* PyUpb_DescriptorPool_DoAdd(PyObject* _self,
125 PyObject* file_desc);
126
127static bool PyUpb_DescriptorPool_TryLoadFileProto(PyUpb_DescriptorPool* self,
128 PyObject* proto) {
129 if (proto == NULL) {
130 if (PyErr_ExceptionMatches(PyExc_KeyError)) {
131 // Expected error: item was simply not found.
132 PyErr_Clear();
133 return true; // We didn't accomplish our goal, but we didn't error out.
134 }
135 return false;
136 }
137 if (proto == Py_None) return true;
138 return PyUpb_DescriptorPool_DoAdd((PyObject*)self, proto) != NULL;
139}
140
141static bool PyUpb_DescriptorPool_TryLoadSymbol(PyUpb_DescriptorPool* self,
142 PyObject* sym) {
143 if (!self->db) return false;
144 PyObject* file_proto =
145 PyObject_CallMethod(self->db, "FindFileContainingSymbol", "O", sym);
146 bool ret = PyUpb_DescriptorPool_TryLoadFileProto(self, file_proto);
147 Py_XDECREF(file_proto);
148 return ret;
149}
150
Joshua Haberman7a243402022-01-08 13:21:14 -0800151static bool PyUpb_DescriptorPool_TryLoadFilename(PyUpb_DescriptorPool* self,
152 PyObject* filename) {
153 if (!self->db) return false;
154 PyObject* file_proto =
155 PyObject_CallMethod(self->db, "FindFileByName", "O", filename);
156 bool ret = PyUpb_DescriptorPool_TryLoadFileProto(self, file_proto);
157 Py_XDECREF(file_proto);
158 return ret;
159}
160
Joshua Habermana754a372022-01-08 12:19:08 -0800161bool PyUpb_DescriptorPool_CheckNoDatabase(PyObject* _self) {
Joshua Haberman00c106f2022-01-08 22:15:10 -0800162 return true;
163}
164
165static bool PyUpb_DescriptorPool_LoadDependentFiles(
166 PyUpb_DescriptorPool* self, google_protobuf_FileDescriptorProto* proto) {
Joshua Haberman00c106f2022-01-08 22:15:10 -0800167 size_t n;
168 const upb_strview* deps =
169 google_protobuf_FileDescriptorProto_dependency(proto, &n);
170 for (size_t i = 0; i < n; i++) {
171 const upb_filedef* dep =
172 upb_symtab_lookupfile2(self->symtab, deps[i].data, deps[i].size);
173 if (!dep) {
174 PyObject* filename =
175 PyUnicode_FromStringAndSize(deps[i].data, deps[i].size);
176 if (!filename) return false;
177 bool ok = PyUpb_DescriptorPool_TryLoadFilename(self, filename);
178 Py_DECREF(filename);
179 if (!ok) return false;
180 }
Joshua Habermana754a372022-01-08 12:19:08 -0800181 }
182 return true;
183}
184
185static PyObject* PyUpb_DescriptorPool_DoAddSerializedFile(
Joshua Haberman94ece042021-08-18 12:38:26 -0700186 PyObject* _self, PyObject* serialized_pb) {
187 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
Joshua Haberman94ece042021-08-18 12:38:26 -0700188 upb_arena* arena = upb_arena_new();
Joshua Habermane3cd0582021-12-02 15:00:55 -0800189 if (!arena) PYUPB_RETURN_OOM;
Joshua Haberman94ece042021-08-18 12:38:26 -0700190 PyObject* result = NULL;
191
Joshua Haberman00c106f2022-01-08 22:15:10 -0800192 char* buf;
193 Py_ssize_t size;
Joshua Haberman94ece042021-08-18 12:38:26 -0700194 if (PyBytes_AsStringAndSize(serialized_pb, &buf, &size) < 0) {
195 goto done;
196 }
197
198 google_protobuf_FileDescriptorProto* proto =
199 google_protobuf_FileDescriptorProto_parse(buf, size, arena);
200 if (!proto) {
201 PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
Joshua Habermancdc9fcd2021-08-23 16:57:40 -0700202 goto done;
Joshua Haberman94ece042021-08-18 12:38:26 -0700203 }
204
Joshua Haberman8f0a2cd2022-01-07 17:43:53 -0800205 upb_strview name = google_protobuf_FileDescriptorProto_name(proto);
206 const upb_filedef* file =
207 upb_symtab_lookupfile2(self->symtab, name.data, name.size);
208
209 if (file) {
210 // If the existing file is equal to the new file, then silently ignore the
211 // duplicate add.
212 google_protobuf_FileDescriptorProto* existing =
213 upb_FileDef_ToProto(file, arena);
214 if (!existing) {
215 PyErr_SetNone(PyExc_MemoryError);
216 goto done;
217 }
218 const upb_msgdef* m = PyUpb_DescriptorPool_GetFileProtoDef();
219 if (PyUpb_Message_IsEqual(proto, existing, m)) {
220 Py_INCREF(Py_None);
221 result = Py_None;
222 goto done;
223 }
224 }
225
Joshua Haberman7a243402022-01-08 13:21:14 -0800226 if (self->db) {
Joshua Haberman00c106f2022-01-08 22:15:10 -0800227 if (!PyUpb_DescriptorPool_LoadDependentFiles(self, proto)) goto done;
Joshua Haberman7a243402022-01-08 13:21:14 -0800228 }
229
Joshua Haberman94ece042021-08-18 12:38:26 -0700230 upb_status status;
231 upb_status_clear(&status);
232
233 const upb_filedef* filedef = upb_symtab_addfile(self->symtab, proto, &status);
234 if (!filedef) {
235 PyErr_Format(PyExc_TypeError,
236 "Couldn't build proto file into descriptor pool: %s",
237 upb_status_errmsg(&status));
Joshua Habermancdc9fcd2021-08-23 16:57:40 -0700238 goto done;
Joshua Haberman94ece042021-08-18 12:38:26 -0700239 }
240
Joshua Habermandeddc202021-12-01 15:11:12 -0800241 result = PyUpb_FileDescriptor_Get(filedef);
Joshua Haberman94ece042021-08-18 12:38:26 -0700242
243done:
244 upb_arena_free(arena);
245 return result;
246}
247
Joshua Habermana754a372022-01-08 12:19:08 -0800248static PyObject* PyUpb_DescriptorPool_DoAdd(PyObject* _self,
249 PyObject* file_desc) {
Joshua Haberman55e5da52021-12-28 21:42:50 -0800250 PyObject* subargs = PyTuple_New(0);
Joshua Habermana754a372022-01-08 12:19:08 -0800251 if (!PyUpb_CMessage_Check(file_desc)) return NULL;
252 const upb_msgdef* m = PyUpb_CMessage_GetMsgdef(file_desc);
253 const char* file_proto_name = "google.protobuf.FileDescriptorProto";
254 if (strcmp(upb_msgdef_fullname(m), file_proto_name) != 0) {
Joshua Habermana754a372022-01-08 12:19:08 -0800255 return PyErr_Format(PyExc_TypeError, "Can only add FileDescriptorProto");
256 }
Joshua Haberman55e5da52021-12-28 21:42:50 -0800257 PyObject* serialized =
258 PyUpb_CMessage_SerializeToString(file_desc, subargs, NULL);
259 Py_DECREF(subargs);
260 if (!serialized) return NULL;
Joshua Habermana754a372022-01-08 12:19:08 -0800261 PyObject* ret = PyUpb_DescriptorPool_DoAddSerializedFile(_self, serialized);
Joshua Haberman55e5da52021-12-28 21:42:50 -0800262 Py_DECREF(serialized);
263 return ret;
264}
265
266/*
Joshua Habermana754a372022-01-08 12:19:08 -0800267 * PyUpb_DescriptorPool_AddSerializedFile()
268 *
269 * Implements:
270 * DescriptorPool.AddSerializedFile(self, serialized_file_descriptor)
271 *
272 * Adds the given serialized FileDescriptorProto to the pool.
273 */
274static PyObject* PyUpb_DescriptorPool_AddSerializedFile(
Joshua Haberman00c106f2022-01-08 22:15:10 -0800275 PyObject * _self, PyObject * serialized_pb) {
276 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
277 if (self->db) {
278 PyErr_SetString(
279 PyExc_ValueError,
280 "Cannot call AddSerializedFile on a DescriptorPool that uses a "
281 "DescriptorDatabase. Add your file to the underlying database.");
282 return false;
283 }
284 return PyUpb_DescriptorPool_DoAddSerializedFile(_self, serialized_pb);
Joshua Habermana754a372022-01-08 12:19:08 -0800285}
286
Joshua Haberman00c106f2022-01-08 22:15:10 -0800287static PyObject* PyUpb_DescriptorPool_Add(PyObject* _self,
Joshua Habermana754a372022-01-08 12:19:08 -0800288 PyObject* file_desc) {
Joshua Haberman00c106f2022-01-08 22:15:10 -0800289 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
290 if (self->db) {
291 PyErr_SetString(
292 PyExc_ValueError,
293 "Cannot call Add on a DescriptorPool that uses a DescriptorDatabase. "
294 "Add your file to the underlying database.");
295 return false;
296 }
297 return PyUpb_DescriptorPool_DoAdd(_self, file_desc);
Joshua Habermana754a372022-01-08 12:19:08 -0800298}
299
300/*
Joshua Haberman55e5da52021-12-28 21:42:50 -0800301 * PyUpb_DescriptorPool_FindFileByName()
302 *
303 * Implements:
304 * DescriptorPool.FindFileByName(self, name)
305 */
306static PyObject* PyUpb_DescriptorPool_FindFileByName(PyObject* _self,
307 PyObject* arg) {
308 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
309
310 const char* name = PyUpb_GetStrData(arg);
311 if (!name) return NULL;
312
313 const upb_filedef* file = upb_symtab_lookupfile(self->symtab, name);
Joshua Haberman7a243402022-01-08 13:21:14 -0800314 if (file == NULL && self->db) {
315 if (!PyUpb_DescriptorPool_TryLoadFilename(self, arg)) return NULL;
316 file = upb_symtab_lookupfile(self->symtab, name);
317 }
Joshua Haberman55e5da52021-12-28 21:42:50 -0800318 if (file == NULL) {
319 return PyErr_Format(PyExc_KeyError, "Couldn't find file %.200s", name);
320 }
321
322 return PyUpb_FileDescriptor_Get(file);
323}
324
Joshua Haberman94ece042021-08-18 12:38:26 -0700325/*
326 * PyUpb_DescriptorPool_FindExtensionByName()
327 *
328 * Implements:
329 * DescriptorPool.FindExtensionByName(self, name)
330 */
331static PyObject* PyUpb_DescriptorPool_FindExtensionByName(PyObject* _self,
332 PyObject* arg) {
333 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
334
335 const char* name = PyUpb_GetStrData(arg);
Joshua Habermancdc9fcd2021-08-23 16:57:40 -0700336 if (!name) return NULL;
Joshua Haberman94ece042021-08-18 12:38:26 -0700337
338 const upb_fielddef* field = upb_symtab_lookupext(self->symtab, name);
Joshua Haberman7a243402022-01-08 13:21:14 -0800339 if (field == NULL && self->db) {
340 if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
341 field = upb_symtab_lookupext(self->symtab, name);
342 }
Joshua Haberman94ece042021-08-18 12:38:26 -0700343 if (field == NULL) {
344 return PyErr_Format(PyExc_KeyError, "Couldn't find extension %.200s", name);
345 }
346
Joshua Habermandeddc202021-12-01 15:11:12 -0800347 return PyUpb_FieldDescriptor_Get(field);
Joshua Haberman94ece042021-08-18 12:38:26 -0700348}
349
Joshua Haberman55e5da52021-12-28 21:42:50 -0800350/*
351 * PyUpb_DescriptorPool_FindMessageTypeByName()
352 *
353 * Implements:
354 * DescriptorPool.FindMessageTypeByName(self, name)
355 */
356static PyObject* PyUpb_DescriptorPool_FindMessageTypeByName(PyObject* _self,
357 PyObject* arg) {
358 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
359
360 const char* name = PyUpb_GetStrData(arg);
361 if (!name) return NULL;
362
363 const upb_msgdef* m = upb_symtab_lookupmsg(self->symtab, name);
Joshua Habermana754a372022-01-08 12:19:08 -0800364 if (m == NULL && self->db) {
365 if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
366 m = upb_symtab_lookupmsg(self->symtab, name);
367 }
Joshua Haberman55e5da52021-12-28 21:42:50 -0800368 if (m == NULL) {
369 return PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name);
370 }
371
372 return PyUpb_Descriptor_Get(m);
373}
374
Joshua Habermane4c88ad2021-12-29 14:41:44 -0800375// Splits a dotted symbol like foo.bar.baz on the last dot. Returns the portion
376// after the last dot (baz) and updates `*parent_size` to the length of the
377// parent (foo.bar). Returns NULL if no dots were present.
378static const char* PyUpb_DescriptorPool_SplitSymbolName(const char* sym,
379 size_t* parent_size) {
380 const char* last_dot = strrchr(sym, '.');
381 if (!last_dot) return NULL;
382 *parent_size = last_dot - sym;
383 return last_dot + 1;
384}
385
Joshua Haberman55e5da52021-12-28 21:42:50 -0800386/*
387 * PyUpb_DescriptorPool_FindFieldByName()
388 *
389 * Implements:
390 * DescriptorPool.FindFieldByName(self, name)
391 */
392static PyObject* PyUpb_DescriptorPool_FindFieldByName(PyObject* _self,
393 PyObject* arg) {
394 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
395
396 const char* name = PyUpb_GetStrData(arg);
397 if (!name) return NULL;
398
Joshua Haberman89ff28c2022-01-07 17:18:55 -0800399 size_t parent_size;
400 const char* child =
401 PyUpb_DescriptorPool_SplitSymbolName(name, &parent_size);
402 const upb_fielddef* f = NULL;
403 if (child) {
404 const upb_msgdef* parent =
405 upb_symtab_lookupmsg2(self->symtab, name, parent_size);
406 if (parent) {
407 f = upb_msgdef_ntofz(parent, child);
Joshua Haberman55e5da52021-12-28 21:42:50 -0800408 }
409 }
410
411 if (!f) {
412 return PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name);
413 }
414
415 return PyUpb_FieldDescriptor_Get(f);
416}
417
418/*
419 * PyUpb_DescriptorPool_FindEnumTypeByName()
420 *
421 * Implements:
422 * DescriptorPool.FindEnumTypeByName(self, name)
423 */
424static PyObject* PyUpb_DescriptorPool_FindEnumTypeByName(PyObject* _self,
425 PyObject* arg) {
426 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
427
428 const char* name = PyUpb_GetStrData(arg);
429 if (!name) return NULL;
430
431 const upb_enumdef* e = upb_symtab_lookupenum(self->symtab, name);
Joshua Haberman7a243402022-01-08 13:21:14 -0800432 if (e == NULL && self->db) {
433 if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
434 e = upb_symtab_lookupenum(self->symtab, name);
435 }
Joshua Haberman55e5da52021-12-28 21:42:50 -0800436 if (e == NULL) {
437 return PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name);
438 }
439
440 return PyUpb_EnumDescriptor_Get(e);
441}
442
443/*
444 * PyUpb_DescriptorPool_FindOneofByName()
445 *
446 * Implements:
447 * DescriptorPool.FindOneofByName(self, name)
448 */
449static PyObject* PyUpb_DescriptorPool_FindOneofByName(PyObject* _self,
450 PyObject* arg) {
451 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
452
453 const char* name = PyUpb_GetStrData(arg);
454 if (!name) return NULL;
455
Joshua Habermane4c88ad2021-12-29 14:41:44 -0800456 size_t parent_size;
457 const char* child = PyUpb_DescriptorPool_SplitSymbolName(name, &parent_size);
458
459 if (child) {
Joshua Haberman55e5da52021-12-28 21:42:50 -0800460 const upb_msgdef* parent =
Joshua Habermane4c88ad2021-12-29 14:41:44 -0800461 upb_symtab_lookupmsg2(self->symtab, name, parent_size);
Joshua Haberman7a243402022-01-08 13:21:14 -0800462 if (parent == NULL && self->db) {
463 if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
464 parent = upb_symtab_lookupmsg2(self->symtab, name, parent_size);
465 }
Joshua Haberman55e5da52021-12-28 21:42:50 -0800466 if (parent) {
Joshua Habermane4c88ad2021-12-29 14:41:44 -0800467 const upb_oneofdef* o = upb_msgdef_ntooz(parent, child);
Joshua Haberman55e5da52021-12-28 21:42:50 -0800468 return PyUpb_OneofDescriptor_Get(o);
469 }
470 }
471
Joshua Haberman7a243402022-01-08 13:21:14 -0800472 return PyErr_Format(PyExc_KeyError, "Couldn't find oneof %.200s", name);
Joshua Haberman55e5da52021-12-28 21:42:50 -0800473}
474
475static PyObject* PyUpb_DescriptorPool_FindServiceByName(PyObject* _self,
476 PyObject* arg) {
477 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
478
479 const char* name = PyUpb_GetStrData(arg);
480 if (!name) return NULL;
481
482 const upb_servicedef* s = upb_symtab_lookupservice(self->symtab, name);
483 if (s == NULL) {
484 return PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name);
485 }
486
487 return PyUpb_ServiceDescriptor_Get(s);
488}
489
490static PyObject* PyUpb_DescriptorPool_FindFileContainingSymbol(PyObject* _self,
491 PyObject* arg) {
492 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
493
494 const char* name = PyUpb_GetStrData(arg);
495 if (!name) return NULL;
496
497 const upb_filedef* f = upb_symtab_lookupfileforsym(self->symtab, name);
Joshua Haberman7a243402022-01-08 13:21:14 -0800498 if (f == NULL && self->db) {
499 if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
500 f = upb_symtab_lookupfileforsym(self->symtab, name);
501 }
Joshua Haberman55e5da52021-12-28 21:42:50 -0800502 if (f == NULL) {
503 return PyErr_Format(PyExc_KeyError, "Couldn't find symbol %.200s", name);
504 }
505
506 return PyUpb_FileDescriptor_Get(f);
507}
508
509static PyObject* PyUpb_DescriptorPool_FindExtensionByNumber(PyObject* _self,
510 PyObject* args) {
511 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
512 PyObject* message_descriptor;
513 int number;
514 if (!PyArg_ParseTuple(args, "Oi", &message_descriptor, &number)) {
515 return NULL;
516 }
517
518 const upb_fielddef* f = upb_symtab_lookupextbynum(
519 self->symtab, PyUpb_Descriptor_GetDef(message_descriptor), number);
520 if (f == NULL) {
521 return PyErr_Format(PyExc_KeyError, "Couldn't find Extension %d", number);
522 }
523
524 return PyUpb_FieldDescriptor_Get(f);
525}
526
527static PyObject* PyUpb_DescriptorPool_FindAllExtensions(PyObject* _self,
528 PyObject* msg_desc) {
529 PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
530 const upb_msgdef* m = PyUpb_Descriptor_GetDef(msg_desc);
531 size_t n;
532 const upb_fielddef** ext = upb_symtab_getallexts(self->symtab, m, &n);
533 PyObject* ret = PyList_New(n);
534 for (size_t i = 0; i < n; i++) {
535 PyObject* field = PyUpb_FieldDescriptor_Get(ext[i]);
Joshua Habermane4c88ad2021-12-29 14:41:44 -0800536 if (!field) return NULL;
Joshua Haberman55e5da52021-12-28 21:42:50 -0800537 PyList_SetItem(ret, i, field);
538 }
539 return ret;
540}
541
Joshua Haberman94ece042021-08-18 12:38:26 -0700542static PyMethodDef PyUpb_DescriptorPool_Methods[] = {
Joshua Haberman55e5da52021-12-28 21:42:50 -0800543 {"Add", PyUpb_DescriptorPool_Add, METH_O,
544 "Adds the FileDescriptorProto and its types to this pool."},
Joshua Haberman94ece042021-08-18 12:38:26 -0700545 {"AddSerializedFile", PyUpb_DescriptorPool_AddSerializedFile, METH_O,
546 "Adds a serialized FileDescriptorProto to this pool."},
Joshua Haberman55e5da52021-12-28 21:42:50 -0800547 {"FindFileByName", PyUpb_DescriptorPool_FindFileByName, METH_O,
548 "Searches for a file descriptor by its .proto name."},
549 {"FindMessageTypeByName", PyUpb_DescriptorPool_FindMessageTypeByName,
550 METH_O, "Searches for a message descriptor by full name."},
551 {"FindFieldByName", PyUpb_DescriptorPool_FindFieldByName, METH_O,
552 "Searches for a field descriptor by full name."},
Joshua Haberman94ece042021-08-18 12:38:26 -0700553 {"FindExtensionByName", PyUpb_DescriptorPool_FindExtensionByName, METH_O,
554 "Searches for extension descriptor by full name."},
Joshua Haberman55e5da52021-12-28 21:42:50 -0800555 {"FindEnumTypeByName", PyUpb_DescriptorPool_FindEnumTypeByName, METH_O,
556 "Searches for enum type descriptor by full name."},
557 {"FindOneofByName", PyUpb_DescriptorPool_FindOneofByName, METH_O,
558 "Searches for oneof descriptor by full name."},
559 {"FindServiceByName", PyUpb_DescriptorPool_FindServiceByName, METH_O,
560 "Searches for service descriptor by full name."},
561 //{ "Find, PyUpb_DescriptorPool_Find, METH_O,
562 // "Searches for method descriptor by full name." },
563 {"FindFileContainingSymbol", PyUpb_DescriptorPool_FindFileContainingSymbol,
564 METH_O, "Gets the FileDescriptor containing the specified symbol."},
565 {"FindExtensionByNumber", PyUpb_DescriptorPool_FindExtensionByNumber,
566 METH_VARARGS, "Gets the extension descriptor for the given number."},
567 {"FindAllExtensions", PyUpb_DescriptorPool_FindAllExtensions, METH_O,
568 "Gets all known extensions of the given message descriptor."},
Joshua Haberman94ece042021-08-18 12:38:26 -0700569 {NULL}};
570
571static PyType_Slot PyUpb_DescriptorPool_Slots[] = {
Joshua Habermancdc9fcd2021-08-23 16:57:40 -0700572 {Py_tp_clear, PyUpb_DescriptorPool_Clear},
Joshua Haberman94ece042021-08-18 12:38:26 -0700573 {Py_tp_dealloc, PyUpb_DescriptorPool_Dealloc},
574 {Py_tp_methods, PyUpb_DescriptorPool_Methods},
Joshua Habermancdc9fcd2021-08-23 16:57:40 -0700575 {Py_tp_new, PyUpb_DescriptorPool_New},
576 {Py_tp_traverse, PyUpb_DescriptorPool_Traverse},
Joshua Haberman94ece042021-08-18 12:38:26 -0700577 {0, NULL}};
578
579static PyType_Spec PyUpb_DescriptorPool_Spec = {
Joshua Habermancdc9fcd2021-08-23 16:57:40 -0700580 PYUPB_MODULE_NAME ".DescriptorPool",
581 sizeof(PyUpb_DescriptorPool),
582 0, // tp_itemsize
583 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
Joshua Haberman94ece042021-08-18 12:38:26 -0700584 PyUpb_DescriptorPool_Slots,
585};
586
587// -----------------------------------------------------------------------------
588// Top Level
589// -----------------------------------------------------------------------------
590
591bool PyUpb_InitDescriptorPool(PyObject* m) {
Joshua Haberman55e5da52021-12-28 21:42:50 -0800592 PyUpb_ModuleState* state = PyUpb_ModuleState_GetFromModule(m);
Joshua Haberman94ece042021-08-18 12:38:26 -0700593 PyTypeObject* descriptor_pool_type =
Joshua Haberman55e5da52021-12-28 21:42:50 -0800594 PyUpb_AddClass(m, &PyUpb_DescriptorPool_Spec);
Joshua Haberman94ece042021-08-18 12:38:26 -0700595
596 if (!descriptor_pool_type) return false;
597
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800598 state->default_pool = PyUpb_DescriptorPool_DoCreateWithCache(
599 descriptor_pool_type, NULL, state->obj_cache);
600 return state->default_pool &&
601 PyModule_AddObject(m, "default_pool", state->default_pool) == 0;
Joshua Haberman94ece042021-08-18 12:38:26 -0700602}