17db96d56Sopenharmony_ci/* Use this file as a template to start implementing a module that
27db96d56Sopenharmony_ci   also declares object types. All occurrences of 'Xxo' should be changed
37db96d56Sopenharmony_ci   to something reasonable for your objects. After that, all other
47db96d56Sopenharmony_ci   occurrences of 'xx' should be changed to something reasonable for your
57db96d56Sopenharmony_ci   module. If your module is named foo your source file should be named
67db96d56Sopenharmony_ci   foo.c or foomodule.c.
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ci   You will probably want to delete all references to 'x_attr' and add
97db96d56Sopenharmony_ci   your own types of attributes instead.  Maybe you want to name your
107db96d56Sopenharmony_ci   local variables other than 'self'.  If your object type is needed in
117db96d56Sopenharmony_ci   other files, you'll have to create a file "foobarobject.h"; see
127db96d56Sopenharmony_ci   floatobject.h for an example.
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ci   This module roughly corresponds to::
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci      class Xxo:
177db96d56Sopenharmony_ci         """A class that explicitly stores attributes in an internal dict"""
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ci          def __init__(self):
207db96d56Sopenharmony_ci              # In the C class, "_x_attr" is not accessible from Python code
217db96d56Sopenharmony_ci              self._x_attr = {}
227db96d56Sopenharmony_ci              self._x_exports = 0
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ci          def __getattr__(self, name):
257db96d56Sopenharmony_ci              return self._x_attr[name]
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ci          def __setattr__(self, name, value):
287db96d56Sopenharmony_ci              self._x_attr[name] = value
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci          def __delattr__(self, name):
317db96d56Sopenharmony_ci              del self._x_attr[name]
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci          @property
347db96d56Sopenharmony_ci          def x_exports(self):
357db96d56Sopenharmony_ci              """Return the number of times an internal buffer is exported."""
367db96d56Sopenharmony_ci              # Each Xxo instance has a 10-byte buffer that can be
377db96d56Sopenharmony_ci              # accessed via the buffer interface (e.g. `memoryview`).
387db96d56Sopenharmony_ci              return self._x_exports
397db96d56Sopenharmony_ci
407db96d56Sopenharmony_ci          def demo(o, /):
417db96d56Sopenharmony_ci              if isinstance(o, str):
427db96d56Sopenharmony_ci                  return o
437db96d56Sopenharmony_ci              elif isinstance(o, Xxo):
447db96d56Sopenharmony_ci                  return o
457db96d56Sopenharmony_ci              else:
467db96d56Sopenharmony_ci                  raise Error('argument must be str or Xxo')
477db96d56Sopenharmony_ci
487db96d56Sopenharmony_ci      class Error(Exception):
497db96d56Sopenharmony_ci          """Exception raised by the xxlimited module"""
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ci      def foo(i: int, j: int, /):
527db96d56Sopenharmony_ci          """Return the sum of i and j."""
537db96d56Sopenharmony_ci          # Unlike this pseudocode, the C function will *only* work with
547db96d56Sopenharmony_ci          # integers and perform C long int arithmetic
557db96d56Sopenharmony_ci          return i + j
567db96d56Sopenharmony_ci
577db96d56Sopenharmony_ci      def new():
587db96d56Sopenharmony_ci          return Xxo()
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci      def Str(str):
617db96d56Sopenharmony_ci          # A trivial subclass of a built-in type
627db96d56Sopenharmony_ci          pass
637db96d56Sopenharmony_ci   */
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_ci#define Py_LIMITED_API 0x030b0000
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci#include "Python.h"
687db96d56Sopenharmony_ci#include <string.h>
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ci#define BUFSIZE 10
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ci// Module state
737db96d56Sopenharmony_citypedef struct {
747db96d56Sopenharmony_ci    PyObject *Xxo_Type;    // Xxo class
757db96d56Sopenharmony_ci    PyObject *Error_Type;       // Error class
767db96d56Sopenharmony_ci} xx_state;
777db96d56Sopenharmony_ci
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci/* Xxo objects */
807db96d56Sopenharmony_ci
817db96d56Sopenharmony_ci// Instance state
827db96d56Sopenharmony_citypedef struct {
837db96d56Sopenharmony_ci    PyObject_HEAD
847db96d56Sopenharmony_ci    PyObject            *x_attr;           /* Attributes dictionary */
857db96d56Sopenharmony_ci    char                x_buffer[BUFSIZE]; /* buffer for Py_buffer */
867db96d56Sopenharmony_ci    Py_ssize_t          x_exports;         /* how many buffer are exported */
877db96d56Sopenharmony_ci} XxoObject;
887db96d56Sopenharmony_ci
897db96d56Sopenharmony_ci// XXX: no good way to do this yet
907db96d56Sopenharmony_ci// #define XxoObject_Check(v)      Py_IS_TYPE(v, Xxo_Type)
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_cistatic XxoObject *
937db96d56Sopenharmony_cinewXxoObject(PyObject *module)
947db96d56Sopenharmony_ci{
957db96d56Sopenharmony_ci    xx_state *state = PyModule_GetState(module);
967db96d56Sopenharmony_ci    if (state == NULL) {
977db96d56Sopenharmony_ci        return NULL;
987db96d56Sopenharmony_ci    }
997db96d56Sopenharmony_ci    XxoObject *self;
1007db96d56Sopenharmony_ci    self = PyObject_GC_New(XxoObject, (PyTypeObject*)state->Xxo_Type);
1017db96d56Sopenharmony_ci    if (self == NULL) {
1027db96d56Sopenharmony_ci        return NULL;
1037db96d56Sopenharmony_ci    }
1047db96d56Sopenharmony_ci    self->x_attr = NULL;
1057db96d56Sopenharmony_ci    memset(self->x_buffer, 0, BUFSIZE);
1067db96d56Sopenharmony_ci    self->x_exports = 0;
1077db96d56Sopenharmony_ci    return self;
1087db96d56Sopenharmony_ci}
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_ci/* Xxo finalization */
1117db96d56Sopenharmony_ci
1127db96d56Sopenharmony_cistatic int
1137db96d56Sopenharmony_ciXxo_traverse(PyObject *self_obj, visitproc visit, void *arg)
1147db96d56Sopenharmony_ci{
1157db96d56Sopenharmony_ci    // Visit the type
1167db96d56Sopenharmony_ci    Py_VISIT(Py_TYPE(self_obj));
1177db96d56Sopenharmony_ci
1187db96d56Sopenharmony_ci    // Visit the attribute dict
1197db96d56Sopenharmony_ci    XxoObject *self = (XxoObject *)self_obj;
1207db96d56Sopenharmony_ci    Py_VISIT(self->x_attr);
1217db96d56Sopenharmony_ci    return 0;
1227db96d56Sopenharmony_ci}
1237db96d56Sopenharmony_ci
1247db96d56Sopenharmony_cistatic int
1257db96d56Sopenharmony_ciXxo_clear(XxoObject *self)
1267db96d56Sopenharmony_ci{
1277db96d56Sopenharmony_ci    Py_CLEAR(self->x_attr);
1287db96d56Sopenharmony_ci    return 0;
1297db96d56Sopenharmony_ci}
1307db96d56Sopenharmony_ci
1317db96d56Sopenharmony_cistatic void
1327db96d56Sopenharmony_ciXxo_finalize(PyObject *self_obj)
1337db96d56Sopenharmony_ci{
1347db96d56Sopenharmony_ci    XxoObject *self = (XxoObject *)self_obj;
1357db96d56Sopenharmony_ci    Py_CLEAR(self->x_attr);
1367db96d56Sopenharmony_ci}
1377db96d56Sopenharmony_ci
1387db96d56Sopenharmony_cistatic void
1397db96d56Sopenharmony_ciXxo_dealloc(PyObject *self)
1407db96d56Sopenharmony_ci{
1417db96d56Sopenharmony_ci    PyObject_GC_UnTrack(self);
1427db96d56Sopenharmony_ci    Xxo_finalize(self);
1437db96d56Sopenharmony_ci    PyTypeObject *tp = Py_TYPE(self);
1447db96d56Sopenharmony_ci    freefunc free = PyType_GetSlot(tp, Py_tp_free);
1457db96d56Sopenharmony_ci    free(self);
1467db96d56Sopenharmony_ci    Py_DECREF(tp);
1477db96d56Sopenharmony_ci}
1487db96d56Sopenharmony_ci
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ci/* Xxo attribute handling */
1517db96d56Sopenharmony_ci
1527db96d56Sopenharmony_cistatic PyObject *
1537db96d56Sopenharmony_ciXxo_getattro(XxoObject *self, PyObject *name)
1547db96d56Sopenharmony_ci{
1557db96d56Sopenharmony_ci    if (self->x_attr != NULL) {
1567db96d56Sopenharmony_ci        PyObject *v = PyDict_GetItemWithError(self->x_attr, name);
1577db96d56Sopenharmony_ci        if (v != NULL) {
1587db96d56Sopenharmony_ci            Py_INCREF(v);
1597db96d56Sopenharmony_ci            return v;
1607db96d56Sopenharmony_ci        }
1617db96d56Sopenharmony_ci        else if (PyErr_Occurred()) {
1627db96d56Sopenharmony_ci            return NULL;
1637db96d56Sopenharmony_ci        }
1647db96d56Sopenharmony_ci    }
1657db96d56Sopenharmony_ci    return PyObject_GenericGetAttr((PyObject *)self, name);
1667db96d56Sopenharmony_ci}
1677db96d56Sopenharmony_ci
1687db96d56Sopenharmony_cistatic int
1697db96d56Sopenharmony_ciXxo_setattro(XxoObject *self, PyObject *name, PyObject *v)
1707db96d56Sopenharmony_ci{
1717db96d56Sopenharmony_ci    if (self->x_attr == NULL) {
1727db96d56Sopenharmony_ci        // prepare the attribute dict
1737db96d56Sopenharmony_ci        self->x_attr = PyDict_New();
1747db96d56Sopenharmony_ci        if (self->x_attr == NULL) {
1757db96d56Sopenharmony_ci            return -1;
1767db96d56Sopenharmony_ci        }
1777db96d56Sopenharmony_ci    }
1787db96d56Sopenharmony_ci    if (v == NULL) {
1797db96d56Sopenharmony_ci        // delete an attribute
1807db96d56Sopenharmony_ci        int rv = PyDict_DelItem(self->x_attr, name);
1817db96d56Sopenharmony_ci        if (rv < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) {
1827db96d56Sopenharmony_ci            PyErr_SetString(PyExc_AttributeError,
1837db96d56Sopenharmony_ci                "delete non-existing Xxo attribute");
1847db96d56Sopenharmony_ci            return -1;
1857db96d56Sopenharmony_ci        }
1867db96d56Sopenharmony_ci        return rv;
1877db96d56Sopenharmony_ci    }
1887db96d56Sopenharmony_ci    else {
1897db96d56Sopenharmony_ci        // set an attribute
1907db96d56Sopenharmony_ci        return PyDict_SetItem(self->x_attr, name, v);
1917db96d56Sopenharmony_ci    }
1927db96d56Sopenharmony_ci}
1937db96d56Sopenharmony_ci
1947db96d56Sopenharmony_ci/* Xxo methods */
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_cistatic PyObject *
1977db96d56Sopenharmony_ciXxo_demo(XxoObject *self, PyTypeObject *defining_class,
1987db96d56Sopenharmony_ci         PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
1997db96d56Sopenharmony_ci{
2007db96d56Sopenharmony_ci    if (kwnames != NULL && PyObject_Length(kwnames)) {
2017db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError, "demo() takes no keyword arguments");
2027db96d56Sopenharmony_ci        return NULL;
2037db96d56Sopenharmony_ci    }
2047db96d56Sopenharmony_ci    if (nargs != 1) {
2057db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError, "demo() takes exactly 1 argument");
2067db96d56Sopenharmony_ci        return NULL;
2077db96d56Sopenharmony_ci    }
2087db96d56Sopenharmony_ci
2097db96d56Sopenharmony_ci    PyObject *o = args[0];
2107db96d56Sopenharmony_ci
2117db96d56Sopenharmony_ci    /* Test if the argument is "str" */
2127db96d56Sopenharmony_ci    if (PyUnicode_Check(o)) {
2137db96d56Sopenharmony_ci        Py_INCREF(o);
2147db96d56Sopenharmony_ci        return o;
2157db96d56Sopenharmony_ci    }
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ci    /* test if the argument is of the Xxo class */
2187db96d56Sopenharmony_ci    if (PyObject_TypeCheck(o, defining_class)) {
2197db96d56Sopenharmony_ci        Py_INCREF(o);
2207db96d56Sopenharmony_ci        return o;
2217db96d56Sopenharmony_ci    }
2227db96d56Sopenharmony_ci
2237db96d56Sopenharmony_ci    Py_INCREF(Py_None);
2247db96d56Sopenharmony_ci    return Py_None;
2257db96d56Sopenharmony_ci}
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_cistatic PyMethodDef Xxo_methods[] = {
2287db96d56Sopenharmony_ci    {"demo",            _PyCFunction_CAST(Xxo_demo),
2297db96d56Sopenharmony_ci     METH_METHOD | METH_FASTCALL | METH_KEYWORDS, PyDoc_STR("demo(o) -> o")},
2307db96d56Sopenharmony_ci    {NULL,              NULL}           /* sentinel */
2317db96d56Sopenharmony_ci};
2327db96d56Sopenharmony_ci
2337db96d56Sopenharmony_ci/* Xxo buffer interface */
2347db96d56Sopenharmony_ci
2357db96d56Sopenharmony_cistatic int
2367db96d56Sopenharmony_ciXxo_getbuffer(XxoObject *self, Py_buffer *view, int flags)
2377db96d56Sopenharmony_ci{
2387db96d56Sopenharmony_ci    int res = PyBuffer_FillInfo(view, (PyObject*)self,
2397db96d56Sopenharmony_ci                               (void *)self->x_buffer, BUFSIZE,
2407db96d56Sopenharmony_ci                               0, flags);
2417db96d56Sopenharmony_ci    if (res == 0) {
2427db96d56Sopenharmony_ci        self->x_exports++;
2437db96d56Sopenharmony_ci    }
2447db96d56Sopenharmony_ci    return res;
2457db96d56Sopenharmony_ci}
2467db96d56Sopenharmony_ci
2477db96d56Sopenharmony_cistatic void
2487db96d56Sopenharmony_ciXxo_releasebuffer(XxoObject *self, Py_buffer *view)
2497db96d56Sopenharmony_ci{
2507db96d56Sopenharmony_ci    self->x_exports--;
2517db96d56Sopenharmony_ci}
2527db96d56Sopenharmony_ci
2537db96d56Sopenharmony_cistatic PyObject *
2547db96d56Sopenharmony_ciXxo_get_x_exports(XxoObject *self, void *c)
2557db96d56Sopenharmony_ci{
2567db96d56Sopenharmony_ci    return PyLong_FromSsize_t(self->x_exports);
2577db96d56Sopenharmony_ci}
2587db96d56Sopenharmony_ci
2597db96d56Sopenharmony_ci/* Xxo type definition */
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ciPyDoc_STRVAR(Xxo_doc,
2627db96d56Sopenharmony_ci             "A class that explicitly stores attributes in an internal dict");
2637db96d56Sopenharmony_ci
2647db96d56Sopenharmony_cistatic PyGetSetDef Xxo_getsetlist[] = {
2657db96d56Sopenharmony_ci    {"x_exports", (getter) Xxo_get_x_exports, NULL, NULL},
2667db96d56Sopenharmony_ci    {NULL},
2677db96d56Sopenharmony_ci};
2687db96d56Sopenharmony_ci
2697db96d56Sopenharmony_ci
2707db96d56Sopenharmony_cistatic PyType_Slot Xxo_Type_slots[] = {
2717db96d56Sopenharmony_ci    {Py_tp_doc, (char *)Xxo_doc},
2727db96d56Sopenharmony_ci    {Py_tp_traverse, Xxo_traverse},
2737db96d56Sopenharmony_ci    {Py_tp_clear, Xxo_clear},
2747db96d56Sopenharmony_ci    {Py_tp_finalize, Xxo_finalize},
2757db96d56Sopenharmony_ci    {Py_tp_dealloc, Xxo_dealloc},
2767db96d56Sopenharmony_ci    {Py_tp_getattro, Xxo_getattro},
2777db96d56Sopenharmony_ci    {Py_tp_setattro, Xxo_setattro},
2787db96d56Sopenharmony_ci    {Py_tp_methods, Xxo_methods},
2797db96d56Sopenharmony_ci    {Py_bf_getbuffer, Xxo_getbuffer},
2807db96d56Sopenharmony_ci    {Py_bf_releasebuffer, Xxo_releasebuffer},
2817db96d56Sopenharmony_ci    {Py_tp_getset, Xxo_getsetlist},
2827db96d56Sopenharmony_ci    {0, 0},  /* sentinel */
2837db96d56Sopenharmony_ci};
2847db96d56Sopenharmony_ci
2857db96d56Sopenharmony_cistatic PyType_Spec Xxo_Type_spec = {
2867db96d56Sopenharmony_ci    .name = "xxlimited.Xxo",
2877db96d56Sopenharmony_ci    .basicsize = sizeof(XxoObject),
2887db96d56Sopenharmony_ci    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
2897db96d56Sopenharmony_ci    .slots = Xxo_Type_slots,
2907db96d56Sopenharmony_ci};
2917db96d56Sopenharmony_ci
2927db96d56Sopenharmony_ci
2937db96d56Sopenharmony_ci/* Str type definition*/
2947db96d56Sopenharmony_ci
2957db96d56Sopenharmony_cistatic PyType_Slot Str_Type_slots[] = {
2967db96d56Sopenharmony_ci    {0, 0},  /* sentinel */
2977db96d56Sopenharmony_ci};
2987db96d56Sopenharmony_ci
2997db96d56Sopenharmony_cistatic PyType_Spec Str_Type_spec = {
3007db96d56Sopenharmony_ci    .name = "xxlimited.Str",
3017db96d56Sopenharmony_ci    .basicsize = 0,
3027db96d56Sopenharmony_ci    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
3037db96d56Sopenharmony_ci    .slots = Str_Type_slots,
3047db96d56Sopenharmony_ci};
3057db96d56Sopenharmony_ci
3067db96d56Sopenharmony_ci
3077db96d56Sopenharmony_ci/* Function of two integers returning integer (with C "long int" arithmetic) */
3087db96d56Sopenharmony_ci
3097db96d56Sopenharmony_ciPyDoc_STRVAR(xx_foo_doc,
3107db96d56Sopenharmony_ci"foo(i,j)\n\
3117db96d56Sopenharmony_ci\n\
3127db96d56Sopenharmony_ciReturn the sum of i and j.");
3137db96d56Sopenharmony_ci
3147db96d56Sopenharmony_cistatic PyObject *
3157db96d56Sopenharmony_cixx_foo(PyObject *module, PyObject *args)
3167db96d56Sopenharmony_ci{
3177db96d56Sopenharmony_ci    long i, j;
3187db96d56Sopenharmony_ci    long res;
3197db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "ll:foo", &i, &j))
3207db96d56Sopenharmony_ci        return NULL;
3217db96d56Sopenharmony_ci    res = i+j; /* XXX Do something here */
3227db96d56Sopenharmony_ci    return PyLong_FromLong(res);
3237db96d56Sopenharmony_ci}
3247db96d56Sopenharmony_ci
3257db96d56Sopenharmony_ci
3267db96d56Sopenharmony_ci/* Function of no arguments returning new Xxo object */
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_cistatic PyObject *
3297db96d56Sopenharmony_cixx_new(PyObject *module, PyObject *Py_UNUSED(unused))
3307db96d56Sopenharmony_ci{
3317db96d56Sopenharmony_ci    XxoObject *rv;
3327db96d56Sopenharmony_ci
3337db96d56Sopenharmony_ci    rv = newXxoObject(module);
3347db96d56Sopenharmony_ci    if (rv == NULL)
3357db96d56Sopenharmony_ci        return NULL;
3367db96d56Sopenharmony_ci    return (PyObject *)rv;
3377db96d56Sopenharmony_ci}
3387db96d56Sopenharmony_ci
3397db96d56Sopenharmony_ci
3407db96d56Sopenharmony_ci
3417db96d56Sopenharmony_ci/* List of functions defined in the module */
3427db96d56Sopenharmony_ci
3437db96d56Sopenharmony_cistatic PyMethodDef xx_methods[] = {
3447db96d56Sopenharmony_ci    {"foo",             xx_foo,         METH_VARARGS,
3457db96d56Sopenharmony_ci        xx_foo_doc},
3467db96d56Sopenharmony_ci    {"new",             xx_new,         METH_NOARGS,
3477db96d56Sopenharmony_ci        PyDoc_STR("new() -> new Xx object")},
3487db96d56Sopenharmony_ci    {NULL,              NULL}           /* sentinel */
3497db96d56Sopenharmony_ci};
3507db96d56Sopenharmony_ci
3517db96d56Sopenharmony_ci
3527db96d56Sopenharmony_ci/* The module itself */
3537db96d56Sopenharmony_ci
3547db96d56Sopenharmony_ciPyDoc_STRVAR(module_doc,
3557db96d56Sopenharmony_ci"This is a template module just for instruction.");
3567db96d56Sopenharmony_ci
3577db96d56Sopenharmony_cistatic int
3587db96d56Sopenharmony_cixx_modexec(PyObject *m)
3597db96d56Sopenharmony_ci{
3607db96d56Sopenharmony_ci    xx_state *state = PyModule_GetState(m);
3617db96d56Sopenharmony_ci
3627db96d56Sopenharmony_ci    state->Error_Type = PyErr_NewException("xxlimited.Error", NULL, NULL);
3637db96d56Sopenharmony_ci    if (state->Error_Type == NULL) {
3647db96d56Sopenharmony_ci        return -1;
3657db96d56Sopenharmony_ci    }
3667db96d56Sopenharmony_ci    if (PyModule_AddType(m, (PyTypeObject*)state->Error_Type) < 0) {
3677db96d56Sopenharmony_ci        return -1;
3687db96d56Sopenharmony_ci    }
3697db96d56Sopenharmony_ci
3707db96d56Sopenharmony_ci    state->Xxo_Type = PyType_FromModuleAndSpec(m, &Xxo_Type_spec, NULL);
3717db96d56Sopenharmony_ci    if (state->Xxo_Type == NULL) {
3727db96d56Sopenharmony_ci        return -1;
3737db96d56Sopenharmony_ci    }
3747db96d56Sopenharmony_ci    if (PyModule_AddType(m, (PyTypeObject*)state->Xxo_Type) < 0) {
3757db96d56Sopenharmony_ci        return -1;
3767db96d56Sopenharmony_ci    }
3777db96d56Sopenharmony_ci
3787db96d56Sopenharmony_ci    // Add the Str type. It is not needed from C code, so it is only
3797db96d56Sopenharmony_ci    // added to the module dict.
3807db96d56Sopenharmony_ci    // It does not inherit from "object" (PyObject_Type), but from "str"
3817db96d56Sopenharmony_ci    // (PyUnincode_Type).
3827db96d56Sopenharmony_ci    PyObject *Str_Type = PyType_FromModuleAndSpec(
3837db96d56Sopenharmony_ci        m, &Str_Type_spec, (PyObject *)&PyUnicode_Type);
3847db96d56Sopenharmony_ci    if (Str_Type == NULL) {
3857db96d56Sopenharmony_ci        return -1;
3867db96d56Sopenharmony_ci    }
3877db96d56Sopenharmony_ci    if (PyModule_AddType(m, (PyTypeObject*)Str_Type) < 0) {
3887db96d56Sopenharmony_ci        return -1;
3897db96d56Sopenharmony_ci    }
3907db96d56Sopenharmony_ci    Py_DECREF(Str_Type);
3917db96d56Sopenharmony_ci
3927db96d56Sopenharmony_ci    return 0;
3937db96d56Sopenharmony_ci}
3947db96d56Sopenharmony_ci
3957db96d56Sopenharmony_cistatic PyModuleDef_Slot xx_slots[] = {
3967db96d56Sopenharmony_ci    {Py_mod_exec, xx_modexec},
3977db96d56Sopenharmony_ci    {0, NULL}
3987db96d56Sopenharmony_ci};
3997db96d56Sopenharmony_ci
4007db96d56Sopenharmony_cistatic int
4017db96d56Sopenharmony_cixx_traverse(PyObject *module, visitproc visit, void *arg)
4027db96d56Sopenharmony_ci{
4037db96d56Sopenharmony_ci    xx_state *state = PyModule_GetState(module);
4047db96d56Sopenharmony_ci    Py_VISIT(state->Xxo_Type);
4057db96d56Sopenharmony_ci    Py_VISIT(state->Error_Type);
4067db96d56Sopenharmony_ci    return 0;
4077db96d56Sopenharmony_ci}
4087db96d56Sopenharmony_ci
4097db96d56Sopenharmony_cistatic int
4107db96d56Sopenharmony_cixx_clear(PyObject *module)
4117db96d56Sopenharmony_ci{
4127db96d56Sopenharmony_ci    xx_state *state = PyModule_GetState(module);
4137db96d56Sopenharmony_ci    Py_CLEAR(state->Xxo_Type);
4147db96d56Sopenharmony_ci    Py_CLEAR(state->Error_Type);
4157db96d56Sopenharmony_ci    return 0;
4167db96d56Sopenharmony_ci}
4177db96d56Sopenharmony_ci
4187db96d56Sopenharmony_cistatic struct PyModuleDef xxmodule = {
4197db96d56Sopenharmony_ci    PyModuleDef_HEAD_INIT,
4207db96d56Sopenharmony_ci    .m_name = "xxlimited",
4217db96d56Sopenharmony_ci    .m_doc = module_doc,
4227db96d56Sopenharmony_ci    .m_size = sizeof(xx_state),
4237db96d56Sopenharmony_ci    .m_methods = xx_methods,
4247db96d56Sopenharmony_ci    .m_slots = xx_slots,
4257db96d56Sopenharmony_ci    .m_traverse = xx_traverse,
4267db96d56Sopenharmony_ci    .m_clear = xx_clear,
4277db96d56Sopenharmony_ci    /* m_free is not necessary here: xx_clear clears all references,
4287db96d56Sopenharmony_ci     * and the module state is deallocated along with the module.
4297db96d56Sopenharmony_ci     */
4307db96d56Sopenharmony_ci};
4317db96d56Sopenharmony_ci
4327db96d56Sopenharmony_ci
4337db96d56Sopenharmony_ci/* Export function for the module (*must* be called PyInit_xx) */
4347db96d56Sopenharmony_ci
4357db96d56Sopenharmony_ciPyMODINIT_FUNC
4367db96d56Sopenharmony_ciPyInit_xxlimited(void)
4377db96d56Sopenharmony_ci{
4387db96d56Sopenharmony_ci    return PyModuleDef_Init(&xxmodule);
4397db96d56Sopenharmony_ci}
440