blob: 4f5a232864804cc4eba5851990f80f2c433517ce [file] [log] [blame]
Joshua Haberman4111d132021-12-04 18:42:53 -08001/*
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/message.h"
29
30#include "python/convert.h"
31#include "python/descriptor.h"
Joshua Haberman627c44b2021-12-30 17:47:12 -080032#include "python/extension_dict.h"
Joshua Habermanbf74b3e2021-12-30 00:52:12 -080033#include "python/map.h"
Joshua Haberman455426e2021-12-08 23:32:05 -080034#include "python/repeated.h"
Eric Saloedecfd52022-09-15 10:26:14 -070035#include "upb/reflection/def.h"
36#include "upb/reflection/message.h"
Eric Salo0bb46632022-11-03 10:33:57 -070037#include "upb/text/encode.h"
Joshua Haberman4111d132021-12-04 18:42:53 -080038#include "upb/util/required_fields.h"
39
Joshua Haberman1c955f32022-01-12 07:19:28 -080040static const upb_MessageDef* PyUpb_MessageMeta_GetMsgdef(PyObject* cls);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -080041static PyObject* PyUpb_MessageMeta_GetAttr(PyObject* self, PyObject* name);
Joshua Haberman4111d132021-12-04 18:42:53 -080042
43// -----------------------------------------------------------------------------
44// CPythonBits
45// -----------------------------------------------------------------------------
46
47// This struct contains a few things that are not exposed directly through the
48// limited API, but that we can get at in somewhat more roundabout ways. The
49// roundabout ways are slower, so we cache the values here.
50//
51// These values are valid to cache in a global, even across sub-interpreters,
52// because they are not pointers to interpreter state. They are process
53// globals that will be the same for any interpreter in this process.
54typedef struct {
55 // For each member, we note the equivalent expression that we could use in the
56 // full (non-limited) API.
57 newfunc type_new; // PyTypeObject.tp_new
Joshua Habermanffdcc462022-01-12 08:38:36 -080058 destructor type_dealloc; // PyTypeObject.tp_dealloc
Joshua Haberman4111d132021-12-04 18:42:53 -080059 getattrofunc type_getattro; // PyTypeObject.tp_getattro
60 setattrofunc type_setattro; // PyTypeObject.tp_setattro
61 size_t type_basicsize; // sizeof(PyHeapTypeObject)
62
63 // While we can refer to PY_VERSION_HEX in the limited API, this will give us
64 // the version of Python we were compiled against, which may be different
65 // than the version we are dynamically linked against. Here we want the
66 // version that is actually running in this process.
Joshua Haberman1c955f32022-01-12 07:19:28 -080067 long python_version_hex; // PY_VERSION_HEX
Joshua Haberman4111d132021-12-04 18:42:53 -080068} PyUpb_CPythonBits;
69
70// A global containing the values for this process.
71PyUpb_CPythonBits cpython_bits;
72
Joshua Habermanffdcc462022-01-12 08:38:36 -080073destructor upb_Pre310_PyType_GetDeallocSlot(PyTypeObject* type_subclass) {
74 // This is a bit desperate. We need type_dealloc(), but PyType_GetSlot(type,
75 // Py_tp_dealloc) will return subtype_dealloc(). There appears to be no way
76 // whatsoever to fetch type_dealloc() through the limited API until Python
77 // 3.10.
78 //
79 // To work around this so we attempt to find it by looking for the offset of
80 // tp_dealloc in PyTypeObject, then memcpy() it directly. This should always
81 // work in practice.
82 //
83 // Starting with Python 3.10 on you can call PyType_GetSlot() on non-heap
84 // types. We will be able to replace all this hack with just:
85 //
86 // PyType_GetSlot(&PyType_Type, Py_tp_dealloc)
87 //
88 destructor subtype_dealloc = PyType_GetSlot(type_subclass, Py_tp_dealloc);
89 for (size_t i = 0; i < 2000; i += sizeof(uintptr_t)) {
90 destructor maybe_subtype_dealloc;
91 memcpy(&maybe_subtype_dealloc, (char*)type_subclass + i,
92 sizeof(destructor));
93 if (maybe_subtype_dealloc == subtype_dealloc) {
94 destructor type_dealloc;
95 memcpy(&type_dealloc, (char*)&PyType_Type + i, sizeof(destructor));
96 return type_dealloc;
97 }
98 }
99 assert(false);
100 return NULL;
101}
102
Joshua Haberman4111d132021-12-04 18:42:53 -0800103static bool PyUpb_CPythonBits_Init(PyUpb_CPythonBits* bits) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800104 PyObject* bases = NULL;
105 PyTypeObject* type = NULL;
106 PyObject* size = NULL;
107 PyObject* sys = NULL;
108 PyObject* hex_version = NULL;
109 bool ret = false;
110
Joshua Haberman4111d132021-12-04 18:42:53 -0800111 // PyType_GetSlot() only works on heap types, so we cannot use it on
112 // &PyType_Type directly. Instead we create our own (temporary) type derived
113 // from PyType_Type: this will inherit all of the slots from PyType_Type, but
114 // as a heap type it can be queried with PyType_GetSlot().
115 static PyType_Slot dummy_slots[] = {{0, NULL}};
116
117 static PyType_Spec dummy_spec = {
118 "module.DummyClass", // tp_name
119 0, // To be filled in by size of base // tp_basicsize
120 0, // tp_itemsize
121 Py_TPFLAGS_DEFAULT, // tp_flags
122 dummy_slots,
123 };
124
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800125 bases = Py_BuildValue("(O)", &PyType_Type);
126 if (!bases) goto err;
127 type = (PyTypeObject*)PyType_FromSpecWithBases(&dummy_spec, bases);
128 if (!type) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800129
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800130 bits->type_new = PyType_GetSlot(type, Py_tp_new);
Joshua Habermanffdcc462022-01-12 08:38:36 -0800131 bits->type_dealloc = upb_Pre310_PyType_GetDeallocSlot(type);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800132 bits->type_getattro = PyType_GetSlot(type, Py_tp_getattro);
133 bits->type_setattro = PyType_GetSlot(type, Py_tp_setattro);
Joshua Haberman4111d132021-12-04 18:42:53 -0800134
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800135 size = PyObject_GetAttrString((PyObject*)&PyType_Type, "__basicsize__");
136 if (!size) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800137 bits->type_basicsize = PyLong_AsLong(size);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800138 if (bits->type_basicsize == -1) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800139
Joshua Habermanffdcc462022-01-12 08:38:36 -0800140 assert(bits->type_new);
141 assert(bits->type_dealloc);
142 assert(bits->type_getattro);
143 assert(bits->type_setattro);
Joshua Haberman4111d132021-12-04 18:42:53 -0800144
145#ifndef Py_LIMITED_API
146 assert(bits->type_new == PyType_Type.tp_new);
Joshua Habermanffdcc462022-01-12 08:38:36 -0800147 assert(bits->type_dealloc == PyType_Type.tp_dealloc);
Joshua Haberman4111d132021-12-04 18:42:53 -0800148 assert(bits->type_getattro == PyType_Type.tp_getattro);
149 assert(bits->type_setattro == PyType_Type.tp_setattro);
150 assert(bits->type_basicsize == sizeof(PyHeapTypeObject));
151#endif
152
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800153 sys = PyImport_ImportModule("sys");
154 hex_version = PyObject_GetAttrString(sys, "hexversion");
Joshua Haberman4111d132021-12-04 18:42:53 -0800155 bits->python_version_hex = PyLong_AsLong(hex_version);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800156 ret = true;
Joshua Haberman4111d132021-12-04 18:42:53 -0800157
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800158err:
159 Py_XDECREF(bases);
160 Py_XDECREF(type);
161 Py_XDECREF(size);
162 Py_XDECREF(sys);
163 Py_XDECREF(hex_version);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800164 return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800165}
166
167// -----------------------------------------------------------------------------
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700168// Message
Joshua Haberman4111d132021-12-04 18:42:53 -0800169// -----------------------------------------------------------------------------
170
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700171// The main message object. The type of the object (PyUpb_Message.ob_type)
Joshua Haberman4111d132021-12-04 18:42:53 -0800172// will be an instance of the PyUpb_MessageMeta type (defined below). So the
173// chain is:
174// FooMessage = MessageMeta(...)
175// foo = FooMessage()
176//
177// Which becomes:
178// Object C Struct Type Python type (ob_type)
179// ----------------- ----------------- ---------------------
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700180// foo PyUpb_Message FooMessage
Joshua Haberman4111d132021-12-04 18:42:53 -0800181// FooMessage PyUpb_MessageMeta message_meta_type
182// message_meta_type PyTypeObject 'type' in Python
183//
184// A message object can be in one of two states: present or non-present. When
185// a message is non-present, it stores a reference to its parent, and a write
186// to any attribute will trigger the message to become present in its parent.
187// The parent may also be non-present, in which case a mutation will trigger a
188// chain reaction.
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700189typedef struct PyUpb_Message {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800190 PyObject_HEAD;
Joshua Haberman4111d132021-12-04 18:42:53 -0800191 PyObject* arena;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800192 uintptr_t def; // Tagged, low bit 1 == upb_FieldDef*, else upb_MessageDef*
Joshua Haberman4111d132021-12-04 18:42:53 -0800193 union {
194 // when def is msgdef, the data for this msg.
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800195 upb_Message* msg;
Joshua Haberman4111d132021-12-04 18:42:53 -0800196 // when def is fielddef, owning pointer to parent
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700197 struct PyUpb_Message* parent;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800198 } ptr;
Joshua Haberman4111d132021-12-04 18:42:53 -0800199 PyObject* ext_dict; // Weak pointer to extension dict, if any.
200 // name->obj dict for non-present msg/map/repeated, NULL if none.
201 PyUpb_WeakMap* unset_subobj_map;
202 int version;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700203} PyUpb_Message;
Joshua Haberman4111d132021-12-04 18:42:53 -0800204
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700205static PyObject* PyUpb_Message_GetAttr(PyObject* _self, PyObject* attr);
Joshua Haberman4111d132021-12-04 18:42:53 -0800206
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700207bool PyUpb_Message_IsStub(PyUpb_Message* msg) { return msg->def & 1; }
Joshua Haberman4111d132021-12-04 18:42:53 -0800208
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700209const upb_FieldDef* PyUpb_Message_GetFieldDef(PyUpb_Message* msg) {
210 assert(PyUpb_Message_IsStub(msg));
Joshua Haberman4111d132021-12-04 18:42:53 -0800211 return (void*)(msg->def & ~(uintptr_t)1);
212}
213
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700214static const upb_MessageDef* _PyUpb_Message_GetMsgdef(PyUpb_Message* msg) {
215 return PyUpb_Message_IsStub(msg)
216 ? upb_FieldDef_MessageSubDef(PyUpb_Message_GetFieldDef(msg))
Joshua Haberman4111d132021-12-04 18:42:53 -0800217 : (void*)msg->def;
218}
219
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700220const upb_MessageDef* PyUpb_Message_GetMsgdef(PyObject* self) {
221 return _PyUpb_Message_GetMsgdef((PyUpb_Message*)self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800222}
223
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700224static upb_Message* PyUpb_Message_GetMsg(PyUpb_Message* self) {
225 assert(!PyUpb_Message_IsStub(self));
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800226 return self->ptr.msg;
Joshua Haberman4111d132021-12-04 18:42:53 -0800227}
228
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700229bool PyUpb_Message_TryCheck(PyObject* self) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800230 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
231 PyObject* type = (PyObject*)Py_TYPE(self);
232 return Py_TYPE(type) == state->message_meta_type;
233}
234
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700235bool PyUpb_Message_Verify(PyObject* self) {
236 if (!PyUpb_Message_TryCheck(self)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800237 PyErr_Format(PyExc_TypeError, "Expected a message object, but got %R.",
238 self);
239 return false;
240 }
241 return true;
242}
243
Joshua Haberman58960e02021-12-30 10:50:41 -0800244// If the message is reified, returns it. Otherwise, returns NULL.
245// If NULL is returned, the object is empty and has no underlying data.
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700246upb_Message* PyUpb_Message_GetIfReified(PyObject* _self) {
247 PyUpb_Message* self = (void*)_self;
248 return PyUpb_Message_IsStub(self) ? NULL : self->ptr.msg;
Joshua Haberman4111d132021-12-04 18:42:53 -0800249}
250
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700251static PyObject* PyUpb_Message_New(PyObject* cls, PyObject* unused_args,
252 PyObject* unused_kwargs) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800253 const upb_MessageDef* msgdef = PyUpb_MessageMeta_GetMsgdef(cls);
Eric Salo41335a02022-10-10 13:53:47 -0700254 const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef);
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700255 PyUpb_Message* msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0);
Joshua Haberman4111d132021-12-04 18:42:53 -0800256 msg->def = (uintptr_t)msgdef;
257 msg->arena = PyUpb_Arena_New();
Eric Salo41335a02022-10-10 13:53:47 -0700258 msg->ptr.msg = upb_Message_New(layout, PyUpb_Arena_Get(msg->arena));
Joshua Haberman4111d132021-12-04 18:42:53 -0800259 msg->unset_subobj_map = NULL;
260 msg->ext_dict = NULL;
261 msg->version = 0;
262
263 PyObject* ret = &msg->ob_base;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800264 PyUpb_ObjCache_Add(msg->ptr.msg, ret);
Joshua Haberman4111d132021-12-04 18:42:53 -0800265 return ret;
266}
267
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800268/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700269 * PyUpb_Message_LookupName()
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800270 *
271 * Tries to find a field or oneof named `py_name` in the message object `self`.
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800272 * The user must pass `f` and/or `o` to indicate whether a field or a oneof name
273 * is expected. If the name is found and it has an expected type, the function
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800274 * sets `*f` or `*o` respectively and returns true. Otherwise returns false
275 * and sets an exception of type `exc_type` if provided.
276 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700277static bool PyUpb_Message_LookupName(PyUpb_Message* self, PyObject* py_name,
278 const upb_FieldDef** f,
279 const upb_OneofDef** o,
280 PyObject* exc_type) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800281 assert(f || o);
Joshua Haberman4111d132021-12-04 18:42:53 -0800282 Py_ssize_t size;
Joshua Habermanc75b39f2022-01-09 21:48:26 -0800283 const char* name = NULL;
284 if (PyUnicode_Check(py_name)) {
285 name = PyUnicode_AsUTF8AndSize(py_name, &size);
286 } else if (PyBytes_Check(py_name)) {
287 PyBytes_AsStringAndSize(py_name, (char**)&name, &size);
288 }
Joshua Habermanffdcc462022-01-12 08:38:36 -0800289 if (!name) {
290 PyErr_Format(exc_type,
291 "Expected a field name, but got non-string argument %S.",
292 py_name);
293 return false;
294 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700295 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800296
Joshua Haberman1c955f32022-01-12 07:19:28 -0800297 if (!upb_MessageDef_FindByNameWithSize(msgdef, name, size, f, o)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800298 if (exc_type) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800299 PyErr_Format(exc_type, "Protocol message %s has no \"%s\" field.",
300 upb_MessageDef_Name(msgdef), name);
Joshua Haberman4111d132021-12-04 18:42:53 -0800301 }
302 return false;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800303 }
304
305 if (!o && !*f) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800306 if (exc_type) {
307 PyErr_Format(exc_type, "Expected a field name, but got oneof name %s.",
308 name);
309 }
310 return false;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800311 }
312
313 if (!f && !*o) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800314 if (exc_type) {
315 PyErr_Format(exc_type, "Expected a oneof name, but got field name %s.",
316 name);
317 }
318 return false;
319 }
320
321 return true;
322}
323
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700324static bool PyUpb_Message_InitMessageMapEntry(PyObject* dst, PyObject* src) {
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800325 if (!src || !dst) return false;
326
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800327 // TODO(haberman): Currently we are doing Clear()+MergeFrom(). Replace with
328 // CopyFrom() once that is implemented.
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800329 PyObject* ok = PyObject_CallMethod(dst, "Clear", NULL);
330 if (!ok) return false;
331 Py_DECREF(ok);
332 ok = PyObject_CallMethod(dst, "MergeFrom", "O", src);
333 if (!ok) return false;
334 Py_DECREF(ok);
335
336 return true;
337}
338
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700339int PyUpb_Message_InitMapAttributes(PyObject* map, PyObject* value,
340 const upb_FieldDef* f) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800341 const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(f);
342 const upb_FieldDef* val_f = upb_MessageDef_Field(entry_m, 1);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800343 PyObject* it = NULL;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800344 PyObject* tmp = NULL;
345 int ret = -1;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800346 if (upb_FieldDef_IsSubMessage(val_f)) {
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800347 it = PyObject_GetIter(value);
348 if (it == NULL) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800349 PyErr_Format(PyExc_TypeError, "Argument for field %s is not iterable",
Joshua Haberman1c955f32022-01-12 07:19:28 -0800350 upb_FieldDef_FullName(f));
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800351 goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800352 }
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800353 PyObject* e;
354 while ((e = PyIter_Next(it)) != NULL) {
355 PyObject* src = PyObject_GetItem(value, e);
356 PyObject* dst = PyObject_GetItem(map, e);
357 Py_DECREF(e);
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700358 bool ok = PyUpb_Message_InitMessageMapEntry(dst, src);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800359 Py_XDECREF(src);
360 Py_XDECREF(dst);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800361 if (!ok) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800362 }
Joshua Haberman4111d132021-12-04 18:42:53 -0800363 } else {
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800364 tmp = PyObject_CallMethod(map, "update", "O", value);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800365 if (!tmp) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800366 }
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800367 ret = 0;
368
369err:
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800370 Py_XDECREF(it);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800371 Py_XDECREF(tmp);
372 return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800373}
374
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700375void PyUpb_Message_EnsureReified(PyUpb_Message* self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800376
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700377static bool PyUpb_Message_InitMapAttribute(PyObject* _self, PyObject* name,
378 const upb_FieldDef* f,
379 PyObject* value) {
380 PyObject* map = PyUpb_Message_GetAttr(_self, name);
381 int ok = PyUpb_Message_InitMapAttributes(map, value, f);
Joshua Habermanbf74b3e2021-12-30 00:52:12 -0800382 Py_DECREF(map);
383 return ok >= 0;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800384}
385
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700386static bool PyUpb_Message_InitRepeatedMessageAttribute(PyObject* _self,
387 PyObject* repeated,
388 PyObject* value,
389 const upb_FieldDef* f) {
Joshua Haberman0abdee02022-05-06 20:53:55 -0700390 PyObject* it = PyObject_GetIter(value);
391 if (!it) {
392 PyErr_Format(PyExc_TypeError, "Argument for field %s is not iterable",
393 upb_FieldDef_FullName(f));
394 return false;
395 }
396 PyObject* e = NULL;
397 PyObject* m = NULL;
398 while ((e = PyIter_Next(it)) != NULL) {
399 if (PyDict_Check(e)) {
400 m = PyUpb_RepeatedCompositeContainer_Add(repeated, NULL, e);
401 if (!m) goto err;
402 } else {
403 m = PyUpb_RepeatedCompositeContainer_Add(repeated, NULL, NULL);
404 if (!m) goto err;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700405 PyObject* merged = PyUpb_Message_MergeFrom(m, e);
Joshua Haberman0abdee02022-05-06 20:53:55 -0700406 if (!merged) goto err;
407 Py_DECREF(merged);
408 }
409 Py_DECREF(e);
410 Py_DECREF(m);
411 m = NULL;
412 }
413
414err:
415 Py_XDECREF(it);
416 Py_XDECREF(e);
417 Py_XDECREF(m);
418 return !PyErr_Occurred(); // Check PyIter_Next() exit.
419}
420
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700421static bool PyUpb_Message_InitRepeatedAttribute(PyObject* _self, PyObject* name,
422 PyObject* value) {
423 PyUpb_Message* self = (void*)_self;
Joshua Haberman0abdee02022-05-06 20:53:55 -0700424 const upb_FieldDef* field;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700425 if (!PyUpb_Message_LookupName(self, name, &field, NULL,
426 PyExc_AttributeError)) {
Joshua Haberman0abdee02022-05-06 20:53:55 -0700427 return false;
428 }
Joshua Habermanffdcc462022-01-12 08:38:36 -0800429 bool ok = false;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700430 PyObject* repeated = PyUpb_Message_GetFieldValue(_self, field);
Joshua Haberman0abdee02022-05-06 20:53:55 -0700431 PyObject* tmp = NULL;
Joshua Habermanc3cfd092022-05-10 08:52:45 -0700432 if (!repeated) goto err;
Joshua Haberman0abdee02022-05-06 20:53:55 -0700433 if (upb_FieldDef_IsSubMessage(field)) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700434 if (!PyUpb_Message_InitRepeatedMessageAttribute(_self, repeated, value,
435 field)) {
Joshua Haberman0abdee02022-05-06 20:53:55 -0700436 goto err;
437 }
438 } else {
439 tmp = PyUpb_RepeatedContainer_Extend(repeated, value);
440 if (!tmp) goto err;
441 }
Joshua Habermanffdcc462022-01-12 08:38:36 -0800442 ok = true;
443
444err:
445 Py_XDECREF(repeated);
446 Py_XDECREF(tmp);
447 return ok;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800448}
449
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700450static bool PyUpb_Message_InitMessageAttribute(PyObject* _self, PyObject* name,
451 PyObject* value) {
452 PyObject* submsg = PyUpb_Message_GetAttr(_self, name);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800453 if (!submsg) return -1;
454 assert(!PyErr_Occurred());
455 bool ok;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700456 if (PyUpb_Message_TryCheck(value)) {
457 PyObject* tmp = PyUpb_Message_MergeFrom(submsg, value);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800458 ok = tmp != NULL;
459 Py_DECREF(tmp);
Joshua Haberman61d6eff2022-01-09 20:50:32 -0800460 } else if (PyDict_Check(value)) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800461 assert(!PyErr_Occurred());
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700462 ok = PyUpb_Message_InitAttributes(submsg, NULL, value) >= 0;
Joshua Haberman61d6eff2022-01-09 20:50:32 -0800463 } else {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700464 const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self);
Joshua Haberman61d6eff2022-01-09 20:50:32 -0800465 PyErr_Format(PyExc_TypeError, "Message must be initialized with a dict: %s",
Joshua Haberman1c955f32022-01-12 07:19:28 -0800466 upb_MessageDef_FullName(m));
Joshua Haberman61d6eff2022-01-09 20:50:32 -0800467 ok = false;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800468 }
469 Py_DECREF(submsg);
470 return ok;
471}
472
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700473static bool PyUpb_Message_InitScalarAttribute(upb_Message* msg,
474 const upb_FieldDef* f,
475 PyObject* value,
476 upb_Arena* arena) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800477 upb_MessageValue msgval;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800478 assert(!PyErr_Occurred());
Joshua Haberman61d6eff2022-01-09 20:50:32 -0800479 if (!PyUpb_PyToUpb(value, f, &msgval, arena)) return false;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800480 upb_Message_Set(msg, f, msgval, arena);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800481 return true;
482}
483
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700484int PyUpb_Message_InitAttributes(PyObject* _self, PyObject* args,
485 PyObject* kwargs) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800486 assert(!PyErr_Occurred());
487
488 if (args != NULL && PyTuple_Size(args) != 0) {
489 PyErr_SetString(PyExc_TypeError, "No positional arguments allowed");
490 return -1;
491 }
492
493 if (kwargs == NULL) return 0;
494
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700495 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800496 Py_ssize_t pos = 0;
497 PyObject* name;
498 PyObject* value;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700499 PyUpb_Message_EnsureReified(self);
500 upb_Message* msg = PyUpb_Message_GetMsg(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800501 upb_Arena* arena = PyUpb_Arena_Get(self->arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800502
503 while (PyDict_Next(kwargs, &pos, &name, &value)) {
504 assert(!PyErr_Occurred());
Joshua Haberman1c955f32022-01-12 07:19:28 -0800505 const upb_FieldDef* f;
Joshua Haberman4111d132021-12-04 18:42:53 -0800506 assert(!PyErr_Occurred());
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700507 if (!PyUpb_Message_LookupName(self, name, &f, NULL, PyExc_ValueError)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800508 return -1;
509 }
510
511 if (value == Py_None) continue; // Ignored.
512
513 assert(!PyErr_Occurred());
514
Joshua Haberman1c955f32022-01-12 07:19:28 -0800515 if (upb_FieldDef_IsMap(f)) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700516 if (!PyUpb_Message_InitMapAttribute(_self, name, f, value)) return -1;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800517 } else if (upb_FieldDef_IsRepeated(f)) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700518 if (!PyUpb_Message_InitRepeatedAttribute(_self, name, value)) return -1;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800519 } else if (upb_FieldDef_IsSubMessage(f)) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700520 if (!PyUpb_Message_InitMessageAttribute(_self, name, value)) return -1;
Joshua Haberman4111d132021-12-04 18:42:53 -0800521 } else {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700522 if (!PyUpb_Message_InitScalarAttribute(msg, f, value, arena)) return -1;
Joshua Haberman4111d132021-12-04 18:42:53 -0800523 }
524 if (PyErr_Occurred()) return -1;
525 }
526
527 if (PyErr_Occurred()) return -1;
528 return 0;
529}
530
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700531static int PyUpb_Message_Init(PyObject* _self, PyObject* args,
532 PyObject* kwargs) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800533 if (args != NULL && PyTuple_Size(args) != 0) {
534 PyErr_SetString(PyExc_TypeError, "No positional arguments allowed");
535 return -1;
536 }
537
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700538 return PyUpb_Message_InitAttributes(_self, args, kwargs);
Joshua Haberman4111d132021-12-04 18:42:53 -0800539}
540
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700541static PyObject* PyUpb_Message_NewStub(PyObject* parent, const upb_FieldDef* f,
542 PyObject* arena) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800543 const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f);
Joshua Haberman4111d132021-12-04 18:42:53 -0800544 PyObject* cls = PyUpb_Descriptor_GetClass(sub_m);
545
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700546 PyUpb_Message* msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0);
Joshua Haberman4111d132021-12-04 18:42:53 -0800547 msg->def = (uintptr_t)f | 1;
548 msg->arena = arena;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700549 msg->ptr.parent = (PyUpb_Message*)parent;
Joshua Haberman4111d132021-12-04 18:42:53 -0800550 msg->unset_subobj_map = NULL;
551 msg->ext_dict = NULL;
552 msg->version = 0;
553
554 Py_DECREF(cls);
555 Py_INCREF(parent);
556 Py_INCREF(arena);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800557 return &msg->ob_base;
Joshua Haberman4111d132021-12-04 18:42:53 -0800558}
559
Eric Saloc2c64272022-07-12 21:31:18 -0700560static bool PyUpb_Message_IsEmpty(const upb_Message* msg,
561 const upb_MessageDef* m,
562 const upb_DefPool* ext_pool) {
563 if (!msg) return true;
564
565 size_t iter = kUpb_Message_Begin;
566 const upb_FieldDef* f;
567 upb_MessageValue val;
568 if (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) return false;
569
570 size_t len;
571 (void)upb_Message_GetUnknown(msg, &len);
572 return len == 0;
573}
574
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700575static bool PyUpb_Message_IsEqual(PyUpb_Message* m1, PyObject* _m2) {
576 PyUpb_Message* m2 = (void*)_m2;
Joshua Haberman4111d132021-12-04 18:42:53 -0800577 if (m1 == m2) return true;
578 if (!PyObject_TypeCheck(_m2, m1->ob_base.ob_type)) {
579 return false;
580 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700581 const upb_MessageDef* m1_msgdef = _PyUpb_Message_GetMsgdef(m1);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800582#ifndef NDEBUG
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700583 const upb_MessageDef* m2_msgdef = _PyUpb_Message_GetMsgdef(m2);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800584 assert(m1_msgdef == m2_msgdef);
585#endif
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700586 const upb_Message* m1_msg = PyUpb_Message_GetIfReified((PyObject*)m1);
587 const upb_Message* m2_msg = PyUpb_Message_GetIfReified(_m2);
Eric Saloc2c64272022-07-12 21:31:18 -0700588 const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m1_msgdef));
589
590 const bool e1 = PyUpb_Message_IsEmpty(m1_msg, m1_msgdef, symtab);
591 const bool e2 = PyUpb_Message_IsEmpty(m2_msg, m1_msgdef, symtab);
592 if (e1 || e2) return e1 && e2;
593
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700594 return upb_Message_IsEqual(m1_msg, m2_msg, m1_msgdef);
Joshua Haberman4111d132021-12-04 18:42:53 -0800595}
596
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700597static const upb_FieldDef* PyUpb_Message_InitAsMsg(PyUpb_Message* m,
598 upb_Arena* arena) {
599 const upb_FieldDef* f = PyUpb_Message_GetFieldDef(m);
Eric Salo41335a02022-10-10 13:53:47 -0700600 const upb_MessageDef* m2 = upb_FieldDef_MessageSubDef(f);
601 m->ptr.msg = upb_Message_New(upb_MessageDef_MiniTable(m2), arena);
602 m->def = (uintptr_t)m2;
Joshua Haberman32ebb482021-12-08 20:06:07 -0800603 PyUpb_ObjCache_Add(m->ptr.msg, &m->ob_base);
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800604 return f;
605}
606
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700607static void PyUpb_Message_SetField(PyUpb_Message* parent, const upb_FieldDef* f,
608 PyUpb_Message* child, upb_Arena* arena) {
609 upb_MessageValue msgval = {.msg_val = PyUpb_Message_GetMsg(child)};
610 upb_Message_Set(PyUpb_Message_GetMsg(parent), f, msgval, arena);
Joshua Haberman32ebb482021-12-08 20:06:07 -0800611 PyUpb_WeakMap_Delete(parent->unset_subobj_map, f);
612 // Releases a ref previously owned by child->ptr.parent of our child.
613 Py_DECREF(child);
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800614}
615
Joshua Haberman4111d132021-12-04 18:42:53 -0800616/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700617 * PyUpb_Message_EnsureReified()
Joshua Haberman4111d132021-12-04 18:42:53 -0800618 *
619 * This implements the "expando" behavior of Python protos:
620 * foo = FooProto()
621 *
622 * # The intermediate messages don't really exist, and won't be serialized.
623 * x = foo.bar.bar.bar.bar.bar.baz
624 *
625 * # Now all the intermediate objects are created.
626 * foo.bar.bar.bar.bar.bar.baz = 5
627 *
628 * This function should be called before performing any mutation of a protobuf
629 * object.
630 *
631 * Post-condition:
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700632 * PyUpb_Message_IsStub(self) is false
Joshua Haberman4111d132021-12-04 18:42:53 -0800633 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700634void PyUpb_Message_EnsureReified(PyUpb_Message* self) {
635 if (!PyUpb_Message_IsStub(self)) return;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800636 upb_Arena* arena = PyUpb_Arena_Get(self->arena);
Joshua Haberman32ebb482021-12-08 20:06:07 -0800637
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800638 // This is a non-present message. We need to create a real upb_Message for
639 // this object and every parent until we reach a present message.
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700640 PyUpb_Message* child = self;
641 PyUpb_Message* parent = self->ptr.parent;
642 const upb_FieldDef* child_f = PyUpb_Message_InitAsMsg(child, arena);
643 Py_INCREF(child); // To avoid a special-case in PyUpb_Message_SetField().
Joshua Haberman32ebb482021-12-08 20:06:07 -0800644
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800645 do {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700646 PyUpb_Message* next_parent = parent->ptr.parent;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800647 const upb_FieldDef* parent_f = NULL;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700648 if (PyUpb_Message_IsStub(parent)) {
649 parent_f = PyUpb_Message_InitAsMsg(parent, arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800650 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700651 PyUpb_Message_SetField(parent, child_f, child, arena);
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800652 child = parent;
Joshua Haberman32ebb482021-12-08 20:06:07 -0800653 child_f = parent_f;
Joshua Haberman4111d132021-12-04 18:42:53 -0800654 parent = next_parent;
Joshua Haberman32ebb482021-12-08 20:06:07 -0800655 } while (child_f);
Joshua Haberman4111d132021-12-04 18:42:53 -0800656
Joshua Haberman32ebb482021-12-08 20:06:07 -0800657 // Releases ref previously owned by child->ptr.parent of our child.
658 Py_DECREF(child);
659 self->version++;
Joshua Haberman4111d132021-12-04 18:42:53 -0800660}
661
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700662static void PyUpb_Message_SyncSubobjs(PyUpb_Message* self);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800663
664/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700665 * PyUpb_Message_Reify()
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800666 *
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800667 * The message equivalent of PyUpb_*Container_Reify(), this transitions
Joshua Haberman1c955f32022-01-12 07:19:28 -0800668 * the wrapper from the unset state (owning a reference on self->ptr.parent) to
669 * the set state (having a non-owning pointer to self->ptr.msg).
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800670 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700671static void PyUpb_Message_Reify(PyUpb_Message* self, const upb_FieldDef* f,
672 upb_Message* msg) {
673 assert(f == PyUpb_Message_GetFieldDef(self));
Joshua Haberman1be47592022-01-09 10:27:09 -0800674 if (!msg) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700675 const upb_MessageDef* msgdef = PyUpb_Message_GetMsgdef((PyObject*)self);
Eric Salo41335a02022-10-10 13:53:47 -0700676 const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef);
677 msg = upb_Message_New(layout, PyUpb_Arena_Get(self->arena));
Joshua Haberman1be47592022-01-09 10:27:09 -0800678 }
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800679 PyUpb_ObjCache_Add(msg, &self->ob_base);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800680 Py_DECREF(&self->ptr.parent->ob_base);
681 self->ptr.msg = msg; // Overwrites self->ptr.parent
Joshua Haberman1c955f32022-01-12 07:19:28 -0800682 self->def = (uintptr_t)upb_FieldDef_MessageSubDef(f);
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700683 PyUpb_Message_SyncSubobjs(self);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800684}
685
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800686/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700687 * PyUpb_Message_SyncSubobjs()
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800688 *
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800689 * This operation must be invoked whenever the underlying upb_Message has been
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800690 * mutated directly in C. This will attach any newly-present field data
Joshua Haberman54b775d2022-01-05 12:55:52 -0800691 * to previously returned stub wrapper objects.
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800692 *
693 * For example:
694 * foo = FooMessage()
695 * sub = foo.submsg # Empty, unset sub-message
696 *
697 * # SyncSubobjs() is required to connect our existing 'sub' wrapper to the
698 * # newly created foo.submsg data in C.
699 * foo.MergeFrom(FooMessage(submsg={}))
Joshua Haberman1c955f32022-01-12 07:19:28 -0800700 *
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800701 * This requires that all of the new sub-objects that have appeared are owned
702 * by `self`'s arena.
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800703 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700704static void PyUpb_Message_SyncSubobjs(PyUpb_Message* self) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800705 PyUpb_WeakMap* subobj_map = self->unset_subobj_map;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800706 if (!subobj_map) return;
707
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700708 upb_Message* msg = PyUpb_Message_GetMsg(self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800709 intptr_t iter = PYUPB_WEAKMAP_BEGIN;
710 const void* key;
711 PyObject* obj;
712
Joshua Haberman4111d132021-12-04 18:42:53 -0800713 // The last ref to this message could disappear during iteration.
Joshua Haberman1be47592022-01-09 10:27:09 -0800714 // When we call PyUpb_*Container_Reify() below, the container will drop
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800715 // its ref on `self`. If that was the last ref on self, the object will be
716 // deleted, and `subobj_map` along with it. We need it to live until we are
717 // done iterating.
Joshua Haberman4111d132021-12-04 18:42:53 -0800718 Py_INCREF(&self->ob_base);
719
720 while (PyUpb_WeakMap_Next(subobj_map, &key, &obj, &iter)) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800721 const upb_FieldDef* f = key;
722 if (upb_FieldDef_HasPresence(f) && !upb_Message_Has(msg, f)) continue;
723 upb_MessageValue msgval = upb_Message_Get(msg, f);
Joshua Haberman4111d132021-12-04 18:42:53 -0800724 PyUpb_WeakMap_DeleteIter(subobj_map, &iter);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800725 if (upb_FieldDef_IsMap(f)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800726 if (!msgval.map_val) continue;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800727 PyUpb_MapContainer_Reify(obj, (upb_Map*)msgval.map_val);
728 } else if (upb_FieldDef_IsRepeated(f)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800729 if (!msgval.array_val) continue;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800730 PyUpb_RepeatedContainer_Reify(obj, (upb_Array*)msgval.array_val);
Joshua Haberman4111d132021-12-04 18:42:53 -0800731 } else {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700732 PyUpb_Message* sub = (void*)obj;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800733 assert(self == sub->ptr.parent);
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700734 PyUpb_Message_Reify(sub, f, (upb_Message*)msgval.msg_val);
Joshua Haberman4111d132021-12-04 18:42:53 -0800735 }
736 }
737
738 Py_DECREF(&self->ob_base);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800739
740 // TODO(haberman): present fields need to be iterated too if they can reach
741 // a WeakMap.
Joshua Haberman4111d132021-12-04 18:42:53 -0800742}
743
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700744static PyObject* PyUpb_Message_ToString(PyUpb_Message* self) {
745 if (PyUpb_Message_IsStub(self)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800746 return PyUnicode_FromStringAndSize(NULL, 0);
747 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700748 upb_Message* msg = PyUpb_Message_GetMsg(self);
749 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800750 const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(msgdef));
Joshua Haberman4111d132021-12-04 18:42:53 -0800751 char buf[1024];
752 int options = UPB_TXTENC_SKIPUNKNOWN;
Joshua Habermancd214fe2022-01-12 10:43:49 -0800753 size_t size = upb_TextEncode(msg, msgdef, symtab, options, buf, sizeof(buf));
Joshua Haberman4111d132021-12-04 18:42:53 -0800754 if (size < sizeof(buf)) {
755 return PyUnicode_FromStringAndSize(buf, size);
756 } else {
757 char* buf2 = malloc(size + 1);
Joshua Habermancd214fe2022-01-12 10:43:49 -0800758 size_t size2 = upb_TextEncode(msg, msgdef, symtab, options, buf2, size + 1);
Joshua Haberman4111d132021-12-04 18:42:53 -0800759 assert(size == size2);
760 PyObject* ret = PyUnicode_FromStringAndSize(buf2, size2);
761 free(buf2);
762 return ret;
763 }
764}
765
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700766static PyObject* PyUpb_Message_RichCompare(PyObject* _self, PyObject* other,
767 int opid) {
768 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800769 if (opid != Py_EQ && opid != Py_NE) {
770 Py_INCREF(Py_NotImplemented);
771 return Py_NotImplemented;
772 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700773 bool ret = PyUpb_Message_IsEqual(self, other);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800774 if (opid == Py_NE) ret = !ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800775 return PyBool_FromLong(ret);
776}
777
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700778void PyUpb_Message_CacheDelete(PyObject* _self, const upb_FieldDef* f) {
779 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800780 PyUpb_WeakMap_Delete(self->unset_subobj_map, f);
781}
782
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700783void PyUpb_Message_SetConcreteSubobj(PyObject* _self, const upb_FieldDef* f,
784 upb_MessageValue subobj) {
785 PyUpb_Message* self = (void*)_self;
786 PyUpb_Message_EnsureReified(self);
787 PyUpb_Message_CacheDelete(_self, f);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800788 upb_Message_Set(self->ptr.msg, f, subobj, PyUpb_Arena_Get(self->arena));
Joshua Haberman4111d132021-12-04 18:42:53 -0800789}
790
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700791static void PyUpb_Message_Dealloc(PyObject* _self) {
792 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800793
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700794 if (PyUpb_Message_IsStub(self)) {
795 PyUpb_Message_CacheDelete((PyObject*)self->ptr.parent,
796 PyUpb_Message_GetFieldDef(self));
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800797 Py_DECREF(self->ptr.parent);
Joshua Haberman4111d132021-12-04 18:42:53 -0800798 } else {
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800799 PyUpb_ObjCache_Delete(self->ptr.msg);
Joshua Haberman4111d132021-12-04 18:42:53 -0800800 }
801
802 if (self->unset_subobj_map) {
803 PyUpb_WeakMap_Free(self->unset_subobj_map);
804 }
805
806 Py_DECREF(self->arena);
807
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700808 // We do not use PyUpb_Dealloc() here because Message is a base type and for
Joshua Haberman4111d132021-12-04 18:42:53 -0800809 // base types there is a bug we have to work around in this case (see below).
810 PyTypeObject* tp = Py_TYPE(self);
811 freefunc tp_free = PyType_GetSlot(tp, Py_tp_free);
812 tp_free(self);
813
814 if (cpython_bits.python_version_hex >= 0x03080000) {
815 // Prior to Python 3.8 there is a bug where deallocating the type here would
816 // lead to a double-decref: https://bugs.python.org/issue37879
817 Py_DECREF(tp);
818 }
819}
820
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700821PyObject* PyUpb_Message_Get(upb_Message* u_msg, const upb_MessageDef* m,
822 PyObject* arena) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800823 PyObject* ret = PyUpb_ObjCache_Get(u_msg);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800824 if (ret) return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800825
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800826 PyObject* cls = PyUpb_Descriptor_GetClass(m);
827 // It is not safe to use PyObject_{,GC}_New() due to:
828 // https://bugs.python.org/issue35810
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700829 PyUpb_Message* py_msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800830 py_msg->arena = arena;
831 py_msg->def = (uintptr_t)m;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800832 py_msg->ptr.msg = u_msg;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800833 py_msg->unset_subobj_map = NULL;
834 py_msg->ext_dict = NULL;
835 py_msg->version = 0;
836 ret = &py_msg->ob_base;
837 Py_DECREF(cls);
838 Py_INCREF(arena);
839 PyUpb_ObjCache_Add(u_msg, ret);
840 return ret;
841}
842
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700843/* PyUpb_Message_GetStub()
Joshua Habermane5d8d282022-01-05 15:47:59 -0800844 *
845 * Non-present messages return "stub" objects that point to their parent, but
846 * will materialize into real upb objects if they are mutated.
Joshua Haberman1c955f32022-01-12 07:19:28 -0800847 *
Joshua Habermane5d8d282022-01-05 15:47:59 -0800848 * Note: we do *not* create stubs for repeated/map fields unless the parent
849 * is a stub:
Joshua Haberman1c955f32022-01-12 07:19:28 -0800850 *
Joshua Habermane5d8d282022-01-05 15:47:59 -0800851 * msg = TestMessage()
852 * msg.submessage # (A) Creates a stub
853 * msg.repeated_foo # (B) Does *not* create a stub
854 * msg.submessage.repeated_bar # (C) Creates a stub
Joshua Haberman1c955f32022-01-12 07:19:28 -0800855 *
Joshua Habermane5d8d282022-01-05 15:47:59 -0800856 * In case (B) we have some freedom: we could either create a stub, or create
857 * a reified object with underlying data. It appears that either could work
858 * equally well, with no observable change to users. There isn't a clear
859 * advantage to either choice. We choose to follow the behavior of the
860 * pre-existing C++ behavior for consistency, but if it becomes apparent that
861 * there would be some benefit to reversing this decision, it should be totally
862 * within the realm of possibility.
863 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700864PyObject* PyUpb_Message_GetStub(PyUpb_Message* self,
865 const upb_FieldDef* field) {
Joshua Haberman455426e2021-12-08 23:32:05 -0800866 PyObject* _self = (void*)self;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800867 if (!self->unset_subobj_map) {
868 self->unset_subobj_map = PyUpb_WeakMap_New();
869 }
870 PyObject* subobj = PyUpb_WeakMap_Get(self->unset_subobj_map, field);
871
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800872 if (subobj) return subobj;
873
Joshua Haberman1c955f32022-01-12 07:19:28 -0800874 if (upb_FieldDef_IsMap(field)) {
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800875 subobj = PyUpb_MapContainer_NewStub(_self, field, self->arena);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800876 } else if (upb_FieldDef_IsRepeated(field)) {
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800877 subobj = PyUpb_RepeatedContainer_NewStub(_self, field, self->arena);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800878 } else {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700879 subobj = PyUpb_Message_NewStub(&self->ob_base, field, self->arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800880 }
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800881 PyUpb_WeakMap_Add(self->unset_subobj_map, field, subobj);
Joshua Haberman4111d132021-12-04 18:42:53 -0800882
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800883 assert(!PyErr_Occurred());
884 return subobj;
885}
886
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700887PyObject* PyUpb_Message_GetPresentWrapper(PyUpb_Message* self,
888 const upb_FieldDef* field) {
889 assert(!PyUpb_Message_IsStub(self));
Joshua Haberman1c955f32022-01-12 07:19:28 -0800890 upb_MutableMessageValue mutval =
891 upb_Message_Mutable(self->ptr.msg, field, PyUpb_Arena_Get(self->arena));
892 if (upb_FieldDef_IsMap(field)) {
Joshua Habermanbf74b3e2021-12-30 00:52:12 -0800893 return PyUpb_MapContainer_GetOrCreateWrapper(mutval.map, field,
894 self->arena);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800895 } else {
Joshua Haberman455426e2021-12-08 23:32:05 -0800896 return PyUpb_RepeatedContainer_GetOrCreateWrapper(mutval.array, field,
897 self->arena);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800898 }
899}
900
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700901PyObject* PyUpb_Message_GetScalarValue(PyUpb_Message* self,
902 const upb_FieldDef* field) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800903 upb_MessageValue val;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700904 if (PyUpb_Message_IsStub(self)) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800905 // Unset message always returns default values.
Joshua Haberman1c955f32022-01-12 07:19:28 -0800906 val = upb_FieldDef_Default(field);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800907 } else {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800908 val = upb_Message_Get(self->ptr.msg, field);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800909 }
910 return PyUpb_UpbToPy(val, field, self->arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800911}
912
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800913/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700914 * PyUpb_Message_GetFieldValue()
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800915 *
916 * Implements the equivalent of getattr(msg, field), once `field` has
Joshua Haberman1c955f32022-01-12 07:19:28 -0800917 * already been resolved to a `upb_FieldDef*`.
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800918 *
919 * This may involve constructing a wrapper object for the given field, or
920 * returning one that was previously constructed. If the field is not actually
921 * set, the wrapper object will be an "unset" object that is not actually
922 * connected to any C data.
923 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700924PyObject* PyUpb_Message_GetFieldValue(PyObject* _self,
925 const upb_FieldDef* field) {
926 PyUpb_Message* self = (void*)_self;
927 assert(upb_FieldDef_ContainingType(field) == PyUpb_Message_GetMsgdef(_self));
Joshua Haberman1c955f32022-01-12 07:19:28 -0800928 bool submsg = upb_FieldDef_IsSubMessage(field);
929 bool seq = upb_FieldDef_IsRepeated(field);
Joshua Haberman4111d132021-12-04 18:42:53 -0800930
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700931 if ((PyUpb_Message_IsStub(self) && (submsg || seq)) ||
Joshua Haberman1c955f32022-01-12 07:19:28 -0800932 (submsg && !seq && !upb_Message_Has(self->ptr.msg, field))) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700933 return PyUpb_Message_GetStub(self, field);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800934 } else if (seq) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700935 return PyUpb_Message_GetPresentWrapper(self, field);
Joshua Haberman4111d132021-12-04 18:42:53 -0800936 } else {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700937 return PyUpb_Message_GetScalarValue(self, field);
Joshua Haberman4111d132021-12-04 18:42:53 -0800938 }
939}
940
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700941int PyUpb_Message_SetFieldValue(PyObject* _self, const upb_FieldDef* field,
942 PyObject* value, PyObject* exc) {
943 PyUpb_Message* self = (void*)_self;
Joshua Haberman0549fc02022-01-01 15:42:51 -0800944 assert(value);
945
Joshua Haberman1c955f32022-01-12 07:19:28 -0800946 if (upb_FieldDef_IsSubMessage(field) || upb_FieldDef_IsRepeated(field)) {
Joshua Haberman3eae44b2022-01-09 22:08:08 -0800947 PyErr_Format(exc,
Joshua Haberman4111d132021-12-04 18:42:53 -0800948 "Assignment not allowed to message, map, or repeated "
949 "field \"%s\" in protocol message object.",
Joshua Haberman1c955f32022-01-12 07:19:28 -0800950 upb_FieldDef_Name(field));
Joshua Haberman4111d132021-12-04 18:42:53 -0800951 return -1;
952 }
953
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700954 PyUpb_Message_EnsureReified(self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800955
Joshua Haberman1c955f32022-01-12 07:19:28 -0800956 upb_MessageValue val;
957 upb_Arena* arena = PyUpb_Arena_Get(self->arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800958 if (!PyUpb_PyToUpb(value, field, &val, arena)) {
959 return -1;
960 }
961
Joshua Haberman1c955f32022-01-12 07:19:28 -0800962 upb_Message_Set(self->ptr.msg, field, val, arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800963 return 0;
964}
965
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700966int PyUpb_Message_GetVersion(PyObject* _self) {
967 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800968 return self->version;
969}
970
Joshua Haberman4111d132021-12-04 18:42:53 -0800971/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700972 * PyUpb_Message_GetAttr()
Joshua Haberman4111d132021-12-04 18:42:53 -0800973 *
974 * Implements:
975 * foo = msg.foo
976 *
977 * Attribute lookup must find both message fields and base class methods like
978 * msg.SerializeToString().
979 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700980__attribute__((flatten)) static PyObject* PyUpb_Message_GetAttr(
Joshua Haberman4111d132021-12-04 18:42:53 -0800981 PyObject* _self, PyObject* attr) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700982 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800983
984 // Lookup field by name.
Joshua Haberman1c955f32022-01-12 07:19:28 -0800985 const upb_FieldDef* field;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700986 if (PyUpb_Message_LookupName(self, attr, &field, NULL, NULL)) {
987 return PyUpb_Message_GetFieldValue(_self, field);
Joshua Haberman4111d132021-12-04 18:42:53 -0800988 }
989
990 // Check base class attributes.
991 assert(!PyErr_Occurred());
992 PyObject* ret = PyObject_GenericGetAttr(_self, attr);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800993 if (ret) return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800994
Joshua Haberman14372452021-12-31 12:02:36 -0800995 // Swallow AttributeError if it occurred and try again on the metaclass
996 // to pick up class attributes. But we have to special-case "Extensions"
997 // which affirmatively returns AttributeError when a message is not
998 // extendable.
Joshua Habermanb38e4a42022-01-16 19:27:55 -0800999 const char* name;
Joshua Haberman14372452021-12-31 12:02:36 -08001000 if (PyErr_ExceptionMatches(PyExc_AttributeError) &&
Joshua Habermanb38e4a42022-01-16 19:27:55 -08001001 (name = PyUpb_GetStrData(attr)) && strcmp(name, "Extensions") != 0) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001002 PyErr_Clear();
1003 return PyUpb_MessageMeta_GetAttr((PyObject*)Py_TYPE(_self), attr);
Joshua Haberman4111d132021-12-04 18:42:53 -08001004 }
Joshua Haberman4111d132021-12-04 18:42:53 -08001005
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001006 return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001007}
1008
1009/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001010 * PyUpb_Message_SetAttr()
Joshua Haberman4111d132021-12-04 18:42:53 -08001011 *
1012 * Implements:
1013 * msg.foo = foo
1014 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001015static int PyUpb_Message_SetAttr(PyObject* _self, PyObject* attr,
1016 PyObject* value) {
1017 PyUpb_Message* self = (void*)_self;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001018 const upb_FieldDef* field;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001019 if (!PyUpb_Message_LookupName(self, attr, &field, NULL,
1020 PyExc_AttributeError)) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001021 return -1;
1022 }
1023
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001024 return PyUpb_Message_SetFieldValue(_self, field, value, PyExc_AttributeError);
Joshua Haberman4111d132021-12-04 18:42:53 -08001025}
1026
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001027static PyObject* PyUpb_Message_HasField(PyObject* _self, PyObject* arg) {
1028 PyUpb_Message* self = (void*)_self;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001029 const upb_FieldDef* field;
1030 const upb_OneofDef* oneof;
Joshua Haberman4111d132021-12-04 18:42:53 -08001031
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001032 if (!PyUpb_Message_LookupName(self, arg, &field, &oneof, PyExc_ValueError)) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001033 return NULL;
1034 }
1035
Joshua Haberman1c955f32022-01-12 07:19:28 -08001036 if (field && !upb_FieldDef_HasPresence(field)) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001037 PyErr_Format(PyExc_ValueError, "Field %s does not have presence.",
Joshua Haberman1c955f32022-01-12 07:19:28 -08001038 upb_FieldDef_FullName(field));
Joshua Haberman4111d132021-12-04 18:42:53 -08001039 return NULL;
1040 }
1041
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001042 if (PyUpb_Message_IsStub(self)) Py_RETURN_FALSE;
Joshua Haberman4111d132021-12-04 18:42:53 -08001043
Joshua Haberman1c955f32022-01-12 07:19:28 -08001044 return PyBool_FromLong(field ? upb_Message_Has(self->ptr.msg, field)
1045 : upb_Message_WhichOneof(self->ptr.msg, oneof) !=
1046 NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -08001047}
1048
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001049static PyObject* PyUpb_Message_FindInitializationErrors(PyObject* _self,
1050 PyObject* arg);
Joshua Habermancbe314d2022-01-09 17:25:10 -08001051
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001052static PyObject* PyUpb_Message_IsInitializedAppendErrors(PyObject* _self,
1053 PyObject* errors) {
1054 PyObject* list = PyUpb_Message_FindInitializationErrors(_self, NULL);
Joshua Habermand8915b32022-01-09 23:04:44 -08001055 if (!list) return NULL;
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001056 bool ok = PyList_Size(list) == 0;
1057 PyObject* ret = NULL;
Joshua Haberman201d2262022-01-10 10:05:09 -08001058 PyObject* extend_result = NULL;
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001059 if (!ok) {
Joshua Haberman201d2262022-01-10 10:05:09 -08001060 extend_result = PyObject_CallMethod(errors, "extend", "O", list);
1061 if (!extend_result) goto done;
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001062 }
1063 ret = PyBool_FromLong(ok);
1064
1065done:
Joshua Habermand8915b32022-01-09 23:04:44 -08001066 Py_XDECREF(list);
Joshua Haberman201d2262022-01-10 10:05:09 -08001067 Py_XDECREF(extend_result);
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001068 return ret;
Joshua Habermand8915b32022-01-09 23:04:44 -08001069}
1070
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001071static PyObject* PyUpb_Message_IsInitialized(PyObject* _self, PyObject* args) {
Joshua Habermancbe314d2022-01-09 17:25:10 -08001072 PyObject* errors = NULL;
1073 if (!PyArg_ParseTuple(args, "|O", &errors)) {
1074 return NULL;
1075 }
Joshua Habermancbe314d2022-01-09 17:25:10 -08001076 if (errors) {
Joshua Habermand8915b32022-01-09 23:04:44 -08001077 // We need to collect a list of unset required fields and append it to
1078 // `errors`.
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001079 return PyUpb_Message_IsInitializedAppendErrors(_self, errors);
Joshua Habermancbe314d2022-01-09 17:25:10 -08001080 } else {
Joshua Habermand8915b32022-01-09 23:04:44 -08001081 // We just need to return a boolean "true" or "false" for whether all
1082 // required fields are set.
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001083 upb_Message* msg = PyUpb_Message_GetIfReified(_self);
1084 const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001085 const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m));
Joshua Habermancbe314d2022-01-09 17:25:10 -08001086 bool initialized = !upb_util_HasUnsetRequired(msg, m, symtab, NULL);
1087 return PyBool_FromLong(initialized);
1088 }
1089}
1090
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001091static PyObject* PyUpb_Message_ListFieldsItemKey(PyObject* self,
1092 PyObject* val) {
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001093 assert(PyTuple_Check(val));
1094 PyObject* field = PyTuple_GetItem(val, 0);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001095 const upb_FieldDef* f = PyUpb_FieldDescriptor_GetDef(field);
1096 return PyLong_FromLong(upb_FieldDef_Number(f));
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001097}
1098
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001099static PyObject* PyUpb_Message_CheckCalledFromGeneratedFile(
Joshua Haberman4e2bbc82022-05-17 10:08:55 -07001100 PyObject* unused, PyObject* unused_arg) {
1101 PyErr_SetString(
1102 PyExc_TypeError,
1103 "Descriptors cannot not be created directly.\n"
1104 "If this call came from a _pb2.py file, your generated code is out of "
1105 "date and must be regenerated with protoc >= 3.19.0.\n"
1106 "If you cannot immediately regenerate your protos, some other possible "
1107 "workarounds are:\n"
1108 " 1. Downgrade the protobuf package to 3.20.x or lower.\n"
1109 " 2. Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python (but this will "
1110 "use pure-Python parsing and will be much slower).\n"
1111 "\n"
1112 "More information: "
1113 "https://developers.google.com/protocol-buffers/docs/news/"
1114 "2022-05-06#python-updates");
1115 return NULL;
1116}
1117
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001118static bool PyUpb_Message_SortFieldList(PyObject* list) {
Joshua Habermand4c0c632022-01-09 23:16:18 -08001119 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1120 bool ok = false;
Joshua Habermanffdcc462022-01-12 08:38:36 -08001121 PyObject* args = PyTuple_New(0);
Joshua Habermand4c0c632022-01-09 23:16:18 -08001122 PyObject* kwargs = PyDict_New();
Joshua Haberman4c005382022-01-09 23:17:20 -08001123 PyObject* method = PyObject_GetAttrString(list, "sort");
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001124 PyObject* call_result = NULL;
Joshua Haberman4c005382022-01-09 23:17:20 -08001125 if (!args || !kwargs || !method) goto err;
Joshua Habermand4c0c632022-01-09 23:16:18 -08001126 if (PyDict_SetItemString(kwargs, "key", state->listfields_item_key) < 0) {
1127 goto err;
1128 }
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001129 call_result = PyObject_Call(method, args, kwargs);
1130 if (!call_result) goto err;
Joshua Habermand4c0c632022-01-09 23:16:18 -08001131 ok = true;
1132
Joshua Haberman1c955f32022-01-12 07:19:28 -08001133err:
Joshua Haberman4c005382022-01-09 23:17:20 -08001134 Py_XDECREF(method);
Joshua Habermand4c0c632022-01-09 23:16:18 -08001135 Py_XDECREF(args);
1136 Py_XDECREF(kwargs);
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001137 Py_XDECREF(call_result);
1138 return ok;
Joshua Habermand4c0c632022-01-09 23:16:18 -08001139}
1140
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001141static PyObject* PyUpb_Message_ListFields(PyObject* _self, PyObject* arg) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001142 PyObject* list = PyList_New(0);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001143 upb_Message* msg = PyUpb_Message_GetIfReified(_self);
Joshua Haberman4423e912021-12-27 18:04:58 -08001144 if (!msg) return list;
Joshua Haberman4111d132021-12-04 18:42:53 -08001145
Joshua Haberman1c955f32022-01-12 07:19:28 -08001146 size_t iter1 = kUpb_Message_Begin;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001147 const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001148 const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m));
1149 const upb_FieldDef* f;
Joshua Haberman4423e912021-12-27 18:04:58 -08001150 PyObject* field_desc = NULL;
1151 PyObject* py_val = NULL;
1152 PyObject* tuple = NULL;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001153 upb_MessageValue val;
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001154 uint32_t last_field = 0;
1155 bool in_order = true;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001156 while (upb_Message_Next(msg, m, symtab, &f, &val, &iter1)) {
1157 const uint32_t field_number = upb_FieldDef_Number(f);
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001158 if (field_number < last_field) in_order = false;
1159 last_field = field_number;
Joshua Haberman4423e912021-12-27 18:04:58 -08001160 PyObject* field_desc = PyUpb_FieldDescriptor_Get(f);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001161 PyObject* py_val = PyUpb_Message_GetFieldValue(_self, f);
Joshua Haberman4423e912021-12-27 18:04:58 -08001162 if (!field_desc || !py_val) goto err;
1163 PyObject* tuple = Py_BuildValue("(NN)", field_desc, py_val);
1164 field_desc = NULL;
1165 py_val = NULL;
1166 if (!tuple) goto err;
Joshua Habermanaee30142021-12-28 20:27:17 -08001167 if (PyList_Append(list, tuple)) goto err;
Joshua Haberman4423e912021-12-27 18:04:58 -08001168 Py_DECREF(tuple);
1169 tuple = NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001170 }
1171
Joshua Haberman4c005382022-01-09 23:17:20 -08001172 // Users rely on fields being returned in field number order.
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001173 if (!in_order && !PyUpb_Message_SortFieldList(list)) goto err;
Joshua Haberman4c005382022-01-09 23:17:20 -08001174
Joshua Haberman4111d132021-12-04 18:42:53 -08001175 return list;
Joshua Haberman4423e912021-12-27 18:04:58 -08001176
1177err:
1178 Py_XDECREF(field_desc);
1179 Py_XDECREF(py_val);
1180 Py_XDECREF(tuple);
1181 Py_DECREF(list);
1182 return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001183}
1184
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001185PyObject* PyUpb_Message_MergeFrom(PyObject* self, PyObject* arg) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001186 if (self->ob_type != arg->ob_type) {
1187 PyErr_Format(PyExc_TypeError,
1188 "Parameter to MergeFrom() must be instance of same class: "
1189 "expected %S got %S.",
1190 Py_TYPE(self), Py_TYPE(arg));
1191 return NULL;
1192 }
1193 // OPT: exit if src is empty.
1194 PyObject* subargs = PyTuple_New(0);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001195 PyObject* serialized = PyUpb_Message_SerializeToString(arg, subargs, NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -08001196 Py_DECREF(subargs);
1197 if (!serialized) return NULL;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001198 PyObject* ret = PyUpb_Message_MergeFromString(self, serialized);
Joshua Haberman4111d132021-12-04 18:42:53 -08001199 Py_DECREF(serialized);
1200 Py_DECREF(ret);
1201 Py_RETURN_NONE;
1202}
1203
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001204static PyObject* PyUpb_Message_SetInParent(PyObject* _self, PyObject* arg) {
1205 PyUpb_Message* self = (void*)_self;
1206 PyUpb_Message_EnsureReified(self);
Joshua Haberman4111d132021-12-04 18:42:53 -08001207 Py_RETURN_NONE;
1208}
1209
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001210static PyObject* PyUpb_Message_UnknownFields(PyObject* _self, PyObject* arg) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001211 // TODO(haberman): re-enable when unknown fields are added.
1212 // return PyUpb_UnknownFields_New(_self);
1213 PyErr_SetString(PyExc_NotImplementedError, "unknown field accessor");
1214 return NULL;
1215}
1216
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001217PyObject* PyUpb_Message_MergeFromString(PyObject* _self, PyObject* arg) {
1218 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -08001219 char* buf;
1220 Py_ssize_t size;
1221 PyObject* bytes = NULL;
1222
1223 if (PyMemoryView_Check(arg)) {
1224 bytes = PyBytes_FromObject(arg);
Joshua Haberman6bb891e2021-12-08 15:29:48 -08001225 // Cannot fail when passed something of the correct type.
1226 int err = PyBytes_AsStringAndSize(bytes, &buf, &size);
1227 (void)err;
1228 assert(err >= 0);
Joshua Haberman4111d132021-12-04 18:42:53 -08001229 } else if (PyBytes_AsStringAndSize(arg, &buf, &size) < 0) {
1230 return NULL;
1231 }
1232
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001233 PyUpb_Message_EnsureReified(self);
1234 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001235 const upb_FileDef* file = upb_MessageDef_File(msgdef);
Joshua Haberman499c2cc2022-01-12 09:09:59 -08001236 const upb_ExtensionRegistry* extreg =
Joshua Haberman1c955f32022-01-12 07:19:28 -08001237 upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
1238 const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef);
1239 upb_Arena* arena = PyUpb_Arena_Get(self->arena);
Joshua Haberman14372452021-12-31 12:02:36 -08001240 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
Joshua Haberman5b3447e2021-12-31 15:37:23 -08001241 int options =
Joshua Haberman14372452021-12-31 12:02:36 -08001242 UPB_DECODE_MAXDEPTH(state->allow_oversize_protos ? UINT32_MAX : 100);
Joshua Haberman4111d132021-12-04 18:42:53 -08001243 upb_DecodeStatus status =
Joshua Haberman72af9dc2022-01-12 10:04:02 -08001244 upb_Decode(buf, size, self->ptr.msg, layout, extreg, options, arena);
Joshua Haberman4111d132021-12-04 18:42:53 -08001245 Py_XDECREF(bytes);
1246 if (status != kUpb_DecodeStatus_Ok) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001247 PyErr_Format(state->decode_error_class, "Error parsing message");
1248 return NULL;
1249 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001250 PyUpb_Message_SyncSubobjs(self);
Joshua Haberman4111d132021-12-04 18:42:53 -08001251 return PyLong_FromSsize_t(size);
1252}
1253
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001254static PyObject* PyUpb_Message_Clear(PyUpb_Message* self, PyObject* args);
Joshua Haberman4111d132021-12-04 18:42:53 -08001255
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001256static PyObject* PyUpb_Message_ParseFromString(PyObject* self, PyObject* arg) {
1257 PyObject* tmp = PyUpb_Message_Clear((PyUpb_Message*)self, NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -08001258 Py_DECREF(tmp);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001259 return PyUpb_Message_MergeFromString(self, arg);
Joshua Haberman4111d132021-12-04 18:42:53 -08001260}
1261
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001262static PyObject* PyUpb_Message_ByteSize(PyObject* self, PyObject* args) {
Joshua Haberman6bb891e2021-12-08 15:29:48 -08001263 // TODO(https://github.com/protocolbuffers/upb/issues/462): At the moment upb
1264 // does not have a "byte size" function, so we just serialize to string and
1265 // get the size of the string.
Joshua Haberman4111d132021-12-04 18:42:53 -08001266 PyObject* subargs = PyTuple_New(0);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001267 PyObject* serialized = PyUpb_Message_SerializeToString(self, subargs, NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -08001268 Py_DECREF(subargs);
1269 if (!serialized) return NULL;
1270 size_t size = PyBytes_Size(serialized);
1271 Py_DECREF(serialized);
1272 return PyLong_FromSize_t(size);
1273}
1274
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001275static PyObject* PyUpb_Message_Clear(PyUpb_Message* self, PyObject* args) {
1276 PyUpb_Message_EnsureReified(self);
1277 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1be47592022-01-09 10:27:09 -08001278 PyUpb_WeakMap* subobj_map = self->unset_subobj_map;
1279
1280 if (subobj_map) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001281 upb_Message* msg = PyUpb_Message_GetMsg(self);
Joshua Habermanc3cfd092022-05-10 08:52:45 -07001282 (void)msg; // Suppress unused warning when asserts are disabled.
Joshua Haberman1be47592022-01-09 10:27:09 -08001283 intptr_t iter = PYUPB_WEAKMAP_BEGIN;
1284 const void* key;
1285 PyObject* obj;
1286
1287 while (PyUpb_WeakMap_Next(subobj_map, &key, &obj, &iter)) {
Joshua Haberman1c955f32022-01-12 07:19:28 -08001288 const upb_FieldDef* f = key;
Joshua Haberman1be47592022-01-09 10:27:09 -08001289 PyUpb_WeakMap_DeleteIter(subobj_map, &iter);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001290 if (upb_FieldDef_IsMap(f)) {
1291 assert(upb_Message_Get(msg, f).map_val == NULL);
Joshua Haberman1be47592022-01-09 10:27:09 -08001292 PyUpb_MapContainer_Reify(obj, NULL);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001293 } else if (upb_FieldDef_IsRepeated(f)) {
1294 assert(upb_Message_Get(msg, f).array_val == NULL);
Joshua Haberman1be47592022-01-09 10:27:09 -08001295 PyUpb_RepeatedContainer_Reify(obj, NULL);
1296 } else {
Joshua Haberman1c955f32022-01-12 07:19:28 -08001297 assert(!upb_Message_Has(msg, f));
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001298 PyUpb_Message* sub = (void*)obj;
Joshua Haberman1be47592022-01-09 10:27:09 -08001299 assert(self == sub->ptr.parent);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001300 PyUpb_Message_Reify(sub, f, NULL);
Joshua Haberman1be47592022-01-09 10:27:09 -08001301 }
1302 }
1303 }
1304
Joshua Haberman1c955f32022-01-12 07:19:28 -08001305 upb_Message_Clear(self->ptr.msg, msgdef);
Joshua Haberman4111d132021-12-04 18:42:53 -08001306 Py_RETURN_NONE;
1307}
1308
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001309void PyUpb_Message_DoClearField(PyObject* _self, const upb_FieldDef* f) {
1310 PyUpb_Message* self = (void*)_self;
1311 PyUpb_Message_EnsureReified((PyUpb_Message*)self);
Joshua Haberman54b775d2022-01-05 12:55:52 -08001312
1313 // We must ensure that any stub object is reified so its parent no longer
1314 // points to us.
1315 PyObject* sub = self->unset_subobj_map
1316 ? PyUpb_WeakMap_Get(self->unset_subobj_map, f)
1317 : NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001318
Joshua Haberman1c955f32022-01-12 07:19:28 -08001319 if (upb_FieldDef_IsMap(f)) {
Joshua Haberman54b775d2022-01-05 12:55:52 -08001320 // For maps we additionally have to invalidate any iterators. So we need
1321 // to get an object even if it's reified.
1322 if (!sub) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001323 sub = PyUpb_Message_GetFieldValue(_self, f);
Joshua Haberman4111d132021-12-04 18:42:53 -08001324 }
Joshua Haberman54b775d2022-01-05 12:55:52 -08001325 PyUpb_MapContainer_EnsureReified(sub);
1326 PyUpb_MapContainer_Invalidate(sub);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001327 } else if (upb_FieldDef_IsRepeated(f)) {
Joshua Haberman54b775d2022-01-05 12:55:52 -08001328 if (sub) {
Joshua Habermane5d8d282022-01-05 15:47:59 -08001329 PyUpb_RepeatedContainer_EnsureReified(sub);
Joshua Haberman4111d132021-12-04 18:42:53 -08001330 }
Joshua Haberman1c955f32022-01-12 07:19:28 -08001331 } else if (upb_FieldDef_IsSubMessage(f)) {
Joshua Haberman54b775d2022-01-05 12:55:52 -08001332 if (sub) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001333 PyUpb_Message_EnsureReified((PyUpb_Message*)sub);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001334 }
Joshua Haberman4111d132021-12-04 18:42:53 -08001335 }
1336
Joshua Haberman54b775d2022-01-05 12:55:52 -08001337 Py_XDECREF(sub);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001338 upb_Message_ClearField(self->ptr.msg, f);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001339}
Joshua Haberman4111d132021-12-04 18:42:53 -08001340
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001341static PyObject* PyUpb_Message_ClearExtension(PyObject* _self, PyObject* arg) {
1342 PyUpb_Message* self = (void*)_self;
1343 PyUpb_Message_EnsureReified(self);
1344 const upb_FieldDef* f = PyUpb_Message_GetExtensionDef(_self, arg);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001345 if (!f) return NULL;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001346 PyUpb_Message_DoClearField(_self, f);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001347 Py_RETURN_NONE;
1348}
1349
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001350static PyObject* PyUpb_Message_ClearField(PyObject* _self, PyObject* arg) {
1351 PyUpb_Message* self = (void*)_self;
Joshua Haberman0549fc02022-01-01 15:42:51 -08001352
Joshua Haberman54b775d2022-01-05 12:55:52 -08001353 // We always need EnsureReified() here (even for an unset message) to
Joshua Haberman0549fc02022-01-01 15:42:51 -08001354 // preserve behavior like:
1355 // msg = FooMessage()
1356 // msg.foo.Clear()
1357 // assert msg.HasField("foo")
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001358 PyUpb_Message_EnsureReified(self);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001359
Joshua Haberman1c955f32022-01-12 07:19:28 -08001360 const upb_FieldDef* f;
1361 const upb_OneofDef* o;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001362 if (!PyUpb_Message_LookupName(self, arg, &f, &o, PyExc_ValueError)) {
Joshua Haberman0549fc02022-01-01 15:42:51 -08001363 return NULL;
1364 }
1365
Joshua Haberman1c955f32022-01-12 07:19:28 -08001366 if (o) f = upb_Message_WhichOneof(self->ptr.msg, o);
Eric Salo27f8d362022-09-07 21:44:48 -07001367 if (f) PyUpb_Message_DoClearField(_self, f);
Joshua Haberman4111d132021-12-04 18:42:53 -08001368 Py_RETURN_NONE;
1369}
1370
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001371static PyObject* PyUpb_Message_DiscardUnknownFields(PyUpb_Message* self,
1372 PyObject* arg) {
1373 PyUpb_Message_EnsureReified(self);
1374 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001375 upb_Message_DiscardUnknown(self->ptr.msg, msgdef, 64);
Joshua Haberman4111d132021-12-04 18:42:53 -08001376 Py_RETURN_NONE;
1377}
1378
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001379static PyObject* PyUpb_Message_FindInitializationErrors(PyObject* _self,
1380 PyObject* arg) {
1381 PyUpb_Message* self = (void*)_self;
1382 upb_Message* msg = PyUpb_Message_GetIfReified(_self);
1383 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001384 const upb_DefPool* ext_pool = upb_FileDef_Pool(upb_MessageDef_File(msgdef));
Joshua Haberman4111d132021-12-04 18:42:53 -08001385 upb_FieldPathEntry* fields;
1386 PyObject* ret = PyList_New(0);
1387 if (upb_util_HasUnsetRequired(msg, msgdef, ext_pool, &fields)) {
1388 char* buf = NULL;
1389 size_t size = 0;
Joshua Habermancbe314d2022-01-09 17:25:10 -08001390 assert(fields->field);
1391 while (fields->field) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001392 upb_FieldPathEntry* field = fields;
1393 size_t need = upb_FieldPath_ToText(&fields, buf, size);
1394 if (need >= size) {
1395 fields = field;
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001396 size = size ? size * 2 : 16;
Joshua Haberman4111d132021-12-04 18:42:53 -08001397 while (size <= need) size *= 2;
1398 buf = realloc(buf, size);
1399 need = upb_FieldPath_ToText(&fields, buf, size);
1400 assert(size > need);
1401 }
Joshua Habermanffdcc462022-01-12 08:38:36 -08001402 PyObject* str = PyUnicode_FromString(buf);
1403 PyList_Append(ret, str);
1404 Py_DECREF(str);
Joshua Haberman4111d132021-12-04 18:42:53 -08001405 }
1406 free(buf);
1407 }
1408 return ret;
1409}
1410
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001411static PyObject* PyUpb_Message_FromString(PyObject* cls, PyObject* serialized) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001412 PyObject* ret = NULL;
1413 PyObject* length = NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001414
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001415 ret = PyObject_CallObject(cls, NULL);
1416 if (ret == NULL) goto err;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001417 length = PyUpb_Message_MergeFromString(ret, serialized);
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001418 if (length == NULL) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -08001419
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001420done:
1421 Py_XDECREF(length);
Joshua Haberman4111d132021-12-04 18:42:53 -08001422 return ret;
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001423
1424err:
1425 Py_XDECREF(ret);
1426 ret = NULL;
1427 goto done;
Joshua Haberman4111d132021-12-04 18:42:53 -08001428}
1429
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001430const upb_FieldDef* PyUpb_Message_GetExtensionDef(PyObject* _self,
1431 PyObject* key) {
Joshua Haberman1c955f32022-01-12 07:19:28 -08001432 const upb_FieldDef* f = PyUpb_FieldDescriptor_GetDef(key);
Joshua Haberman72603462022-01-01 16:08:29 -08001433 if (!f) {
1434 PyErr_Clear();
1435 PyErr_Format(PyExc_KeyError, "Object %R is not a field descriptor\n", key);
1436 return NULL;
1437 }
Joshua Haberman1c955f32022-01-12 07:19:28 -08001438 if (!upb_FieldDef_IsExtension(f)) {
Joshua Haberman72603462022-01-01 16:08:29 -08001439 PyErr_Format(PyExc_KeyError, "Field %s is not an extension\n",
Joshua Haberman1c955f32022-01-12 07:19:28 -08001440 upb_FieldDef_FullName(f));
Joshua Haberman72603462022-01-01 16:08:29 -08001441 return NULL;
1442 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001443 const upb_MessageDef* msgdef = PyUpb_Message_GetMsgdef(_self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001444 if (upb_FieldDef_ContainingType(f) != msgdef) {
Joshua Haberman72603462022-01-01 16:08:29 -08001445 PyErr_Format(PyExc_KeyError, "Extension doesn't match (%s vs %s)",
Joshua Haberman1c955f32022-01-12 07:19:28 -08001446 upb_MessageDef_FullName(msgdef), upb_FieldDef_FullName(f));
Joshua Haberman72603462022-01-01 16:08:29 -08001447 return NULL;
1448 }
1449 return f;
1450}
1451
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001452static PyObject* PyUpb_Message_HasExtension(PyObject* _self,
1453 PyObject* ext_desc) {
1454 upb_Message* msg = PyUpb_Message_GetIfReified(_self);
1455 const upb_FieldDef* f = PyUpb_Message_GetExtensionDef(_self, ext_desc);
Joshua Haberman4111d132021-12-04 18:42:53 -08001456 if (!f) return NULL;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001457 if (upb_FieldDef_IsRepeated(f)) {
Joshua Haberman72603462022-01-01 16:08:29 -08001458 PyErr_SetString(PyExc_KeyError,
1459 "Field is repeated. A singular method is required.");
1460 return NULL;
1461 }
Joshua Haberman4111d132021-12-04 18:42:53 -08001462 if (!msg) Py_RETURN_FALSE;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001463 return PyBool_FromLong(upb_Message_Has(msg, f));
Joshua Haberman4111d132021-12-04 18:42:53 -08001464}
1465
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001466void PyUpb_Message_ReportInitializationErrors(const upb_MessageDef* msgdef,
1467 PyObject* errors, PyObject* exc) {
Joshua Habermanfff8dfb2022-01-09 23:31:27 -08001468 PyObject* comma = PyUnicode_FromString(",");
1469 PyObject* missing_fields = NULL;
1470 if (!comma) goto done;
1471 missing_fields = PyUnicode_Join(comma, errors);
1472 if (!missing_fields) goto done;
1473 PyErr_Format(exc, "Message %s is missing required fields: %U",
Joshua Haberman1c955f32022-01-12 07:19:28 -08001474 upb_MessageDef_FullName(msgdef), missing_fields);
Joshua Habermanfff8dfb2022-01-09 23:31:27 -08001475done:
1476 Py_XDECREF(comma);
1477 Py_XDECREF(missing_fields);
1478 Py_DECREF(errors);
1479}
1480
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001481PyObject* PyUpb_Message_SerializeInternal(PyObject* _self, PyObject* args,
1482 PyObject* kwargs,
1483 bool check_required) {
1484 PyUpb_Message* self = (void*)_self;
1485 if (!PyUpb_Message_Verify((PyObject*)self)) return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001486 static const char* kwlist[] = {"deterministic", NULL};
1487 int deterministic = 0;
1488 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|p", (char**)(kwlist),
1489 &deterministic)) {
1490 return NULL;
1491 }
1492
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001493 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
1494 if (PyUpb_Message_IsStub(self)) {
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001495 // Nothing to serialize, but we do have to check whether the message is
1496 // initialized.
1497 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001498 PyObject* errors = PyUpb_Message_FindInitializationErrors(_self, NULL);
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001499 if (!errors) return NULL;
1500 if (PyList_Size(errors) == 0) {
1501 Py_DECREF(errors);
1502 return PyBytes_FromStringAndSize(NULL, 0);
1503 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001504 PyUpb_Message_ReportInitializationErrors(msgdef, errors,
1505 state->encode_error_class);
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001506 return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001507 }
1508
Joshua Haberman1c955f32022-01-12 07:19:28 -08001509 upb_Arena* arena = upb_Arena_New();
1510 const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef);
Joshua Haberman4111d132021-12-04 18:42:53 -08001511 size_t size = 0;
Joshua Habermanfff8dfb2022-01-09 23:31:27 -08001512 // Python does not currently have any effective limit on serialization depth.
Joshua Haberman5b3447e2021-12-31 15:37:23 -08001513 int options = UPB_ENCODE_MAXDEPTH(UINT32_MAX);
Protobuf Team Bot65bde4e2022-06-13 17:57:18 -07001514 if (check_required) options |= kUpb_EncodeOption_CheckRequired;
1515 if (deterministic) options |= kUpb_EncodeOption_Deterministic;
1516 char* pb;
1517 upb_EncodeStatus status =
1518 upb_Encode(self->ptr.msg, layout, options, arena, &pb, &size);
Joshua Haberman4111d132021-12-04 18:42:53 -08001519 PyObject* ret = NULL;
1520
Protobuf Team Bot65bde4e2022-06-13 17:57:18 -07001521 if (status != kUpb_EncodeStatus_Ok) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001522 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001523 PyObject* errors = PyUpb_Message_FindInitializationErrors(_self, NULL);
Joshua Haberman4984a222022-01-09 20:46:18 -08001524 if (PyList_Size(errors) != 0) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001525 PyUpb_Message_ReportInitializationErrors(msgdef, errors,
1526 state->encode_error_class);
Joshua Habermanfff8dfb2022-01-09 23:31:27 -08001527 } else {
1528 PyErr_Format(state->encode_error_class, "Failed to serialize proto");
Joshua Haberman4984a222022-01-09 20:46:18 -08001529 }
Joshua Haberman4111d132021-12-04 18:42:53 -08001530 goto done;
1531 }
1532
1533 ret = PyBytes_FromStringAndSize(pb, size);
1534
1535done:
Joshua Haberman1c955f32022-01-12 07:19:28 -08001536 upb_Arena_Free(arena);
Joshua Haberman4111d132021-12-04 18:42:53 -08001537 return ret;
1538}
1539
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001540PyObject* PyUpb_Message_SerializeToString(PyObject* _self, PyObject* args,
1541 PyObject* kwargs) {
1542 return PyUpb_Message_SerializeInternal(_self, args, kwargs, true);
Joshua Haberman4111d132021-12-04 18:42:53 -08001543}
1544
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001545PyObject* PyUpb_Message_SerializePartialToString(PyObject* _self,
1546 PyObject* args,
1547 PyObject* kwargs) {
1548 return PyUpb_Message_SerializeInternal(_self, args, kwargs, false);
Joshua Haberman4111d132021-12-04 18:42:53 -08001549}
1550
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001551static PyObject* PyUpb_Message_WhichOneof(PyObject* _self, PyObject* name) {
1552 PyUpb_Message* self = (void*)_self;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001553 const upb_OneofDef* o;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001554 if (!PyUpb_Message_LookupName(self, name, NULL, &o, PyExc_ValueError)) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001555 return NULL;
1556 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001557 upb_Message* msg = PyUpb_Message_GetIfReified(_self);
Joshua Haberman4111d132021-12-04 18:42:53 -08001558 if (!msg) Py_RETURN_NONE;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001559 const upb_FieldDef* f = upb_Message_WhichOneof(msg, o);
Joshua Haberman4111d132021-12-04 18:42:53 -08001560 if (!f) Py_RETURN_NONE;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001561 return PyUnicode_FromString(upb_FieldDef_Name(f));
Joshua Haberman4111d132021-12-04 18:42:53 -08001562}
1563
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001564void PyUpb_Message_ClearExtensionDict(PyObject* _self) {
1565 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -08001566 assert(self->ext_dict);
1567 self->ext_dict = NULL;
1568}
1569
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001570static PyObject* PyUpb_Message_GetExtensionDict(PyObject* _self,
1571 void* closure) {
1572 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -08001573 if (self->ext_dict) {
Joshua Habermanac27e3b2022-02-27 17:51:27 -08001574 Py_INCREF(self->ext_dict);
Joshua Haberman4111d132021-12-04 18:42:53 -08001575 return self->ext_dict;
1576 }
1577
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001578 const upb_MessageDef* m = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001579 if (upb_MessageDef_ExtensionRangeCount(m) == 0) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001580 PyErr_SetNone(PyExc_AttributeError);
1581 return NULL;
1582 }
1583
Joshua Haberman627c44b2021-12-30 17:47:12 -08001584 self->ext_dict = PyUpb_ExtensionDict_New(_self);
1585 return self->ext_dict;
Joshua Haberman4111d132021-12-04 18:42:53 -08001586}
1587
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001588static PyGetSetDef PyUpb_Message_Getters[] = {
1589 {"Extensions", PyUpb_Message_GetExtensionDict, NULL, "Extension dict"},
Joshua Haberman4111d132021-12-04 18:42:53 -08001590 {NULL}};
1591
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001592static PyMethodDef PyUpb_Message_Methods[] = {
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001593 // TODO(https://github.com/protocolbuffers/upb/issues/459)
Joshua Haberman4111d132021-12-04 18:42:53 -08001594 //{ "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
1595 // "Makes a deep copy of the class." },
1596 //{ "__unicode__", (PyCFunction)ToUnicode, METH_NOARGS,
1597 // "Outputs a unicode representation of the message." },
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001598 {"ByteSize", (PyCFunction)PyUpb_Message_ByteSize, METH_NOARGS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001599 "Returns the size of the message in bytes."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001600 {"Clear", (PyCFunction)PyUpb_Message_Clear, METH_NOARGS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001601 "Clears the message."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001602 {"ClearExtension", PyUpb_Message_ClearExtension, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001603 "Clears a message field."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001604 {"ClearField", PyUpb_Message_ClearField, METH_O, "Clears a message field."},
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001605 // TODO(https://github.com/protocolbuffers/upb/issues/459)
Joshua Haberman4111d132021-12-04 18:42:53 -08001606 //{ "CopyFrom", (PyCFunction)CopyFrom, METH_O,
1607 // "Copies a protocol message into the current message." },
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001608 {"DiscardUnknownFields", (PyCFunction)PyUpb_Message_DiscardUnknownFields,
Joshua Haberman4111d132021-12-04 18:42:53 -08001609 METH_NOARGS, "Discards the unknown fields."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001610 {"FindInitializationErrors", PyUpb_Message_FindInitializationErrors,
Joshua Habermancbe314d2022-01-09 17:25:10 -08001611 METH_NOARGS, "Finds unset required fields."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001612 {"FromString", PyUpb_Message_FromString, METH_O | METH_CLASS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001613 "Creates new method instance from given serialized data."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001614 {"HasExtension", PyUpb_Message_HasExtension, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001615 "Checks if a message field is set."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001616 {"HasField", PyUpb_Message_HasField, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001617 "Checks if a message field is set."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001618 {"IsInitialized", PyUpb_Message_IsInitialized, METH_VARARGS,
Joshua Habermancbe314d2022-01-09 17:25:10 -08001619 "Checks if all required fields of a protocol message are set."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001620 {"ListFields", PyUpb_Message_ListFields, METH_NOARGS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001621 "Lists all set fields of a message."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001622 {"MergeFrom", PyUpb_Message_MergeFrom, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001623 "Merges a protocol message into the current message."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001624 {"MergeFromString", PyUpb_Message_MergeFromString, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001625 "Merges a serialized message into the current message."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001626 {"ParseFromString", PyUpb_Message_ParseFromString, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001627 "Parses a serialized message into the current message."},
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001628 // TODO(https://github.com/protocolbuffers/upb/issues/459)
Joshua Haberman4111d132021-12-04 18:42:53 -08001629 //{ "RegisterExtension", (PyCFunction)RegisterExtension, METH_O |
1630 // METH_CLASS,
1631 // "Registers an extension with the current message." },
1632 {"SerializePartialToString",
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001633 (PyCFunction)PyUpb_Message_SerializePartialToString,
Joshua Haberman4111d132021-12-04 18:42:53 -08001634 METH_VARARGS | METH_KEYWORDS,
1635 "Serializes the message to a string, even if it isn't initialized."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001636 {"SerializeToString", (PyCFunction)PyUpb_Message_SerializeToString,
Joshua Haberman4111d132021-12-04 18:42:53 -08001637 METH_VARARGS | METH_KEYWORDS,
1638 "Serializes the message to a string, only for initialized messages."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001639 {"SetInParent", (PyCFunction)PyUpb_Message_SetInParent, METH_NOARGS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001640 "Sets the has bit of the given field in its parent message."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001641 {"UnknownFields", (PyCFunction)PyUpb_Message_UnknownFields, METH_NOARGS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001642 "Parse unknown field set"},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001643 {"WhichOneof", PyUpb_Message_WhichOneof, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001644 "Returns the name of the field set inside a oneof, "
1645 "or None if no field is set."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001646 {"_ListFieldsItemKey", PyUpb_Message_ListFieldsItemKey,
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001647 METH_O | METH_STATIC,
1648 "Compares ListFields() list entries by field number"},
Joshua Haberman4e2bbc82022-05-17 10:08:55 -07001649 {"_CheckCalledFromGeneratedFile",
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001650 PyUpb_Message_CheckCalledFromGeneratedFile, METH_NOARGS | METH_STATIC,
Joshua Haberman4e2bbc82022-05-17 10:08:55 -07001651 "Raises TypeError if the caller is not in a _pb2.py file."},
Joshua Haberman4111d132021-12-04 18:42:53 -08001652 {NULL, NULL}};
1653
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001654static PyType_Slot PyUpb_Message_Slots[] = {
1655 {Py_tp_dealloc, PyUpb_Message_Dealloc},
Joshua Haberman4111d132021-12-04 18:42:53 -08001656 {Py_tp_doc, "A ProtocolMessage"},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001657 {Py_tp_getattro, PyUpb_Message_GetAttr},
1658 {Py_tp_getset, PyUpb_Message_Getters},
Joshua Haberman4111d132021-12-04 18:42:53 -08001659 {Py_tp_hash, PyObject_HashNotImplemented},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001660 {Py_tp_methods, PyUpb_Message_Methods},
1661 {Py_tp_new, PyUpb_Message_New},
1662 {Py_tp_str, PyUpb_Message_ToString},
1663 {Py_tp_repr, PyUpb_Message_ToString},
1664 {Py_tp_richcompare, PyUpb_Message_RichCompare},
1665 {Py_tp_setattro, PyUpb_Message_SetAttr},
1666 {Py_tp_init, PyUpb_Message_Init},
Joshua Haberman4111d132021-12-04 18:42:53 -08001667 {0, NULL}};
1668
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001669PyType_Spec PyUpb_Message_Spec = {
1670 PYUPB_MODULE_NAME ".Message", // tp_name
1671 sizeof(PyUpb_Message), // tp_basicsize
Joshua Haberman4111d132021-12-04 18:42:53 -08001672 0, // tp_itemsize
1673 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001674 PyUpb_Message_Slots,
Joshua Haberman4111d132021-12-04 18:42:53 -08001675};
1676
1677// -----------------------------------------------------------------------------
1678// MessageMeta
1679// -----------------------------------------------------------------------------
1680
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001681// MessageMeta is the metaclass for message objects. The generated code uses it
1682// to construct message classes, ie.
1683//
1684// FooMessage = _message.MessageMeta('FooMessage', (_message.Message), {...})
1685//
1686// (This is not quite true: at the moment the Python library subclasses
1687// MessageMeta, and uses that subclass as the metaclass. There is a TODO below
1688// to simplify this, so that the illustration above is indeed accurate).
1689
Joshua Haberman4111d132021-12-04 18:42:53 -08001690typedef struct {
Joshua Haberman1c955f32022-01-12 07:19:28 -08001691 const upb_MiniTable* layout;
Joshua Haberman4111d132021-12-04 18:42:53 -08001692 PyObject* py_message_descriptor;
1693} PyUpb_MessageMeta;
1694
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001695// The PyUpb_MessageMeta struct is trailing data tacked onto the end of
1696// MessageMeta instances. This means that we get our instances of this struct
1697// by adding the appropriate number of bytes.
1698static PyUpb_MessageMeta* PyUpb_GetMessageMeta(PyObject* cls) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001699#ifndef NDEBUG
1700 PyUpb_ModuleState* state = PyUpb_ModuleState_MaybeGet();
1701 assert(!state || cls->ob_type == state->message_meta_type);
1702#endif
1703 return (PyUpb_MessageMeta*)((char*)cls + cpython_bits.type_basicsize);
1704}
1705
Joshua Haberman1c955f32022-01-12 07:19:28 -08001706static const upb_MessageDef* PyUpb_MessageMeta_GetMsgdef(PyObject* cls) {
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001707 PyUpb_MessageMeta* self = PyUpb_GetMessageMeta(cls);
1708 return PyUpb_Descriptor_GetDef(self->py_message_descriptor);
1709}
1710
Joshua Haberman4111d132021-12-04 18:42:53 -08001711PyObject* PyUpb_MessageMeta_DoCreateClass(PyObject* py_descriptor,
1712 const char* name, PyObject* dict) {
1713 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1714 PyTypeObject* descriptor_type = state->descriptor_types[kPyUpb_Descriptor];
1715 if (!PyObject_TypeCheck(py_descriptor, descriptor_type)) {
1716 return PyErr_Format(PyExc_TypeError, "Expected a message Descriptor");
1717 }
1718
Joshua Haberman1c955f32022-01-12 07:19:28 -08001719 const upb_MessageDef* msgdef = PyUpb_Descriptor_GetDef(py_descriptor);
Joshua Haberman4111d132021-12-04 18:42:53 -08001720 assert(msgdef);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001721 assert(!PyUpb_ObjCache_Get(upb_MessageDef_MiniTable(msgdef)));
Joshua Haberman4111d132021-12-04 18:42:53 -08001722
1723 PyObject* slots = PyTuple_New(0);
Joshua Habermanffdcc462022-01-12 08:38:36 -08001724 if (!slots) return NULL;
1725 int status = PyDict_SetItemString(dict, "__slots__", slots);
1726 Py_DECREF(slots);
1727 if (status < 0) return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001728
1729 // Bases are either:
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001730 // (Message, Message) # for regular messages
1731 // (Message, Message, WktBase) # For well-known types
Joshua Haberman4111d132021-12-04 18:42:53 -08001732 PyObject* wkt_bases = PyUpb_GetWktBases(state);
1733 PyObject* wkt_base =
Joshua Haberman1c955f32022-01-12 07:19:28 -08001734 PyDict_GetItemString(wkt_bases, upb_MessageDef_FullName(msgdef));
Joshua Haberman4111d132021-12-04 18:42:53 -08001735 PyObject* args;
1736 if (wkt_base == NULL) {
1737 args = Py_BuildValue("s(OO)O", name, state->cmessage_type,
1738 state->message_class, dict);
1739 } else {
1740 args = Py_BuildValue("s(OOO)O", name, state->cmessage_type,
1741 state->message_class, wkt_base, dict);
1742 }
1743
1744 PyObject* ret = cpython_bits.type_new(state->message_meta_type, args, NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -08001745 Py_DECREF(args);
1746 if (!ret) return NULL;
1747
1748 PyUpb_MessageMeta* meta = PyUpb_GetMessageMeta(ret);
1749 meta->py_message_descriptor = py_descriptor;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001750 meta->layout = upb_MessageDef_MiniTable(msgdef);
Joshua Haberman4111d132021-12-04 18:42:53 -08001751 Py_INCREF(meta->py_message_descriptor);
1752
Joshua Habermanffdcc462022-01-12 08:38:36 -08001753 PyUpb_ObjCache_Add(meta->layout, ret);
Joshua Haberman4111d132021-12-04 18:42:53 -08001754
1755 return ret;
1756}
1757
1758static PyObject* PyUpb_MessageMeta_New(PyTypeObject* type, PyObject* args,
1759 PyObject* kwargs) {
1760 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1761 static const char* kwlist[] = {"name", "bases", "dict", 0};
1762 PyObject *bases, *dict;
1763 const char* name;
1764
1765 // Check arguments: (name, bases, dict)
1766 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!O!:type", (char**)kwlist,
1767 &name, &PyTuple_Type, &bases, &PyDict_Type,
1768 &dict)) {
1769 return NULL;
1770 }
1771
1772 // Check bases: only (), or (message.Message,) are allowed
1773 Py_ssize_t size = PyTuple_Size(bases);
1774 if (!(size == 0 ||
1775 (size == 1 && PyTuple_GetItem(bases, 0) == state->message_class))) {
Joshua Haberman4423e912021-12-27 18:04:58 -08001776 PyErr_Format(PyExc_TypeError,
1777 "A Message class can only inherit from Message, not %S",
1778 bases);
Joshua Haberman4111d132021-12-04 18:42:53 -08001779 return NULL;
1780 }
1781
1782 // Check dict['DESCRIPTOR']
1783 PyObject* py_descriptor = PyDict_GetItemString(dict, "DESCRIPTOR");
1784 if (py_descriptor == NULL) {
1785 PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR");
1786 return NULL;
1787 }
1788
Joshua Haberman1c955f32022-01-12 07:19:28 -08001789 const upb_MessageDef* m = PyUpb_Descriptor_GetDef(py_descriptor);
1790 PyObject* ret = PyUpb_ObjCache_Get(upb_MessageDef_MiniTable(m));
Joshua Haberman4111d132021-12-04 18:42:53 -08001791 if (ret) return ret;
1792 return PyUpb_MessageMeta_DoCreateClass(py_descriptor, name, dict);
1793}
1794
1795static void PyUpb_MessageMeta_Dealloc(PyObject* self) {
1796 PyUpb_MessageMeta* meta = PyUpb_GetMessageMeta(self);
1797 PyUpb_ObjCache_Delete(meta->layout);
1798 Py_DECREF(meta->py_message_descriptor);
Joshua Habermanffdcc462022-01-12 08:38:36 -08001799 PyTypeObject* tp = Py_TYPE(self);
1800 cpython_bits.type_dealloc(self);
1801 Py_DECREF(tp);
Joshua Haberman4111d132021-12-04 18:42:53 -08001802}
1803
Joshua Haberman1c955f32022-01-12 07:19:28 -08001804void PyUpb_MessageMeta_AddFieldNumber(PyObject* self, const upb_FieldDef* f) {
Joshua Haberman8af637b2022-01-09 21:59:29 -08001805 PyObject* name =
Joshua Haberman1c955f32022-01-12 07:19:28 -08001806 PyUnicode_FromFormat("%s_FIELD_NUMBER", upb_FieldDef_Name(f));
Joshua Haberman8af637b2022-01-09 21:59:29 -08001807 PyObject* upper = PyObject_CallMethod(name, "upper", "");
Joshua Haberman1c955f32022-01-12 07:19:28 -08001808 PyObject_SetAttr(self, upper, PyLong_FromLong(upb_FieldDef_Number(f)));
Joshua Haberman8af637b2022-01-09 21:59:29 -08001809 Py_DECREF(name);
1810 Py_DECREF(upper);
1811}
1812
Joshua Haberman4111d132021-12-04 18:42:53 -08001813static PyObject* PyUpb_MessageMeta_GetDynamicAttr(PyObject* self,
1814 PyObject* name) {
1815 const char* name_buf = PyUpb_GetStrData(name);
Joshua Habermanb38e4a42022-01-16 19:27:55 -08001816 if (!name_buf) return NULL;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001817 const upb_MessageDef* msgdef = PyUpb_MessageMeta_GetMsgdef(self);
1818 const upb_FileDef* filedef = upb_MessageDef_File(msgdef);
1819 const upb_DefPool* symtab = upb_FileDef_Pool(filedef);
Joshua Haberman4111d132021-12-04 18:42:53 -08001820
1821 PyObject* py_key =
Joshua Haberman1c955f32022-01-12 07:19:28 -08001822 PyBytes_FromFormat("%s.%s", upb_MessageDef_FullName(msgdef), name_buf);
Joshua Haberman4111d132021-12-04 18:42:53 -08001823 const char* key = PyUpb_GetStrData(py_key);
1824 PyObject* ret = NULL;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001825 const upb_MessageDef* nested = upb_DefPool_FindMessageByName(symtab, key);
1826 const upb_EnumDef* enumdef;
1827 const upb_EnumValueDef* enumval;
1828 const upb_FieldDef* ext;
Joshua Haberman4111d132021-12-04 18:42:53 -08001829
1830 if (nested) {
1831 ret = PyUpb_Descriptor_GetClass(nested);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001832 } else if ((enumdef = upb_DefPool_FindEnumByName(symtab, key))) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001833 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1834 PyObject* klass = state->enum_type_wrapper_class;
1835 ret = PyUpb_EnumDescriptor_Get(enumdef);
1836 ret = PyObject_CallFunctionObjArgs(klass, ret, NULL);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001837 } else if ((enumval = upb_DefPool_FindEnumByNameval(symtab, key))) {
1838 ret = PyLong_FromLong(upb_EnumValueDef_Number(enumval));
1839 } else if ((ext = upb_DefPool_FindExtensionByName(symtab, key))) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001840 ret = PyUpb_FieldDescriptor_Get(ext);
1841 }
1842
1843 Py_DECREF(py_key);
1844
Joshua Haberman1c955f32022-01-12 07:19:28 -08001845 const char* suffix = "_FIELD_NUMBER";
Joshua Haberman3b25e6f2022-01-09 19:28:04 -08001846 size_t n = strlen(name_buf);
1847 size_t suffix_n = strlen(suffix);
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001848 if (n > suffix_n && memcmp(suffix, name_buf + n - suffix_n, suffix_n) == 0) {
Joshua Haberman3b25e6f2022-01-09 19:28:04 -08001849 // We can't look up field names dynamically, because the <NAME>_FIELD_NUMBER
1850 // naming scheme upper-cases the field name and is therefore non-reversible.
1851 // So we just add all field numbers.
Joshua Haberman1c955f32022-01-12 07:19:28 -08001852 int n = upb_MessageDef_FieldCount(msgdef);
Joshua Haberman3b25e6f2022-01-09 19:28:04 -08001853 for (int i = 0; i < n; i++) {
Joshua Haberman1c955f32022-01-12 07:19:28 -08001854 PyUpb_MessageMeta_AddFieldNumber(self, upb_MessageDef_Field(msgdef, i));
Joshua Haberman8af637b2022-01-09 21:59:29 -08001855 }
Joshua Haberman1c955f32022-01-12 07:19:28 -08001856 n = upb_MessageDef_NestedExtensionCount(msgdef);
Joshua Haberman8af637b2022-01-09 21:59:29 -08001857 for (int i = 0; i < n; i++) {
Joshua Haberman1c955f32022-01-12 07:19:28 -08001858 PyUpb_MessageMeta_AddFieldNumber(
1859 self, upb_MessageDef_NestedExtension(msgdef, i));
Joshua Haberman3b25e6f2022-01-09 19:28:04 -08001860 }
1861 ret = PyObject_GenericGetAttr(self, name);
1862 }
1863
Joshua Haberman4111d132021-12-04 18:42:53 -08001864 return ret;
1865}
1866
1867static PyObject* PyUpb_MessageMeta_GetAttr(PyObject* self, PyObject* name) {
1868 // We want to first delegate to the type's tp_dict to retrieve any attributes
1869 // that were previously calculated and cached in the type's dict.
1870 PyObject* ret = cpython_bits.type_getattro(self, name);
1871 if (ret) return ret;
1872
1873 // We did not find a cached attribute. Try to calculate the attribute
1874 // dynamically, using the descriptor as an argument.
1875 PyErr_Clear();
1876 ret = PyUpb_MessageMeta_GetDynamicAttr(self, name);
1877
1878 if (ret) {
1879 PyObject_SetAttr(self, name, ret);
1880 PyErr_Clear();
1881 return ret;
1882 }
1883
1884 PyErr_SetObject(PyExc_AttributeError, name);
1885 return NULL;
1886}
1887
1888static PyType_Slot PyUpb_MessageMeta_Slots[] = {
1889 {Py_tp_new, PyUpb_MessageMeta_New},
1890 {Py_tp_dealloc, PyUpb_MessageMeta_Dealloc},
1891 {Py_tp_getattro, PyUpb_MessageMeta_GetAttr},
1892 {0, NULL}};
1893
1894static PyType_Spec PyUpb_MessageMeta_Spec = {
1895 PYUPB_MODULE_NAME ".MessageMeta", // tp_name
1896 0, // To be filled in by size of base // tp_basicsize
1897 0, // tp_itemsize
1898 // TODO(haberman): remove BASETYPE, Python should just use MessageMeta
1899 // directly instead of subclassing it.
1900 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
1901 PyUpb_MessageMeta_Slots,
1902};
1903
Joshua Habermane079f1b2021-12-18 22:10:46 -08001904static PyObject* PyUpb_MessageMeta_CreateType(void) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001905 PyObject* bases = Py_BuildValue("(O)", &PyType_Type);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001906 if (!bases) return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001907 PyUpb_MessageMeta_Spec.basicsize =
1908 cpython_bits.type_basicsize + sizeof(PyUpb_MessageMeta);
1909 PyObject* type = PyType_FromSpecWithBases(&PyUpb_MessageMeta_Spec, bases);
1910 Py_DECREF(bases);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001911 return type;
1912}
Joshua Haberman4111d132021-12-04 18:42:53 -08001913
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001914bool PyUpb_InitMessage(PyObject* m) {
1915 if (!PyUpb_CPythonBits_Init(&cpython_bits)) return false;
1916 PyObject* message_meta_type = PyUpb_MessageMeta_CreateType();
Joshua Haberman4111d132021-12-04 18:42:53 -08001917
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001918 PyUpb_ModuleState* state = PyUpb_ModuleState_GetFromModule(m);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001919 state->cmessage_type = PyUpb_AddClass(m, &PyUpb_Message_Spec);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001920 state->message_meta_type = (PyTypeObject*)message_meta_type;
1921
1922 if (!state->cmessage_type || !state->message_meta_type) return false;
1923 if (PyModule_AddObject(m, "MessageMeta", message_meta_type)) return false;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001924 state->listfields_item_key = PyObject_GetAttrString(
1925 (PyObject*)state->cmessage_type, "_ListFieldsItemKey");
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001926
Joshua Haberman6a94a382022-02-27 17:35:52 -08001927 PyObject* mod =
1928 PyImport_ImportModule(PYUPB_PROTOBUF_PUBLIC_PACKAGE ".message");
Joshua Haberman4423e912021-12-27 18:04:58 -08001929 if (mod == NULL) return false;
1930
1931 state->encode_error_class = PyObject_GetAttrString(mod, "EncodeError");
1932 state->decode_error_class = PyObject_GetAttrString(mod, "DecodeError");
1933 state->message_class = PyObject_GetAttrString(mod, "Message");
1934 Py_DECREF(mod);
1935
Joshua Haberman0a858bb2022-02-27 13:01:15 -08001936 PyObject* enum_type_wrapper = PyImport_ImportModule(
1937 PYUPB_PROTOBUF_INTERNAL_PACKAGE ".enum_type_wrapper");
Joshua Haberman4447d872022-01-09 13:13:59 -08001938 if (enum_type_wrapper == NULL) return false;
1939
1940 state->enum_type_wrapper_class =
1941 PyObject_GetAttrString(enum_type_wrapper, "EnumTypeWrapper");
1942 Py_DECREF(enum_type_wrapper);
1943
Joshua Haberman4423e912021-12-27 18:04:58 -08001944 if (!state->encode_error_class || !state->decode_error_class ||
Joshua Habermand4c0c632022-01-09 23:16:18 -08001945 !state->message_class || !state->listfields_item_key ||
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001946 !state->enum_type_wrapper_class) {
Joshua Haberman4423e912021-12-27 18:04:58 -08001947 return false;
1948 }
1949
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001950 return true;
Joshua Haberman4111d132021-12-04 18:42:53 -08001951}