1 /* Test PEP 688 - Buffers */
2
3 #include "parts.h"
4
5 #include "structmember.h" // PyMemberDef
6 #include <stddef.h> // offsetof
7
8 typedef struct {
9 PyObject_HEAD
10 PyObject *obj;
11 Py_ssize_t references;
12 } testBufObject;
13
14 static PyObject *
15 testbuf_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
16 {
17 PyObject *obj = PyBytes_FromString("test");
18 if (obj == NULL) {
19 return NULL;
20 }
21 testBufObject *self = (testBufObject *)type->tp_alloc(type, 0);
22 if (self == NULL) {
23 Py_DECREF(obj);
24 return NULL;
25 }
26 self->obj = obj;
27 self->references = 0;
28 return (PyObject *)self;
29 }
30
31 static int
32 testbuf_traverse(testBufObject *self, visitproc visit, void *arg)
33 {
34 Py_VISIT(self->obj);
35 return 0;
36 }
37
38 static int
39 testbuf_clear(testBufObject *self)
40 {
41 Py_CLEAR(self->obj);
42 return 0;
43 }
44
45 static void
46 testbuf_dealloc(testBufObject *self)
47 {
48 PyObject_GC_UnTrack(self);
49 Py_XDECREF(self->obj);
50 Py_TYPE(self)->tp_free((PyObject *) self);
51 }
52
53 static int
54 testbuf_getbuf(testBufObject *self, Py_buffer *view, int flags)
55 {
56 int buf = PyObject_GetBuffer(self->obj, view, flags);
57 Py_SETREF(view->obj, Py_NewRef(self));
58 self->references++;
59 return buf;
60 }
61
62 static void
63 testbuf_releasebuf(testBufObject *self, Py_buffer *view)
64 {
65 self->references--;
66 assert(self->references >= 0);
67 }
68
69 static PyBufferProcs testbuf_as_buffer = {
70 .bf_getbuffer = (getbufferproc) testbuf_getbuf,
71 .bf_releasebuffer = (releasebufferproc) testbuf_releasebuf,
72 };
73
74 static struct PyMemberDef testbuf_members[] = {
75 {"references", T_PYSSIZET, offsetof(testBufObject, references), READONLY},
76 {NULL},
77 };
78
79 static PyTypeObject testBufType = {
80 PyVarObject_HEAD_INIT(NULL, 0)
81 .tp_name = "testBufType",
82 .tp_basicsize = sizeof(testBufObject),
83 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
84 .tp_new = testbuf_new,
85 .tp_dealloc = (destructor) testbuf_dealloc,
86 .tp_traverse = (traverseproc) testbuf_traverse,
87 .tp_clear = (inquiry) testbuf_clear,
88 .tp_as_buffer = &testbuf_as_buffer,
89 .tp_members = testbuf_members
90 };
91
92 int
93 _PyTestCapi_Init_Buffer(PyObject *m) {
94 if (PyType_Ready(&testBufType) < 0) {
95 return -1;
96 }
97 if (PyModule_AddObjectRef(m, "testBuf", (PyObject *)&testBufType)) {
98 return -1;
99 }
100
101 return 0;
102 }