Skip to content

Commit

Permalink
C Parser: cleanup PyIter_Send backport
Browse files Browse the repository at this point in the history
  • Loading branch information
MKuranowski committed Feb 20, 2024
1 parent b008b1e commit 0f924a4
Showing 1 changed file with 55 additions and 62 deletions.
117 changes: 55 additions & 62 deletions aiocsv/_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,62 @@ static inline PyObject* PyObject_CallMethodOneArg(PyObject* self, PyObject* name
#define Py_TPFLAGS_IMMUTABLETYPE 0
#define Py_TPFLAGS_DISALLOW_INSTANTIATION 0

typedef enum {
PYGEN_RETURN = 0,
PYGEN_ERROR = -1,
PYGEN_NEXT = 1,
} PySendResult;

static inline PyObject* Py_NewRef(PyObject* o) {
Py_INCREF(o);
return o;
}

static PyObject* _fetch_stop_iteration_value(void) {
PyObject* exc_type;
PyObject* exc_value;
PyObject* exc_traceback;
PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);

assert(exc_type);
assert(PyErr_ExceptionMatches(PyExc_StopIteration));

PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback);
assert(PyObject_TypeCheck(exc_value, (PyTypeObject*)PyExc_StopIteration));

PyErr_Clear();

PyObject* value = ((PyStopIterationObject*)exc_value)->value;
Py_INCREF(value);
Py_XDECREF(exc_type);
Py_XDECREF(exc_value);
Py_XDECREF(exc_traceback);
return value;
}

static PySendResult PyIter_Send(PyObject *iter, PyObject *arg, PyObject **presult) {
assert(arg);
assert(presult);

// Ensure arg is Py_None
if (arg != Py_None) {
PyErr_SetString(PyExc_SystemError, "aiocsv's PyIter_Send backport doesn't support sending values other than None");
return PYGEN_ERROR;
}

// Ensure iter is an iterator
if (!PyIter_Check(iter)) {
PyErr_Format(PyExc_TypeError, "%R is not an iterable", Py_TYPE(iter));
return PYGEN_ERROR;
}

*presult = (Py_TYPE(iter)->tp_iternext)(iter);
if (*presult) return PYGEN_NEXT;
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) return PYGEN_ERROR;
*presult = _fetch_stop_iteration_value();
return PYGEN_RETURN;
}

#endif

typedef struct {
Expand Down Expand Up @@ -667,64 +718,6 @@ static int Parser_initiate_read(Parser* self) {
return result;
}

// TODO: Simplify once support for 3.8 and 3.9 is dropped

typedef enum {
AR_COMPLETE = 0,
AR_ERROR = -1,
AR_YIELD = 1,
} AdvanceReadResult;

// #if PY_VERSION_HEX < 0x030A0000
#if 1

static PyObject* PyErr_FetchStopIterationValue(void) {
PyObject* exc_type;
PyObject* exc_value;
PyObject* exc_traceback;
PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);

assert(exc_type);
assert(PyErr_ExceptionMatches(PyExc_StopIteration));

PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback);
assert(PyObject_TypeCheck(exc_value, (PyTypeObject*)PyExc_StopIteration));

PyErr_Clear();

PyObject* value = ((PyStopIterationObject*)exc_value)->value;
Py_INCREF(value);
Py_XDECREF(exc_type);
Py_XDECREF(exc_value);
Py_XDECREF(exc_traceback);
return value;
}

static inline AdvanceReadResult Parser_advance_read(Parser* self, PyObject** str_or_yield) {
*str_or_yield = (Py_TYPE(self->current_read)->tp_iternext)(self->current_read);
if (*str_or_yield) return AR_YIELD;
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) return AR_ERROR;
*str_or_yield = PyErr_FetchStopIterationValue();
return AR_COMPLETE;
}

#else

static inline AdvanceReadResult Parser_advance_read(Parser* self, PyObject** str_or_yield) {
switch (PyIter_Send(self->current_read, Py_None, str_or_yield)) {
case PYGEN_RETURN:
return AR_COMPLETE;
case PYGEN_ERROR:
return AR_ERROR;
case PYGEN_NEXT:
return AR_YIELD;
default:
Py_UNREACHABLE();
}
}

#endif

static int Parser_copy_to_buffer(Parser* self, PyObject* unicode) {
int result = 1;

Expand Down Expand Up @@ -778,12 +771,12 @@ static PyObject* Parser_next(Parser* self) {
// Await on the pending read
if (self->current_read) {
PyObject* read_str;
switch (Parser_advance_read(self, &read_str)) {
case AR_COMPLETE:
switch (PyIter_Send(self->current_read, Py_None, &read_str)) {
case PYGEN_RETURN:
break;
case AR_ERROR:
case PYGEN_ERROR:
return NULL;
case AR_YIELD:
case PYGEN_NEXT:
return read_str;
}

Expand Down

0 comments on commit 0f924a4

Please sign in to comment.