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