1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #ifndef PYUPB_PROTOBUF_H__
9 #define PYUPB_PROTOBUF_H__
10
11 #include <stdbool.h>
12
13 #include "python/descriptor.h"
14 #include "python/python_api.h"
15 #include "upb/hash/int_table.h"
16
17 #define PYUPB_PROTOBUF_PUBLIC_PACKAGE "google.protobuf"
18 #define PYUPB_PROTOBUF_INTERNAL_PACKAGE "google.protobuf.internal"
19 #define PYUPB_DESCRIPTOR_PROTO_PACKAGE "google.protobuf"
20 #define PYUPB_MODULE_NAME "google._upb._message"
21
22 #define PYUPB_DESCRIPTOR_MODULE "google.protobuf.descriptor_pb2"
23 #define PYUPB_RETURN_OOM return PyErr_SetNone(PyExc_MemoryError), NULL
24
25 struct PyUpb_WeakMap;
26 typedef struct PyUpb_WeakMap PyUpb_WeakMap;
27
28 // -----------------------------------------------------------------------------
29 // ModuleState
30 // -----------------------------------------------------------------------------
31
32 // We store all "global" state in this struct instead of using (C) global
33 // variables. This makes this extension compatible with sub-interpreters.
34
35 typedef struct {
36 // From descriptor.c
37 PyTypeObject* descriptor_types[kPyUpb_Descriptor_Count];
38
39 // From descriptor_containers.c
40 PyTypeObject* by_name_map_type;
41 PyTypeObject* by_name_iterator_type;
42 PyTypeObject* by_number_map_type;
43 PyTypeObject* by_number_iterator_type;
44 PyTypeObject* generic_sequence_type;
45
46 // From descriptor_pool.c
47 PyObject* default_pool;
48
49 // From descriptor_pool.c
50 PyTypeObject* descriptor_pool_type;
51 upb_DefPool* c_descriptor_symtab;
52
53 // From extension_dict.c
54 PyTypeObject* extension_dict_type;
55 PyTypeObject* extension_iterator_type;
56
57 // From map.c
58 PyTypeObject* map_iterator_type;
59 PyTypeObject* message_map_container_type;
60 PyTypeObject* scalar_map_container_type;
61
62 // From message.c
63 PyObject* decode_error_class;
64 PyObject* descriptor_string;
65 PyObject* encode_error_class;
66 PyObject* enum_type_wrapper_class;
67 PyObject* message_class;
68 PyTypeObject* cmessage_type;
69 PyTypeObject* message_meta_type;
70 PyObject* listfields_item_key;
71
72 // From protobuf.c
73 bool allow_oversize_protos;
74 PyObject* wkt_bases;
75 PyTypeObject* arena_type;
76 PyUpb_WeakMap* obj_cache;
77
78 // From repeated.c
79 PyTypeObject* repeated_composite_container_type;
80 PyTypeObject* repeated_scalar_container_type;
81
82 // From unknown_fields.c
83 PyTypeObject* unknown_fields_type;
84 PyObject* unknown_field_type;
85 } PyUpb_ModuleState;
86
87 // Returns the global state object from the current interpreter. The current
88 // interpreter is looked up from thread-local state.
89 PyUpb_ModuleState* PyUpb_ModuleState_Get(void);
90 PyUpb_ModuleState* PyUpb_ModuleState_GetFromModule(PyObject* module);
91
92 // Returns NULL if module state is not yet available (during startup).
93 // Any use of the module state during startup needs to be passed explicitly.
94 PyUpb_ModuleState* PyUpb_ModuleState_MaybeGet(void);
95
96 // Returns:
97 // from google.protobuf.internal.well_known_types import WKTBASES
98 //
99 // This has to be imported lazily rather than at module load time, because
100 // otherwise it would cause a circular import.
101 PyObject* PyUpb_GetWktBases(PyUpb_ModuleState* state);
102
103 // -----------------------------------------------------------------------------
104 // WeakMap
105 // -----------------------------------------------------------------------------
106
107 // A WeakMap maps C pointers to the corresponding Python wrapper object. We
108 // want a consistent Python wrapper object for each C object, both to save
109 // memory and to provide object stability (ie. x is x).
110 //
111 // Each wrapped object should add itself to the map when it is constructed and
112 // remove itself from the map when it is destroyed. The map is weak so it does
113 // not take references to the cached objects.
114
115 PyUpb_WeakMap* PyUpb_WeakMap_New(void);
116 void PyUpb_WeakMap_Free(PyUpb_WeakMap* map);
117
118 // Adds the given object to the map, indexed by the given key.
119 void PyUpb_WeakMap_Add(PyUpb_WeakMap* map, const void* key, PyObject* py_obj);
120
121 // Removes the given key from the cache. It must exist in the cache currently.
122 void PyUpb_WeakMap_Delete(PyUpb_WeakMap* map, const void* key);
123 void PyUpb_WeakMap_TryDelete(PyUpb_WeakMap* map, const void* key);
124
125 // Returns a new reference to an object if it exists, otherwise returns NULL.
126 PyObject* PyUpb_WeakMap_Get(PyUpb_WeakMap* map, const void* key);
127
128 #define PYUPB_WEAKMAP_BEGIN UPB_INTTABLE_BEGIN
129
130 // Iteration over the weak map, eg.
131 //
132 // intptr_t it = PYUPB_WEAKMAP_BEGIN;
133 // while (PyUpb_WeakMap_Next(map, &key, &obj, &it)) {
134 // // ...
135 // }
136 //
137 // Note that the callee does not own a ref on the returned `obj`.
138 bool PyUpb_WeakMap_Next(PyUpb_WeakMap* map, const void** key, PyObject** obj,
139 intptr_t* iter);
140 void PyUpb_WeakMap_DeleteIter(PyUpb_WeakMap* map, intptr_t* iter);
141
142 // -----------------------------------------------------------------------------
143 // ObjCache
144 // -----------------------------------------------------------------------------
145
146 // The object cache is a global WeakMap for mapping upb objects to the
147 // corresponding wrapper.
148 void PyUpb_ObjCache_Add(const void* key, PyObject* py_obj);
149 void PyUpb_ObjCache_Delete(const void* key);
150 PyObject* PyUpb_ObjCache_Get(const void* key); // returns NULL if not present.
151 PyUpb_WeakMap* PyUpb_ObjCache_Instance(void);
152
153 // -----------------------------------------------------------------------------
154 // Arena
155 // -----------------------------------------------------------------------------
156
157 PyObject* PyUpb_Arena_New(void);
158 upb_Arena* PyUpb_Arena_Get(PyObject* arena);
159
160 // -----------------------------------------------------------------------------
161 // Utilities
162 // -----------------------------------------------------------------------------
163
164 PyTypeObject* AddObject(PyObject* m, const char* name, PyType_Spec* spec);
165
166 // Creates a Python type from `spec` and adds it to the given module `m`.
167 PyTypeObject* PyUpb_AddClass(PyObject* m, PyType_Spec* spec);
168
169 // Like PyUpb_AddClass(), but allows you to specify a tuple of base classes
170 // in `bases`.
171 PyTypeObject* PyUpb_AddClassWithBases(PyObject* m, PyType_Spec* spec,
172 PyObject* bases);
173
174 // Like PyUpb_AddClass(), but allows you to specify a tuple of base classes in
175 // `bases` to register as a "virtual subclass" with mixin methods.
176 PyTypeObject* PyUpb_AddClassWithRegister(PyObject* m, PyType_Spec* spec,
177 PyObject* virtual_base,
178 const char** methods);
179
180 // A function that implements the tp_new slot for types that we do not allow
181 // users to create directly. This will immediately fail with an error message.
182 PyObject* PyUpb_Forbidden_New(PyObject* cls, PyObject* args, PyObject* kwds);
183
184 // Our standard dealloc func. It follows the guidance defined in:
185 // https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_dealloc
186 // However it tests Py_TPFLAGS_HEAPTYPE dynamically so that a single dealloc
187 // function can work for any type.
PyUpb_Dealloc(void * self)188 static inline void PyUpb_Dealloc(void* self) {
189 PyTypeObject* tp = Py_TYPE(self);
190 assert(PyType_GetFlags(tp) & Py_TPFLAGS_HEAPTYPE);
191 freefunc tp_free = (freefunc)PyType_GetSlot(tp, Py_tp_free);
192 tp_free(self);
193 Py_DECREF(tp);
194 }
195
196 // Equivalent to the Py_NewRef() function introduced in Python 3.10. If/when we
197 // drop support for Python <3.10, we can remove this function and replace all
198 // callers with Py_NewRef().
PyUpb_NewRef(PyObject * obj)199 static inline PyObject* PyUpb_NewRef(PyObject* obj) {
200 Py_INCREF(obj);
201 return obj;
202 }
203
204 const char* PyUpb_GetStrData(PyObject* obj);
205 const char* PyUpb_VerifyStrData(PyObject* obj);
206
207 // For an expression like:
208 // foo[index]
209 //
210 // Converts `index` to an effective i/count/step, for a repeated field
211 // or descriptor sequence of size 'size'.
212 bool PyUpb_IndexToRange(PyObject* index, Py_ssize_t size, Py_ssize_t* i,
213 Py_ssize_t* count, Py_ssize_t* step);
214 #endif // PYUPB_PROTOBUF_H__
215