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