1 /* Test PEP 688 - Buffers */
2
3 #include "parts.h"
4
5
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 *
testbuf_new(PyTypeObject * type,PyObject * args,PyObject * kwds)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
testbuf_traverse(testBufObject * self,visitproc visit,void * arg)32 testbuf_traverse(testBufObject *self, visitproc visit, void *arg)
33 {
34 Py_VISIT(self->obj);
35 return 0;
36 }
37
38 static int
testbuf_clear(testBufObject * self)39 testbuf_clear(testBufObject *self)
40 {
41 Py_CLEAR(self->obj);
42 return 0;
43 }
44
45 static void
testbuf_dealloc(testBufObject * self)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
testbuf_getbuf(testBufObject * self,Py_buffer * view,int flags)54 testbuf_getbuf(testBufObject *self, Py_buffer *view, int flags)
55 {
56 int buf = PyObject_GetBuffer(self->obj, view, flags);
57 if (buf == 0) {
58 Py_SETREF(view->obj, Py_NewRef(self));
59 self->references++;
60 }
61 return buf;
62 }
63
64 static void
testbuf_releasebuf(testBufObject * self,Py_buffer * view)65 testbuf_releasebuf(testBufObject *self, Py_buffer *view)
66 {
67 self->references--;
68 assert(self->references >= 0);
69 }
70
71 static PyBufferProcs testbuf_as_buffer = {
72 .bf_getbuffer = (getbufferproc) testbuf_getbuf,
73 .bf_releasebuffer = (releasebufferproc) testbuf_releasebuf,
74 };
75
76 static struct PyMemberDef testbuf_members[] = {
77 {"references", Py_T_PYSSIZET, offsetof(testBufObject, references), Py_READONLY},
78 {NULL},
79 };
80
81 static PyTypeObject testBufType = {
82 PyVarObject_HEAD_INIT(NULL, 0)
83 .tp_name = "testBufType",
84 .tp_basicsize = sizeof(testBufObject),
85 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
86 .tp_new = testbuf_new,
87 .tp_dealloc = (destructor) testbuf_dealloc,
88 .tp_traverse = (traverseproc) testbuf_traverse,
89 .tp_clear = (inquiry) testbuf_clear,
90 .tp_as_buffer = &testbuf_as_buffer,
91 .tp_members = testbuf_members
92 };
93
94 int
_PyTestCapi_Init_Buffer(PyObject * m)95 _PyTestCapi_Init_Buffer(PyObject *m) {
96 if (PyType_Ready(&testBufType) < 0) {
97 return -1;
98 }
99 if (PyModule_AddObjectRef(m, "testBuf", (PyObject *)&testBufType)) {
100 return -1;
101 }
102
103 return 0;
104 }
105