Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Objects/capsule.c
12 views
1
/* Wrap void * pointers to be passed between C modules */
2
3
#include "Python.h"
4
5
/* Internal structure of PyCapsule */
6
typedef struct {
7
PyObject_HEAD
8
void *pointer;
9
const char *name;
10
void *context;
11
PyCapsule_Destructor destructor;
12
} PyCapsule;
13
14
15
16
static int
17
_is_legal_capsule(PyCapsule *capsule, const char *invalid_capsule)
18
{
19
if (!capsule || !PyCapsule_CheckExact(capsule) || capsule->pointer == NULL) {
20
PyErr_SetString(PyExc_ValueError, invalid_capsule);
21
return 0;
22
}
23
return 1;
24
}
25
26
#define is_legal_capsule(capsule, name) \
27
(_is_legal_capsule(capsule, \
28
name " called with invalid PyCapsule object"))
29
30
31
static int
32
name_matches(const char *name1, const char *name2) {
33
/* if either is NULL, */
34
if (!name1 || !name2) {
35
/* they're only the same if they're both NULL. */
36
return name1 == name2;
37
}
38
return !strcmp(name1, name2);
39
}
40
41
42
43
PyObject *
44
PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
45
{
46
PyCapsule *capsule;
47
48
if (!pointer) {
49
PyErr_SetString(PyExc_ValueError, "PyCapsule_New called with null pointer");
50
return NULL;
51
}
52
53
capsule = PyObject_New(PyCapsule, &PyCapsule_Type);
54
if (capsule == NULL) {
55
return NULL;
56
}
57
58
capsule->pointer = pointer;
59
capsule->name = name;
60
capsule->context = NULL;
61
capsule->destructor = destructor;
62
63
return (PyObject *)capsule;
64
}
65
66
67
int
68
PyCapsule_IsValid(PyObject *o, const char *name)
69
{
70
PyCapsule *capsule = (PyCapsule *)o;
71
72
return (capsule != NULL &&
73
PyCapsule_CheckExact(capsule) &&
74
capsule->pointer != NULL &&
75
name_matches(capsule->name, name));
76
}
77
78
79
void *
80
PyCapsule_GetPointer(PyObject *o, const char *name)
81
{
82
PyCapsule *capsule = (PyCapsule *)o;
83
84
if (!is_legal_capsule(capsule, "PyCapsule_GetPointer")) {
85
return NULL;
86
}
87
88
if (!name_matches(name, capsule->name)) {
89
PyErr_SetString(PyExc_ValueError, "PyCapsule_GetPointer called with incorrect name");
90
return NULL;
91
}
92
93
return capsule->pointer;
94
}
95
96
97
const char *
98
PyCapsule_GetName(PyObject *o)
99
{
100
PyCapsule *capsule = (PyCapsule *)o;
101
102
if (!is_legal_capsule(capsule, "PyCapsule_GetName")) {
103
return NULL;
104
}
105
return capsule->name;
106
}
107
108
109
PyCapsule_Destructor
110
PyCapsule_GetDestructor(PyObject *o)
111
{
112
PyCapsule *capsule = (PyCapsule *)o;
113
114
if (!is_legal_capsule(capsule, "PyCapsule_GetDestructor")) {
115
return NULL;
116
}
117
return capsule->destructor;
118
}
119
120
121
void *
122
PyCapsule_GetContext(PyObject *o)
123
{
124
PyCapsule *capsule = (PyCapsule *)o;
125
126
if (!is_legal_capsule(capsule, "PyCapsule_GetContext")) {
127
return NULL;
128
}
129
return capsule->context;
130
}
131
132
133
int
134
PyCapsule_SetPointer(PyObject *o, void *pointer)
135
{
136
PyCapsule *capsule = (PyCapsule *)o;
137
138
if (!pointer) {
139
PyErr_SetString(PyExc_ValueError, "PyCapsule_SetPointer called with null pointer");
140
return -1;
141
}
142
143
if (!is_legal_capsule(capsule, "PyCapsule_SetPointer")) {
144
return -1;
145
}
146
147
capsule->pointer = pointer;
148
return 0;
149
}
150
151
152
int
153
PyCapsule_SetName(PyObject *o, const char *name)
154
{
155
PyCapsule *capsule = (PyCapsule *)o;
156
157
if (!is_legal_capsule(capsule, "PyCapsule_SetName")) {
158
return -1;
159
}
160
161
capsule->name = name;
162
return 0;
163
}
164
165
166
int
167
PyCapsule_SetDestructor(PyObject *o, PyCapsule_Destructor destructor)
168
{
169
PyCapsule *capsule = (PyCapsule *)o;
170
171
if (!is_legal_capsule(capsule, "PyCapsule_SetDestructor")) {
172
return -1;
173
}
174
175
capsule->destructor = destructor;
176
return 0;
177
}
178
179
180
int
181
PyCapsule_SetContext(PyObject *o, void *context)
182
{
183
PyCapsule *capsule = (PyCapsule *)o;
184
185
if (!is_legal_capsule(capsule, "PyCapsule_SetContext")) {
186
return -1;
187
}
188
189
capsule->context = context;
190
return 0;
191
}
192
193
194
void *
195
PyCapsule_Import(const char *name, int no_block)
196
{
197
PyObject *object = NULL;
198
void *return_value = NULL;
199
char *trace;
200
size_t name_length = (strlen(name) + 1) * sizeof(char);
201
char *name_dup = (char *)PyMem_Malloc(name_length);
202
203
if (!name_dup) {
204
return PyErr_NoMemory();
205
}
206
207
memcpy(name_dup, name, name_length);
208
209
trace = name_dup;
210
while (trace) {
211
char *dot = strchr(trace, '.');
212
if (dot) {
213
*dot++ = '\0';
214
}
215
216
if (object == NULL) {
217
object = PyImport_ImportModule(trace);
218
if (!object) {
219
PyErr_Format(PyExc_ImportError, "PyCapsule_Import could not import module \"%s\"", trace);
220
}
221
} else {
222
PyObject *object2 = PyObject_GetAttrString(object, trace);
223
Py_SETREF(object, object2);
224
}
225
if (!object) {
226
goto EXIT;
227
}
228
229
trace = dot;
230
}
231
232
/* compare attribute name to module.name by hand */
233
if (PyCapsule_IsValid(object, name)) {
234
PyCapsule *capsule = (PyCapsule *)object;
235
return_value = capsule->pointer;
236
} else {
237
PyErr_Format(PyExc_AttributeError,
238
"PyCapsule_Import \"%s\" is not valid",
239
name);
240
}
241
242
EXIT:
243
Py_XDECREF(object);
244
if (name_dup) {
245
PyMem_Free(name_dup);
246
}
247
return return_value;
248
}
249
250
251
static void
252
capsule_dealloc(PyObject *o)
253
{
254
PyCapsule *capsule = (PyCapsule *)o;
255
if (capsule->destructor) {
256
capsule->destructor(o);
257
}
258
PyObject_Free(o);
259
}
260
261
262
static PyObject *
263
capsule_repr(PyObject *o)
264
{
265
PyCapsule *capsule = (PyCapsule *)o;
266
const char *name;
267
const char *quote;
268
269
if (capsule->name) {
270
quote = "\"";
271
name = capsule->name;
272
} else {
273
quote = "";
274
name = "NULL";
275
}
276
277
return PyUnicode_FromFormat("<capsule object %s%s%s at %p>",
278
quote, name, quote, capsule);
279
}
280
281
282
283
PyDoc_STRVAR(PyCapsule_Type__doc__,
284
"Capsule objects let you wrap a C \"void *\" pointer in a Python\n\
285
object. They're a way of passing data through the Python interpreter\n\
286
without creating your own custom type.\n\
287
\n\
288
Capsules are used for communication between extension modules.\n\
289
They provide a way for an extension module to export a C interface\n\
290
to other extension modules, so that extension modules can use the\n\
291
Python import mechanism to link to one another.\n\
292
");
293
294
PyTypeObject PyCapsule_Type = {
295
PyVarObject_HEAD_INIT(&PyType_Type, 0)
296
"PyCapsule", /*tp_name*/
297
sizeof(PyCapsule), /*tp_basicsize*/
298
0, /*tp_itemsize*/
299
/* methods */
300
capsule_dealloc, /*tp_dealloc*/
301
0, /*tp_vectorcall_offset*/
302
0, /*tp_getattr*/
303
0, /*tp_setattr*/
304
0, /*tp_as_async*/
305
capsule_repr, /*tp_repr*/
306
0, /*tp_as_number*/
307
0, /*tp_as_sequence*/
308
0, /*tp_as_mapping*/
309
0, /*tp_hash*/
310
0, /*tp_call*/
311
0, /*tp_str*/
312
0, /*tp_getattro*/
313
0, /*tp_setattro*/
314
0, /*tp_as_buffer*/
315
0, /*tp_flags*/
316
PyCapsule_Type__doc__ /*tp_doc*/
317
};
318
319
320
321