blob: 25e40415c93f9ff829a033c0bed88d42734f296a [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
Adam Cozzette501ecec2023-09-26 14:36:20 -070017#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"
Adam Cozzette501ecec2023-09-26 14:36:20 -070021
22#define PYUPB_DESCRIPTOR_MODULE "google.protobuf.descriptor_pb2"
23#define PYUPB_RETURN_OOM return PyErr_SetNone(PyExc_MemoryError), NULL
24
25struct PyUpb_WeakMap;
26typedef 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
35typedef 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.
89PyUpb_ModuleState* PyUpb_ModuleState_Get(void);
90PyUpb_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.
94PyUpb_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.
101PyObject* 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
115PyUpb_WeakMap* PyUpb_WeakMap_New(void);
116void PyUpb_WeakMap_Free(PyUpb_WeakMap* map);
117
118// Adds the given object to the map, indexed by the given key.
119void 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.
122void PyUpb_WeakMap_Delete(PyUpb_WeakMap* map, const void* key);
123void PyUpb_WeakMap_TryDelete(PyUpb_WeakMap* map, const void* key);
124
125// Returns a new reference to an object if it exists, otherwise returns NULL.
126PyObject* 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`.
138bool PyUpb_WeakMap_Next(PyUpb_WeakMap* map, const void** key, PyObject** obj,
139 intptr_t* iter);
140void 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.
148void PyUpb_ObjCache_Add(const void* key, PyObject* py_obj);
149void PyUpb_ObjCache_Delete(const void* key);
150PyObject* PyUpb_ObjCache_Get(const void* key); // returns NULL if not present.
151PyUpb_WeakMap* PyUpb_ObjCache_Instance(void);
152
153// -----------------------------------------------------------------------------
154// Arena
155// -----------------------------------------------------------------------------
156
157PyObject* PyUpb_Arena_New(void);
158upb_Arena* PyUpb_Arena_Get(PyObject* arena);
159
160// -----------------------------------------------------------------------------
161// Utilities
162// -----------------------------------------------------------------------------
163
164PyTypeObject* 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`.
167PyTypeObject* 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`.
171PyTypeObject* PyUpb_AddClassWithBases(PyObject* m, PyType_Spec* spec,
172 PyObject* bases);
173
Sandy Zhang5b329362024-03-05 17:54:43 -0800174// 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.
176PyTypeObject* PyUpb_AddClassWithRegister(PyObject* m, PyType_Spec* spec,
177 PyObject* virtual_base,
178 const char** methods);
179
Adam Cozzette501ecec2023-09-26 14:36:20 -0700180// 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.
182PyObject* 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.
188static 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().
199static inline PyObject* PyUpb_NewRef(PyObject* obj) {
200 Py_INCREF(obj);
201 return obj;
202}
203
204const char* PyUpb_GetStrData(PyObject* obj);
205const 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'.
212bool 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__