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