text: #define PY_SSIZE_T_CLEAN
  #include <Python.h>
  #include <datetime.h>
  #include "module.h"
  #include "tags.h"
  #include "encoder.h"
  #include "decoder.h"
  
  
  // Some notes on conventions in this code. All methods conform to a couple of
  // return styles:
  //
  // * PyObject* (mostly for methods accessible from Python) in which case a
  //   return value of NULL indicates an error, or
  //
  // * int (mostly for internal methods) in which case 0 indicates success and -1
  //   an error. This is in keeping with most of Python's C-API.
  //
  // In an attempt to avoid leaks a particular coding style is used where
  // possible:
  //
  // 1. As soon as a new reference to an object is generated / returned, a
  //    block like this follows: if (ref) { ... Py_DECREF(ref); }
  //
  // 2. The result is calculated in the "ret" local and returned only at the
  //    end of the function, once we're sure all references have been accounted
  //    for.
  //
  // 3. No "return" is permitted before the end of the function, and "break" or
  //    "goto" should be used over a minimal distance to ensure Py_DECREFs aren't
  //    jumped over.
  //
  // 4. Wherever possible, functions that return a PyObject pointer return a
  //    *new* reference (like the majority of the CPython API) as opposed to
  //    a borrowed reference.
  //
  // 5. The above rules are broken occasionally where necessary for clarity :)
  //
  // While this style helps ensure fewer leaks, it's worth noting it results in
  // rather "nested" code which looks a bit unusual / ugly for C. Furthermore,
  // it's not fool-proof; there's probably some leaks left. Please file bugs for
  // any leaks you detect!
  
  
  // break_marker singleton ////////////////////////////////////////////////////
  
  static PyObject *
  break_marker_repr(PyObject *op)
  {
      return PyUnicode_FromString("break_marker");
  }
  
  static void
  break_marker_dealloc(PyObject *ignore)
  {
      Py_FatalError("deallocating break_marker");
  }
  
  static PyObject *
  break_marker_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
  {
      if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_Size(kwargs))) {
          PyErr_SetString(PyExc_TypeError, "break_marker_type takes no arguments");
          return NULL;
      }
      Py_INCREF(break_marker);
      return break_marker;
  }
  
  static int
  break_marker_bool(PyObject *v)
  {
      return 1;
  }
  
  static PyNumberMethods break_marker_as_number = {
      .nb_bool = (inquiry) break_marker_bool,
  };
  
  PyTypeObject break_marker_type = {
      PyVarObject_HEAD_INIT(NULL, 0)
      .tp_name = "break_marker_type",
      .tp_flags = Py_TPFLAGS_DEFAULT,
      .tp_new = break_marker_new,
      .tp_dealloc = break_marker_dealloc,
      .tp_repr = break_marker_repr,
      .tp_as_number = &break_marker_as_number,
  };
  
  PyObject _break_marker_obj = {
      _PyObject_EXTRA_INIT
      1, &break_marker_type
  };
  
  
  // undefined singleton ///////////////////////////////////////////////////////
  
  static PyObject *
  undefined_repr(PyObject *op)
  {
      return PyUnicode_FromString("undefined");
  }
  
  static void
  undefined_dealloc(PyObject *ignore)
  {
      Py_FatalError("deallocating undefined");
  }
  
  static PyObject *
  undefined_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
  {
      if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_Size(kwargs))) {
          PyErr_SetString(PyExc_TypeError, "undefined_type takes no arguments");
          return NULL;
      }
      Py_INCREF(undefined);
      return undefined;
  }
  
  static int
  undefined_bool(PyObject *v)
  {
      return 0;
  }
  
  static PyNumberMethods undefined_as_number = {
      .nb_bool = (inquiry) undefined_bool,
  };
  
  PyTypeObject undefined_type = {
      PyVarObject_HEAD_INIT(NULL, 0)
      .tp_name = "undefined_type",
      .tp_flags = Py_TPFLAGS_DEFAULT,
      .tp_new = undefined_new,
      .tp_dealloc = undefined_dealloc,
      .tp_repr = undefined_repr,
      .tp_as_number = &undefined_as_number,
  };
  
  PyObject _undefined_obj = {
      _PyObject_EXTRA_INIT
      1, &undefined_type
  };
  
  
  // CBORSimpleValue namedtuple ////////////////////////////////////////////////
  
  PyTypeObject CBORSimpleValueType;
  
  static PyStructSequence_Field CBORSimpleValueFields[] = {
      {.name = "value"},
      {NULL},
  };
  
  PyDoc_STRVAR(_CBOR2_CBORSimpleValue__doc__,
  "Represents a CBOR \"simple value\", with a value of 0 to 255."
  );
  
  static PyStructSequence_Desc CBORSimpleValueDesc = {
      .name = "CBORSimpleValue",
      .doc = _CBOR2_CBORSimpleValue__doc__,
      .fields = CBORSimpleValueFields,
      .n_in_sequence = 1,
  };
  
  static PyObject *
  CBORSimpleValue_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
  {
      static char *keywords[] = {"value", NULL};
      PyObject *value = NULL, *ret;
      Py_ssize_t val;
  
      if (!PyArg_ParseTupleAndKeywords(args, kwargs, "n", keywords, &val))
          return NULL;
  
      if (val < 0 || val > 255) {
          PyErr_SetString(PyExc_TypeError, "simple value out of range (0..255)");
          return NULL;
      }
  
      ret = PyStructSequence_New(type);
      if (ret) {
          value = PyLong_FromSsize_t(val);
          if (value)
              PyStructSequence_SET_ITEM(ret, 0, value);
      }
      return ret;
  }
  
  static PyObject *
  CBORSimpleValue_richcompare(PyObject *a, PyObject *b, int op)
  {
      switch (PyObject_IsInstance(b, (PyObject *) &CBORSimpleValueType)) {
          case 1:
          return PyObject_RichCompare(
              PyStructSequence_GET_ITEM(a, 0),
              PyStructSequence_GET_ITEM(b, 0),
              op);
          case -1:
          return NULL;
      }
      switch (PyObject_IsInstance(b, (PyObject *) &PyLong_Type)) {
          case 1:
          return PyObject_RichCompare(
              PyStructSequence_GET_ITEM(a, 0), b, op);
          case -1:
          return NULL;
      }
      Py_RETURN_NOTIMPLEMENTED;
  }
  
  
  // dump/load functions ///////////////////////////////////////////////////////
  
  static PyObject *
  CBOR2_dump(PyObject *module, PyObject *args, PyObject *kwargs)
  {
      PyObject *obj = NULL, *ret = NULL;
      CBOREncoderObject *self;
      bool decref_args = false;
  
      if (PyTuple_GET_SIZE(args) == 0) {
          if (kwargs)
              obj = PyDict_GetItem(kwargs, _CBOR2_str_obj);
          if (!obj) {
              PyErr_SetString(PyExc_TypeError,
                      "dump missing 1 required argument: 'obj'");
              return NULL;
          }
          Py_INCREF(obj);
          if (PyDict_DelItem(kwargs, _CBOR2_str_obj) == -1) {
              Py_DECREF(obj);
              return NULL;
          }
      } else {
          obj = PyTuple_GET_ITEM(args, 0);
          args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));
          if (!args)
              return NULL;
          Py_INCREF(obj);
          decref_args = true;
      }
  
      self = (CBOREncoderObject *)CBOREncoder_new(&CBOREncoderType, NULL, NULL);
      if (self) {
          if (CBOREncoder_init(self, args, kwargs) == 0) {
              ret = CBOREncoder_encode(self, obj);
          }
          Py_DECREF(self);
      }
      Py_DECREF(obj);
      if (decref_args)
          Py_DECREF(args);
      return ret;
  }
  
  
  static PyObject *
  CBOR2_dumps(PyObject *module, PyObject *args, PyObject *kwargs)
  {
      PyObject *fp, *result, *new_args = NULL, *obj = NULL, *ret = NULL;
      Py_ssize_t i;
  
      if (!_CBOR2_BytesIO && _CBOR2_init_BytesIO() == -1)
          return NULL;
  
      fp = PyObject_CallFunctionObjArgs(_CBOR2_BytesIO, NULL);
      if (fp) {
          if (PyTuple_GET_SIZE(args) == 0) {
              if (kwargs)
                  obj = PyDict_GetItem(kwargs, _CBOR2_str_obj);
              if (obj) {
                  if (PyDict_DelItem(kwargs, _CBOR2_str_obj) == 0)
                      new_args = PyTuple_Pack(2, obj, fp);
              } else {
                  PyErr_SetString(PyExc_TypeError,
                          "dumps missing required argument: 'obj'");
              }
          } else {
              obj = PyTuple_GET_ITEM(args, 0);
              new_args = PyTuple_New(PyTuple_GET_SIZE(args) + 1);
              if (new_args) {
                  Py_INCREF(obj);
                  Py_INCREF(fp);
                  PyTuple_SET_ITEM(new_args, 0, obj);  // steals ref
                  PyTuple_SET_ITEM(new_args, 1, fp);  // steals ref
                  for (i = 1; i < PyTuple_GET_SIZE(args); ++i) {
                      Py_INCREF(PyTuple_GET_ITEM(args, i));
                      PyTuple_SET_ITEM(new_args, i + 1, PyTuple_GET_ITEM(args, i));
                  }
              }
          }
  
          if (new_args) {
              result = CBOR2_dump(module, new_args, kwargs);
              if (result) {
                  ret = PyObject_CallMethodObjArgs(fp, _CBOR2_str_getvalue, NULL);
                  Py_DECREF(result);
              }
              Py_DECREF(new_args);
          }
          Py_DECREF(fp);
      }
      return ret;
  }
  
  
  static PyObject *
  CBOR2_load(PyObject *module, PyObject *args, PyObject *kwargs)
  {
      PyObject *ret = NULL;
      CBORDecoderObject *self;
  
      self = (CBORDecoderObject *)CBORDecoder_new(&CBORDecoderType, NULL, NULL);
      if (self) {
          if (CBORDecoder_init(self, args, kwargs) == 0) {
              ret = CBORDecoder_decode(self);
          }
          Py_DECREF(self);
      }
      return ret;
  }
  
  
  static PyObject *
  CBOR2_loads(PyObject *module, PyObject *args, PyObject *kwargs)
  {
      PyObject *fp, *new_args = NULL, *s = NULL, *ret = NULL;
      Py_ssize_t i;
  
      if (!_CBOR2_BytesIO && _CBOR2_init_BytesIO() == -1)
          return NULL;
  
      if (PyTuple_GET_SIZE(args) == 0) {
          if (kwargs) {
              new_args = PyTuple_New(1);
              if (new_args) {
                  s = PyDict_GetItem(kwargs, _CBOR2_str_s);
                  Py_INCREF(s);
                  if (PyDict_DelItem(kwargs, _CBOR2_str_s) == -1) {
                      Py_DECREF(s);
                      Py_CLEAR(new_args);
                  }
              }
          } else {
              PyErr_SetString(PyExc_TypeError,
                      "dump missing 1 required argument: 's'");
          }
      } else {
          new_args = PyTuple_New(PyTuple_GET_SIZE(args));
          if (new_args) {
              s = PyTuple_GET_ITEM(args, 0);
              Py_INCREF(s);
              for (i = 1; i < PyTuple_GET_SIZE(args); ++i) {
                  // inc. ref because PyTuple_SET_ITEM steals a ref
                  Py_INCREF(PyTuple_GET_ITEM(args, i));
                  PyTuple_SET_ITEM(new_args, i, PyTuple_GET_ITEM(args, i));
              }
          }
      }
  
      if (new_args) {
          fp = PyObject_CallFunctionObjArgs(_CBOR2_BytesIO, s, NULL);
          if (fp) {
              PyTuple_SET_ITEM(new_args, 0, fp);
              ret = CBOR2_load(module, new_args, kwargs);
              // no need to dec. ref fp here because SET_ITEM above stole the ref
          }
          Py_DECREF(s);
          Py_DECREF(new_args);
      }
      return ret;
  }
  
  
  // Cache-init functions //////////////////////////////////////////////////////
  
  int
  _CBOR2_init_BytesIO(void)
  {
      PyObject *io;
  
      // from io import BytesIO
      io = PyImport_ImportModule("io");
      if (!io)
          goto error;
      _CBOR2_BytesIO = PyObject_GetAttr(io, _CBOR2_str_BytesIO);
      Py_DECREF(io);
      if (!_CBOR2_BytesIO)
          goto error;
      return 0;
  error:
      PyErr_SetString(PyExc_ImportError,
              "unable to import BytesIO from io");
      return -1;
  }
  
  int
  _CBOR2_init_FrozenDict(void)
  {
      PyObject *cbor2_types;
  
      // from cbor2.types import FrozenDict
      cbor2_types = PyImport_ImportModule("cbor2.types");
      if (!cbor2_types)
          goto error;
      _CBOR2_FrozenDict = PyObject_GetAttr(cbor2_types, _CBOR2_str_FrozenDict);
      Py_DECREF(cbor2_types);
      if (!_CBOR2_FrozenDict)
          goto error;
      return 0;
  error:
      PyErr_SetString(PyExc_ImportError,
              "unable to import FrozenDict from cbor2.types");
      return -1;
  }
  
  
  int
  _CBOR2_init_Decimal(void)
  {
      PyObject *decimal;
  
      // from decimal import Decimal
      decimal = PyImport_ImportModule("decimal");
      if (!decimal)
          goto error;
      _CBOR2_Decimal = PyObject_GetAttr(decimal, _CBOR2_str_Decimal);
      Py_DECREF(decimal);
      if (!_CBOR2_Decimal)
          goto error;
      return 0;
  error:
      PyErr_SetString(PyExc_ImportError, "unable to import Decimal from decimal");
      return -1;
  }
  
  
  int
  _CBOR2_init_Fraction(void)
  {
      PyObject *fractions;
  
      // from fractions import Fraction
      fractions = PyImport_ImportModule("fractions");
      if (!fractions)
          goto error;
      _CBOR2_Fraction = PyObject_GetAttr(fractions, _CBOR2_str_Fraction);
      Py_DECREF(fractions);
      if (!_CBOR2_Fraction)
          goto error;
      return 0;
  error:
      PyErr_SetString(PyExc_ImportError, "unable to import Fraction from fractions");
      return -1;
  }
  
  
  int
  _CBOR2_init_UUID(void)
  {
      PyObject *uuid;
  
      // from uuid import UUID
      uuid = PyImport_ImportModule("uuid");
      if (!uuid)
          goto error;
      _CBOR2_UUID = PyObject_GetAttr(uuid, _CBOR2_str_UUID);
      Py_DECREF(uuid);
      if (!_CBOR2_UUID)
          goto error;
      return 0;
  error:
      PyErr_SetString(PyExc_ImportError, "unable to import UUID from uuid");
      return -1;
  }
  
  
  int
  _CBOR2_init_re_compile(void)
  {
      PyObject *re;
  
      // import re
      // datestr_re = re.compile("long-date-time-regex...")
      re = PyImport_ImportModule("re");
      if (!re)
          goto error;
      _CBOR2_re_compile = PyObject_GetAttr(re, _CBOR2_str_compile);
      Py_DECREF(re);
      if (!_CBOR2_re_compile)
          goto error;
      _CBOR2_datestr_re = PyObject_CallFunctionObjArgs(
              _CBOR2_re_compile, _CBOR2_str_datestr_re, NULL);
      if (!_CBOR2_datestr_re)
          goto error;
      return 0;
  error:
      PyErr_SetString(PyExc_ImportError, "unable to import compile from re");
      return -1;
  }
  
  
  int
  _CBOR2_init_timezone_utc(void)
  {
  #if PY_VERSION_HEX >= 0x03070000
      Py_INCREF(PyDateTime_TimeZone_UTC);
      _CBOR2_timezone_utc = PyDateTime_TimeZone_UTC;
      _CBOR2_timezone = NULL;
      return 0;
  #else
      PyObject* datetime;
  
      // from datetime import timezone
      // utc = timezone.utc
      datetime = PyImport_ImportModule("datetime");
      if (!datetime)
          goto error;
      _CBOR2_timezone = PyObject_GetAttr(datetime, _CBOR2_str_timezone);
      Py_DECREF(datetime);
      if (!_CBOR2_timezone)
          goto error;
      _CBOR2_timezone_utc = PyObject_GetAttr(_CBOR2_timezone, _CBOR2_str_utc);
      if (!_CBOR2_timezone_utc)
          goto error;
      return 0;
  error:
      PyErr_SetString(PyExc_ImportError, "unable to import timezone from datetime");
      return -1;
  #endif
  }
  
  
  int
  _CBOR2_init_Parser(void)
  {
      PyObject *parser;
  
      // from email.parser import Parser
      parser = PyImport_ImportModule("email.parser");
      if (!parser)
          goto error;
      _CBOR2_Parser = PyObject_GetAttr(parser, _CBOR2_str_Parser);
      Py_DECREF(parser);
      if (!_CBOR2_Parser)
          goto error;
      return 0;
  error:
      PyErr_SetString(PyExc_ImportError, "unable to import Parser from email.parser");
      return -1;
  }
  
  
  int
  _CBOR2_init_ip_address(void)
  {
      PyObject *ipaddress;
  
      // from ipaddress import ip_address
      ipaddress = PyImport_ImportModule("ipaddress");
      if (!ipaddress)
          goto error;
      _CBOR2_ip_address = PyObject_GetAttr(ipaddress, _CBOR2_str_ip_address);
      _CBOR2_ip_network = PyObject_GetAttr(ipaddress, _CBOR2_str_ip_network);
      Py_DECREF(ipaddress);
      if (!_CBOR2_ip_address)
          goto error;
      if (!_CBOR2_ip_network)
          goto error;
      return 0;
  error:
      PyErr_SetString(PyExc_ImportError, "unable to import ip_address from ipaddress");
      return -1;
  }
  
  
  // Module definition /////////////////////////////////////////////////////////
  
  PyObject *_CBOR2_empty_bytes = NULL;
  PyObject *_CBOR2_empty_str = NULL;
  PyObject *_CBOR2_str_as_string = NULL;
  PyObject *_CBOR2_str_as_tuple = NULL;
  PyObject *_CBOR2_str_bit_length = NULL;
  PyObject *_CBOR2_str_bytes = NULL;
  PyObject *_CBOR2_str_BytesIO = NULL;
  PyObject *_CBOR2_str_canonical_encoders = NULL;
  PyObject *_CBOR2_str_compile = NULL;
  PyObject *_CBOR2_str_copy = NULL;
  PyObject *_CBOR2_str_datestr_re = NULL;
  PyObject *_CBOR2_str_Decimal = NULL;
  PyObject *_CBOR2_str_default_encoders = NULL;
  PyObject *_CBOR2_str_denominator = NULL;
  PyObject *_CBOR2_str_encode_date = NULL;
  PyObject *_CBOR2_str_Fraction = NULL;
  PyObject *_CBOR2_str_fromtimestamp = NULL;
  PyObject *_CBOR2_str_FrozenDict = NULL;
  PyObject *_CBOR2_str_getvalue = NULL;
  PyObject *_CBOR2_str_groups = NULL;
  PyObject *_CBOR2_str_ip_address = NULL;
  PyObject *_CBOR2_str_ip_network = NULL;
  PyObject *_CBOR2_str_is_infinite = NULL;
  PyObject *_CBOR2_str_is_nan = NULL;
  PyObject *_CBOR2_str_isoformat = NULL;
  PyObject *_CBOR2_str_join = NULL;
  PyObject *_CBOR2_str_match = NULL;
  PyObject *_CBOR2_str_network_address = NULL;
  PyObject *_CBOR2_str_numerator = NULL;
  PyObject *_CBOR2_str_obj = NULL;
  PyObject *_CBOR2_str_packed = NULL;
  PyObject *_CBOR2_str_Parser = NULL;
  PyObject *_CBOR2_str_parsestr = NULL;
  PyObject *_CBOR2_str_pattern = NULL;
  PyObject *_CBOR2_str_prefixlen = NULL;
  PyObject *_CBOR2_str_read = NULL;
  PyObject *_CBOR2_str_s = NULL;
  PyObject *_CBOR2_str_timestamp = NULL;
  PyObject *_CBOR2_str_timezone = NULL;
  PyObject *_CBOR2_str_update = NULL;
  PyObject *_CBOR2_str_utc = NULL;
  PyObject *_CBOR2_str_utc_suffix = NULL;
  PyObject *_CBOR2_str_UUID = NULL;
  PyObject *_CBOR2_str_write = NULL;
  
  PyObject *_CBOR2_CBORError = NULL;
  PyObject *_CBOR2_CBOREncodeError = NULL;
  PyObject *_CBOR2_CBOREncodeTypeError = NULL;
  PyObject *_CBOR2_CBOREncodeValueError = NULL;
  PyObject *_CBOR2_CBORDecodeError = NULL;
  PyObject *_CBOR2_CBORDecodeValueError = NULL;
  PyObject *_CBOR2_CBORDecodeEOF = NULL;
  
  PyObject *_CBOR2_timezone = NULL;
  PyObject *_CBOR2_timezone_utc = NULL;
  PyObject *_CBOR2_BytesIO = NULL;
  PyObject *_CBOR2_Decimal = NULL;
  PyObject *_CBOR2_Fraction = NULL;
  PyObject *_CBOR2_FrozenDict = NULL;
  PyObject *_CBOR2_UUID = NULL;
  PyObject *_CBOR2_Parser = NULL;
  PyObject *_CBOR2_re_compile = NULL;
  PyObject *_CBOR2_datestr_re = NULL;
  PyObject *_CBOR2_ip_address = NULL;
  PyObject *_CBOR2_ip_network = NULL;
  
  PyObject *_CBOR2_default_encoders = NULL;
  PyObject *_CBOR2_canonical_encoders = NULL;
  
  static void
  cbor2_free(PyObject *m)
  {
      Py_CLEAR(_CBOR2_timezone_utc);
      Py_CLEAR(_CBOR2_timezone);
      Py_CLEAR(_CBOR2_BytesIO);
      Py_CLEAR(_CBOR2_Decimal);
      Py_CLEAR(_CBOR2_Fraction);
      Py_CLEAR(_CBOR2_UUID);
      Py_CLEAR(_CBOR2_Parser);
      Py_CLEAR(_CBOR2_re_compile);
      Py_CLEAR(_CBOR2_datestr_re);
      Py_CLEAR(_CBOR2_ip_address);
      Py_CLEAR(_CBOR2_ip_network);
      Py_CLEAR(_CBOR2_CBOREncodeError);
      Py_CLEAR(_CBOR2_CBOREncodeTypeError);
      Py_CLEAR(_CBOR2_CBOREncodeValueError);
      Py_CLEAR(_CBOR2_CBORDecodeError);
      Py_CLEAR(_CBOR2_CBORDecodeValueError);
      Py_CLEAR(_CBOR2_CBORDecodeEOF);
      Py_CLEAR(_CBOR2_CBORError);
      Py_CLEAR(_CBOR2_default_encoders);
      Py_CLEAR(_CBOR2_canonical_encoders);
  }
  
  static PyMethodDef _cbor2methods[] = {
      {"dump", (PyCFunction) CBOR2_dump, METH_VARARGS | METH_KEYWORDS,
          "encode a value to the stream"},
      {"dumps", (PyCFunction) CBOR2_dumps, METH_VARARGS | METH_KEYWORDS,
          "encode a value to a byte-string"},
      {"load", (PyCFunction) CBOR2_load, METH_VARARGS | METH_KEYWORDS,
          "decode a value from the stream"},
      {"loads", (PyCFunction) CBOR2_loads, METH_VARARGS | METH_KEYWORDS,
          "decode a value from a byte-string"},
      {NULL}
  };
  
  PyDoc_STRVAR(_cbor2__doc__,
  "The _cbor2 module is the C-extension backing the cbor2 Python module. It\n"
  "defines the base :exc:`CBORError`, :exc:`CBOREncodeError`,\n"
  ":exc:`CBOREncodeTypeError`, :exc:`CBOREncodeValueError`,\n"
  ":exc:`CBORDecodeError`, :exc:`CBORDecodeValueError`, :exc:`CBORDecodeEOF`,\n"
  ":class:`CBOREncoder`, :class:`CBORDecoder`, :class:`CBORTag`, and undefined\n"
  "types which are operational in and of themselves."
  );
  
  PyDoc_STRVAR(_cbor2_CBORError__doc__,
  "Base class for errors that occur during CBOR encoding or decoding."
  );
  
  PyDoc_STRVAR(_cbor2_CBOREncodeError__doc__,
  "Raised for exceptions occurring during CBOR encoding."
  );
  
  PyDoc_STRVAR(_cbor2_CBOREncodeTypeError__doc__,
  "Raised when attempting to encode a type that cannot be serialized."
  );
  
  PyDoc_STRVAR(_cbor2_CBOREncodeValueError__doc__,
  "Raised when the CBOR encoder encounters an invalid value."
  );
  
  PyDoc_STRVAR(_cbor2_CBORDecodeError__doc__,
  "Raised for exceptions occurring during CBOR decoding."
  );
  
  PyDoc_STRVAR(_cbor2_CBORDecodeValueError__doc__,
  "Raised when the CBOR stream being decoded contains an invalid value."
  );
  
  PyDoc_STRVAR(_cbor2_CBORDecodeEOF__doc__,
  "Raised when decoding unexpectedly reaches EOF."
  );
  
  static struct PyModuleDef _cbor2module = {
      PyModuleDef_HEAD_INIT,
      .m_name = "_cbor2",
      .m_doc = _cbor2__doc__,
      .m_size = -1,
      .m_free = (freefunc) cbor2_free,
      .m_methods = _cbor2methods,
  };
  
  int
  init_default_encoders(void)
  {
      PyObject *mod, *dict;
  
      // NOTE: All functions below return borrowed references, hence the lack of
      // DECREF calls
      if (_CBOR2_default_encoders)
          return 0;
      mod = PyState_FindModule(&_cbor2module);
      if (!mod)
          return -1;
      dict = PyModule_GetDict(mod);
      if (!dict)
          return -1;
      _CBOR2_default_encoders = PyDict_GetItem(
          dict, _CBOR2_str_default_encoders);
      if (_CBOR2_default_encoders) {
          Py_INCREF(_CBOR2_default_encoders);
          return 0;
      }
      return -1;
  }
  
  int
  init_canonical_encoders(void)
  {
      PyObject *mod, *dict;
  
      // NOTE: All functions below return borrowed references, hence the lack of
      // DECREF calls
      if (_CBOR2_canonical_encoders)
          return 0;
      mod = PyState_FindModule(&_cbor2module);
      if (!mod)
          return -1;
      dict = PyModule_GetDict(mod);
      if (!dict)
          return -1;
      _CBOR2_canonical_encoders = PyDict_GetItem(
          dict, _CBOR2_str_canonical_encoders);
      if (_CBOR2_canonical_encoders) {
          Py_INCREF(_CBOR2_canonical_encoders);
          return 0;
      }
      return -1;
  }
  
  PyMODINIT_FUNC
  PyInit__cbor2(void)
  {
      PyObject *module, *base;
  
      PyDateTime_IMPORT;
      if (!PyDateTimeAPI)
          return NULL;
  
      if (PyType_Ready(&break_marker_type) < 0)
          return NULL;
      if (PyType_Ready(&undefined_type) < 0)
          return NULL;
      if (PyType_Ready(&CBORTagType) < 0)
          return NULL;
      if (PyType_Ready(&CBOREncoderType) < 0)
          return NULL;
      if (PyType_Ready(&CBORDecoderType) < 0)
          return NULL;
  
      module = PyModule_Create(&_cbor2module);
      if (!module)
          return NULL;
  
      _CBOR2_CBORError = PyErr_NewExceptionWithDoc(
              "_cbor2.CBORError", _cbor2_CBORError__doc__, NULL, NULL);
      if (!_CBOR2_CBORError)
          goto error;
      Py_INCREF(_CBOR2_CBORError);
      if (PyModule_AddObject(module, "CBORError", _CBOR2_CBORError) == -1)
          goto error;
  
      _CBOR2_CBOREncodeError = PyErr_NewExceptionWithDoc(
              "_cbor2.CBOREncodeError", _cbor2_CBOREncodeError__doc__,
              _CBOR2_CBORError, NULL);
      if (!_CBOR2_CBOREncodeError)
          goto error;
      Py_INCREF(_CBOR2_CBOREncodeError);
      if (PyModule_AddObject(module, "CBOREncodeError", _CBOR2_CBOREncodeError) == -1)
          goto error;
  
      base = PyTuple_Pack(2, _CBOR2_CBOREncodeError, PyExc_TypeError);
      _CBOR2_CBOREncodeTypeError = PyErr_NewExceptionWithDoc(
              "_cbor2.CBOREncodeTypeError", _cbor2_CBOREncodeTypeError__doc__,
              base, NULL);
      Py_DECREF(base);
      if (!_CBOR2_CBOREncodeTypeError)
          goto error;
      Py_INCREF(_CBOR2_CBOREncodeTypeError);
      if (PyModule_AddObject(module, "CBOREncodeTypeError", _CBOR2_CBOREncodeTypeError) == -1)
          goto error;
  
      base = PyTuple_Pack(2, _CBOR2_CBOREncodeError, PyExc_ValueError);
      _CBOR2_CBOREncodeValueError = PyErr_NewExceptionWithDoc(
              "_cbor2.CBOREncodeValueError", _cbor2_CBOREncodeValueError__doc__,
              base, NULL);
      Py_DECREF(base);
      if (!_CBOR2_CBOREncodeValueError)
          goto error;
      Py_INCREF(_CBOR2_CBOREncodeValueError);
      if (PyModule_AddObject(module, "CBOREncodeValueError", _CBOR2_CBOREncodeValueError) == -1)
          goto error;
  
      _CBOR2_CBORDecodeError = PyErr_NewExceptionWithDoc(
              "_cbor2.CBORDecodeError", _cbor2_CBORDecodeError__doc__,
              _CBOR2_CBORError, NULL);
      if (!_CBOR2_CBORDecodeError)
          goto error;
      Py_INCREF(_CBOR2_CBORDecodeError);
      if (PyModule_AddObject(module, "CBORDecodeError", _CBOR2_CBORDecodeError) == -1)
          goto error;
  
      base = PyTuple_Pack(2, _CBOR2_CBORDecodeError, PyExc_ValueError);
      _CBOR2_CBORDecodeValueError = PyErr_NewExceptionWithDoc(
              "_cbor2.CBORDecodeValueError", _cbor2_CBORDecodeValueError__doc__,
              base, NULL);
      Py_DECREF(base);
      if (!_CBOR2_CBORDecodeValueError)
          goto error;
      Py_INCREF(_CBOR2_CBORDecodeValueError);
      if (PyModule_AddObject(module, "CBORDecodeValueError", _CBOR2_CBORDecodeValueError) == -1)
          goto error;
  
      base = PyTuple_Pack(2, _CBOR2_CBORDecodeError, PyExc_EOFError);
      _CBOR2_CBORDecodeEOF = PyErr_NewExceptionWithDoc(
              "_cbor2.CBORDecodeEOF", _cbor2_CBORDecodeEOF__doc__,
              base, NULL);
      Py_DECREF(base);
      if (!_CBOR2_CBORDecodeEOF)
          goto error;
      Py_INCREF(_CBOR2_CBORDecodeEOF);
      if (PyModule_AddObject(module, "CBORDecodeEOF", _CBOR2_CBORDecodeEOF) == -1)
          goto error;
  
  #if PY_VERSION_HEX >= 0x03040000
      // Use PyStructSequence_InitType2 to workaround #34784 (dup of #28709)
      if (PyStructSequence_InitType2(&CBORSimpleValueType, &CBORSimpleValueDesc) == -1)
          goto error;
  #else
      // PyStructSequence_InitType2 was added in 3.4
      PyStructSequence_InitType(&CBORSimpleValueType, &CBORSimpleValueDesc);
  #endif
      Py_INCREF((PyObject *) &CBORSimpleValueType);
      CBORSimpleValueType.tp_new = CBORSimpleValue_new;
      CBORSimpleValueType.tp_richcompare = CBORSimpleValue_richcompare;
      if (PyModule_AddObject(
              module, "CBORSimpleValue", (PyObject *) &CBORSimpleValueType) == -1)
          goto error;
  
      Py_INCREF(&CBORTagType);
      if (PyModule_AddObject(module, "CBORTag", (PyObject *) &CBORTagType) == -1)
          goto error;
  
      Py_INCREF(&CBOREncoderType);
      if (PyModule_AddObject(module, "CBOREncoder", (PyObject *) &CBOREncoderType) == -1)
          goto error;
  
      Py_INCREF(&CBORDecoderType);
      if (PyModule_AddObject(module, "CBORDecoder", (PyObject *) &CBORDecoderType) == -1)
          goto error;
  
      Py_INCREF(break_marker);
      if (PyModule_AddObject(module, "break_marker", break_marker) == -1)
          goto error;
  
      Py_INCREF(undefined);
      if (PyModule_AddObject(module, "undefined", undefined) == -1)
          goto error;
  
  #define INTERN_STRING(name)                                           \
      if (!_CBOR2_str_##name &&                                         \
              !(_CBOR2_str_##name = PyUnicode_InternFromString(#name))) \
          goto error;
  
      INTERN_STRING(as_string);
      INTERN_STRING(as_tuple);
      INTERN_STRING(bit_length);
      INTERN_STRING(bytes);
      INTERN_STRING(BytesIO);
      INTERN_STRING(canonical_encoders);
      INTERN_STRING(compile);
      INTERN_STRING(copy);
      INTERN_STRING(Decimal);
      INTERN_STRING(default_encoders);
      INTERN_STRING(denominator);
      INTERN_STRING(encode_date);
      INTERN_STRING(Fraction);
      INTERN_STRING(fromtimestamp);
      INTERN_STRING(FrozenDict);
      INTERN_STRING(getvalue);
      INTERN_STRING(groups);
      INTERN_STRING(ip_address);
      INTERN_STRING(ip_network);
      INTERN_STRING(is_infinite);
      INTERN_STRING(is_nan);
      INTERN_STRING(isoformat);
      INTERN_STRING(join);
      INTERN_STRING(match);
      INTERN_STRING(network_address);
      INTERN_STRING(numerator);
      INTERN_STRING(obj);
      INTERN_STRING(packed);
      INTERN_STRING(Parser);
      INTERN_STRING(parsestr);
      INTERN_STRING(pattern);
      INTERN_STRING(prefixlen);
      INTERN_STRING(read);
      INTERN_STRING(s);
      INTERN_STRING(timestamp);
      INTERN_STRING(timezone);
      INTERN_STRING(update);
      INTERN_STRING(utc);
      INTERN_STRING(UUID);
      INTERN_STRING(write);
  
  #undef INTERN_STRING
  
      if (!_CBOR2_str_utc_suffix &&
              !(_CBOR2_str_utc_suffix = PyUnicode_InternFromString("+00:00")))
          goto error;
      if (!_CBOR2_str_datestr_re &&
              !(_CBOR2_str_datestr_re = PyUnicode_InternFromString(
                      "^(\\d{4})-(\\d\\d)-(\\d\\d)T"     // Y-m-d
                      "(\\d\\d):(\\d\\d):(\\d\\d)"       // H:M:S
                      "(?:\\.(\\d{1,6})\\d*)?"           // .uS
                      "(?:Z|([+-]\\d\\d):(\\d\\d))$")))  // +-TZ
          goto error;
      if (!_CBOR2_empty_bytes &&
              !(_CBOR2_empty_bytes = PyBytes_FromStringAndSize(NULL, 0)))
          goto error;
      if (!_CBOR2_empty_str &&
              !(_CBOR2_empty_str = PyUnicode_FromStringAndSize(NULL, 0)))
          goto error;
  
      return module;
  error:
      Py_DECREF(module);
      return NULL;
  }
  