/* Test PEP 688 - Buffers */ #include "parts.h" #include // offsetof typedef struct { PyObject_HEAD PyObject *obj; Py_ssize_t references; } testBufObject; static PyObject * testbuf_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *obj = PyBytes_FromString("test"); if (obj == NULL) { return NULL; } testBufObject *self = (testBufObject *)type->tp_alloc(type, 0); if (self == NULL) { Py_DECREF(obj); return NULL; } self->obj = obj; self->references = 0; return (PyObject *)self; } static int testbuf_traverse(testBufObject *self, visitproc visit, void *arg) { Py_VISIT(self->obj); return 0; } static int testbuf_clear(testBufObject *self) { Py_CLEAR(self->obj); return 0; } static void testbuf_dealloc(testBufObject *self) { PyObject_GC_UnTrack(self); Py_XDECREF(self->obj); Py_TYPE(self)->tp_free((PyObject *) self); } static int testbuf_getbuf(testBufObject *self, Py_buffer *view, int flags) { int buf = PyObject_GetBuffer(self->obj, view, flags); if (buf == 0) { Py_SETREF(view->obj, Py_NewRef(self)); self->references++; } return buf; } static void testbuf_releasebuf(testBufObject *self, Py_buffer *view) { self->references--; assert(self->references >= 0); } static PyBufferProcs testbuf_as_buffer = { .bf_getbuffer = (getbufferproc) testbuf_getbuf, .bf_releasebuffer = (releasebufferproc) testbuf_releasebuf, }; static struct PyMemberDef testbuf_members[] = { {"references", Py_T_PYSSIZET, offsetof(testBufObject, references), Py_READONLY}, {NULL}, }; static PyTypeObject testBufType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "testBufType", .tp_basicsize = sizeof(testBufObject), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_new = testbuf_new, .tp_dealloc = (destructor) testbuf_dealloc, .tp_traverse = (traverseproc) testbuf_traverse, .tp_clear = (inquiry) testbuf_clear, .tp_as_buffer = &testbuf_as_buffer, .tp_members = testbuf_members }; int _PyTestCapi_Init_Buffer(PyObject *m) { if (PyType_Ready(&testBufType) < 0) { return -1; } if (PyModule_AddObjectRef(m, "testBuf", (PyObject *)&testBufType)) { return -1; } return 0; }