Coverage Report

Created: 2026-10-17 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Objects/iterobject.c
Line
Count
Source
1
/* Iterator objects */
2
3
#include "Python.h"
4
#include "pycore_abstract.h"      // _PyObject_HasLen()
5
#include "pycore_call.h"          // _PyObject_CallNoArgs()
6
#include "pycore_ceval.h"         // _PyEval_GetBuiltin()
7
#include "pycore_genobject.h"     // _PyCoro_GetAwaitableIter()
8
#include "pycore_iterobject.h"    // _PyCallIter_NewEx()
9
#include "pycore_object.h"        // _PyObject_GC_TRACK()
10
#include "pycore_pyatomic_ft_wrappers.h"  // FT_ATOMIC_LOAD_SSIZE_RELAXED()
11
#include "pycore_pyerrors.h"      // _PyErr_FormatFromCause()
12
#include "pycore_pystate.h"       // _PyThreadState_GET()
13
14
15
typedef struct {
16
    PyObject_HEAD
17
    Py_ssize_t it_index;  /* -1 when iterator is exhausted */
18
    PyObject *it_seq; /* Set to NULL when iterator is exhausted
19
                         (in the default build) */
20
} seqiterobject;
21
22
PyObject *
23
PySeqIter_New(PyObject *seq)
24
1.89M
{
25
1.89M
    seqiterobject *it;
26
27
1.89M
    if (!PySequence_Check(seq)) {
28
0
        PyErr_BadInternalCall();
29
0
        return NULL;
30
0
    }
31
1.89M
    it = PyObject_GC_New(seqiterobject, &PySeqIter_Type);
32
1.89M
    if (it == NULL)
33
0
        return NULL;
34
1.89M
    it->it_index = 0;
35
1.89M
    it->it_seq = Py_NewRef(seq);
36
1.89M
    _PyObject_GC_TRACK(it);
37
1.89M
    return (PyObject *)it;
38
1.89M
}
39
40
static void
41
iter_dealloc(PyObject *op)
42
1.89M
{
43
1.89M
    seqiterobject *it = (seqiterobject*)op;
44
1.89M
    _PyObject_GC_UNTRACK(it);
45
1.89M
    Py_XDECREF(it->it_seq);
46
1.89M
    PyObject_GC_Del(it);
47
1.89M
}
48
49
static int
50
iter_traverse(PyObject *op, visitproc visit, void *arg)
51
1.32k
{
52
1.32k
    seqiterobject *it = (seqiterobject*)op;
53
1.32k
    Py_VISIT(it->it_seq);
54
1.32k
    return 0;
55
1.32k
}
56
57
static PyObject *
58
iter_iternext(PyObject *iterator)
59
9.30M
{
60
9.30M
    seqiterobject *it;
61
9.30M
    PyObject *seq;
62
9.30M
    PyObject *result;
63
64
9.30M
    assert(PySeqIter_Check(iterator));
65
9.30M
    it = (seqiterobject *)iterator;
66
9.30M
    Py_ssize_t index = FT_ATOMIC_LOAD_SSIZE_RELAXED(it->it_index);
67
9.30M
    if (index < 0)
68
0
        return NULL;
69
9.30M
    seq = it->it_seq;
70
9.30M
#ifndef Py_GIL_DISABLED
71
9.30M
    if (seq == NULL)
72
0
        return NULL;
73
9.30M
#endif
74
9.30M
    if (index == PY_SSIZE_T_MAX) {
75
0
        PyErr_SetString(PyExc_OverflowError,
76
0
                        "iter index too large");
77
0
        return NULL;
78
0
    }
79
80
9.30M
    result = PySequence_GetItem(seq, index);
81
9.30M
    if (result != NULL) {
82
        /* PySequence_GetItem() can exhaust the iterator re-entrantly.
83
         * Preserve the exhaustion sentinel if it is observed.  Concurrent
84
         * exhaustion can still race with the store, but remains memory-safe
85
         * because the sequence stays alive. */
86
7.40M
        if (FT_ATOMIC_LOAD_SSIZE_RELAXED(it->it_index) >= 0) {
87
7.40M
            FT_ATOMIC_STORE_SSIZE_RELAXED(it->it_index, index + 1);
88
7.40M
        }
89
7.40M
        return result;
90
7.40M
    }
91
1.89M
    if (PyErr_ExceptionMatches(PyExc_IndexError) ||
92
0
        PyErr_ExceptionMatches(PyExc_StopIteration))
93
1.89M
    {
94
        /* Mark the iterator exhausted before anything that can run
95
         * arbitrary code. */
96
1.89M
        FT_ATOMIC_STORE_SSIZE_RELAXED(it->it_index, -1);
97
1.89M
#ifndef Py_GIL_DISABLED
98
1.89M
        Py_CLEAR(it->it_seq);
99
1.89M
#endif
100
1.89M
        PyErr_Clear();
101
1.89M
    }
102
1.89M
    return NULL;
103
9.30M
}
104
105
static PyObject *
106
iter_len(PyObject *op, PyObject *Py_UNUSED(ignored))
107
7.86k
{
108
7.86k
    seqiterobject *it = (seqiterobject*)op;
109
7.86k
    Py_ssize_t seqsize, len;
110
111
7.86k
    Py_ssize_t index = FT_ATOMIC_LOAD_SSIZE_RELAXED(it->it_index);
112
7.86k
    if (index >= 0 && it->it_seq != NULL) {
113
7.86k
        if (_PyObject_HasLen(it->it_seq)) {
114
7.86k
            seqsize = PySequence_Size(it->it_seq);
115
7.86k
            if (seqsize == -1)
116
0
                return NULL;
117
7.86k
        }
118
0
        else {
119
0
            Py_RETURN_NOTIMPLEMENTED;
120
0
        }
121
7.86k
        len = seqsize - index;
122
7.86k
        if (len >= 0)
123
7.86k
            return PyLong_FromSsize_t(len);
124
7.86k
    }
125
0
    return PyLong_FromLong(0);
126
7.86k
}
127
128
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
129
130
static PyObject *
131
iter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
132
0
{
133
0
    seqiterobject *it = (seqiterobject*)op;
134
0
    PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter));
135
136
    /* _PyEval_GetBuiltin can invoke arbitrary code,
137
     * call must be before access of iterator pointers.
138
     * see issue #101765 */
139
140
0
    Py_ssize_t index = FT_ATOMIC_LOAD_SSIZE_RELAXED(it->it_index);
141
0
    if (index >= 0 && it->it_seq != NULL)
142
0
        return Py_BuildValue("N(O)n", iter, it->it_seq, index);
143
0
    else
144
0
        return Py_BuildValue("N(())", iter);
145
0
}
146
147
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
148
149
static PyObject *
150
iter_setstate(PyObject *op, PyObject *state)
151
0
{
152
0
    seqiterobject *it = (seqiterobject*)op;
153
0
    Py_ssize_t index = PyLong_AsSsize_t(state);
154
0
    if (index == -1 && PyErr_Occurred())
155
0
        return NULL;
156
0
    if (index < 0)
157
0
        index = 0;
158
0
    if (it->it_seq && FT_ATOMIC_LOAD_SSIZE_RELAXED(it->it_index) >= 0) {
159
0
        FT_ATOMIC_STORE_SSIZE_RELAXED(it->it_index, index);
160
0
    }
161
0
    Py_RETURN_NONE;
162
0
}
163
164
PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
165
166
static PyMethodDef seqiter_methods[] = {
167
    {"__length_hint__", iter_len, METH_NOARGS, length_hint_doc},
168
    {"__reduce__", iter_reduce, METH_NOARGS, reduce_doc},
169
    {"__setstate__", iter_setstate, METH_O, setstate_doc},
170
    {NULL,              NULL}           /* sentinel */
171
};
172
173
PyTypeObject PySeqIter_Type = {
174
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
175
    "iterator",                                 /* tp_name */
176
    sizeof(seqiterobject),                      /* tp_basicsize */
177
    0,                                          /* tp_itemsize */
178
    /* methods */
179
    iter_dealloc,                               /* tp_dealloc */
180
    0,                                          /* tp_vectorcall_offset */
181
    0,                                          /* tp_getattr */
182
    0,                                          /* tp_setattr */
183
    0,                                          /* tp_as_async */
184
    0,                                          /* tp_repr */
185
    0,                                          /* tp_as_number */
186
    0,                                          /* tp_as_sequence */
187
    0,                                          /* tp_as_mapping */
188
    0,                                          /* tp_hash */
189
    0,                                          /* tp_call */
190
    0,                                          /* tp_str */
191
    PyObject_GenericGetAttr,                    /* tp_getattro */
192
    0,                                          /* tp_setattro */
193
    0,                                          /* tp_as_buffer */
194
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
195
    0,                                          /* tp_doc */
196
    iter_traverse,                              /* tp_traverse */
197
    0,                                          /* tp_clear */
198
    0,                                          /* tp_richcompare */
199
    0,                                          /* tp_weaklistoffset */
200
    PyObject_SelfIter,                          /* tp_iter */
201
    iter_iternext,                              /* tp_iternext */
202
    seqiter_methods,                            /* tp_methods */
203
    0,                                          /* tp_members */
204
};
205
206
/* -------------------------------------- */
207
208
typedef struct {
209
    PyObject_HEAD
210
    PyObject *it_callable;  /* set to NULL when the iterator is exhausted */
211
    PyObject *it_sentinel;  /* can be NULL, and is when exhausted */
212
    PyObject *it_stop_exc;  /* never NULL */
213
} calliterobject;
214
215
PyObject *
216
_PyCallIter_NewEx(PyObject *callable, PyObject *sentinel, PyObject *stop_exc)
217
328k
{
218
328k
    calliterobject *it;
219
328k
    if (stop_exc == NULL) {
220
328k
        stop_exc = PyExc_StopIteration;
221
328k
    }
222
0
    else if (_PyEval_CheckExceptTypeValid(_PyThreadState_GET(), stop_exc) < 0) {
223
0
        return NULL;
224
0
    }
225
328k
    it = PyObject_GC_New(calliterobject, &PyCallIter_Type);
226
328k
    if (it == NULL)
227
0
        return NULL;
228
328k
    it->it_callable = Py_NewRef(callable);
229
328k
    it->it_sentinel = Py_XNewRef(sentinel);
230
328k
    it->it_stop_exc = Py_NewRef(stop_exc);
231
328k
    _PyObject_GC_TRACK(it);
232
328k
    return (PyObject *)it;
233
328k
}
234
235
PyObject *
236
PyCallIter_New(PyObject *callable, PyObject *sentinel)
237
328k
{
238
328k
    return _PyCallIter_NewEx(callable, sentinel, NULL);
239
328k
}
240
241
static void
242
calliter_exhaust(calliterobject *it)
243
328k
{
244
328k
    Py_CLEAR(it->it_callable);
245
328k
    Py_CLEAR(it->it_sentinel);
246
328k
}
247
248
static void
249
calliter_dealloc(PyObject *op)
250
328k
{
251
328k
    calliterobject *it = (calliterobject*)op;
252
328k
    _PyObject_GC_UNTRACK(it);
253
328k
    Py_XDECREF(it->it_callable);
254
328k
    Py_XDECREF(it->it_sentinel);
255
328k
    Py_XDECREF(it->it_stop_exc);
256
328k
    PyObject_GC_Del(it);
257
328k
}
258
259
static int
260
calliter_traverse(PyObject *op, visitproc visit, void *arg)
261
1.03k
{
262
1.03k
    calliterobject *it = (calliterobject*)op;
263
1.03k
    Py_VISIT(it->it_callable);
264
1.03k
    Py_VISIT(it->it_sentinel);
265
1.03k
    Py_VISIT(it->it_stop_exc);
266
1.03k
    return 0;
267
1.03k
}
268
269
static PyObject *
270
calliter_iternext(PyObject *op)
271
3.15M
{
272
3.15M
    calliterobject *it = (calliterobject*)op;
273
3.15M
    PyObject *result;
274
275
3.15M
    if (it->it_callable == NULL) {
276
0
        return NULL;
277
0
    }
278
279
3.15M
    result = _PyObject_CallNoArgs(it->it_callable);
280
    /* The call can exhaust the iterator re-entrantly. */
281
3.15M
    if (result != NULL && it->it_callable != NULL) {
282
3.15M
        if (it->it_sentinel == NULL) {
283
0
            return result; /* Common case, fast path */
284
0
        }
285
3.15M
        int ok = PyObject_RichCompareBool(it->it_sentinel, result, Py_EQ);
286
3.15M
        if (ok == 0) {
287
2.82M
            return result; /* Common case, fast path */
288
2.82M
        }
289
290
328k
        if (ok > 0) {
291
328k
            calliter_exhaust(it);
292
328k
        }
293
328k
    }
294
4
    else if (PyErr_ExceptionMatches(it->it_stop_exc)) {
295
4
        PyErr_Clear();
296
4
        calliter_exhaust(it);
297
4
    }
298
0
    else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
299
        /* It would be mistaken for the end of the iteration (see PEP 479). */
300
0
        _PyErr_FormatFromCause(PyExc_RuntimeError,
301
0
                               "callable raised StopIteration");
302
0
    }
303
328k
    Py_XDECREF(result);
304
328k
    return NULL;
305
3.15M
}
306
307
static PyObject *
308
calliter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
309
0
{
310
0
    calliterobject *it = (calliterobject*)op;
311
0
    PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter));
312
313
    /* _PyEval_GetBuiltin can invoke arbitrary code,
314
     * call must be before access of iterator pointers.
315
     * see issue #101765 */
316
317
0
    if (it->it_callable == NULL) {
318
0
        return Py_BuildValue("N(())", iter);
319
0
    }
320
    /* Only the sentinel can be passed as an argument of iter(), so other
321
       attributes are restored from the state (see calliter_setstate()). */
322
0
    if (it->it_sentinel == NULL) {
323
0
        return Py_BuildValue("N(OO)(()O)", iter, it->it_callable, Py_None,
324
0
                             it->it_stop_exc);
325
0
    }
326
0
    else if (it->it_stop_exc == PyExc_StopIteration) {
327
0
        return Py_BuildValue("N(OO)", iter, it->it_callable, it->it_sentinel);
328
0
    }
329
0
    else {
330
0
        return Py_BuildValue("N(OO)((O)O)", iter, it->it_callable, Py_None,
331
0
                             it->it_sentinel, it->it_stop_exc);
332
0
    }
333
0
}
334
335
static PyObject *
336
calliter_setstate(PyObject *op, PyObject *state)
337
0
{
338
0
    calliterobject *it = (calliterobject*)op;
339
0
    PyObject *sentinel, *stop_exc;
340
341
0
    if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) != 2) {
342
0
        goto error;
343
0
    }
344
0
    sentinel = PyTuple_GET_ITEM(state, 0);
345
0
    stop_exc = PyTuple_GET_ITEM(state, 1);
346
0
    if (!PyTuple_Check(sentinel) || PyTuple_GET_SIZE(sentinel) > 1) {
347
0
        goto error;
348
0
    }
349
0
    if (_PyEval_CheckExceptTypeValid(_PyThreadState_GET(), stop_exc) < 0) {
350
0
        return NULL;
351
0
    }
352
0
    if (it->it_callable != NULL) {
353
0
        Py_XSETREF(it->it_sentinel,
354
0
                   PyTuple_GET_SIZE(sentinel) ?
355
0
                   Py_NewRef(PyTuple_GET_ITEM(sentinel, 0)) : NULL);
356
0
        Py_SETREF(it->it_stop_exc, Py_NewRef(stop_exc));
357
0
    }
358
0
    Py_RETURN_NONE;
359
360
0
error:
361
0
    PyErr_SetString(PyExc_TypeError, "invalid state for callable_iterator");
362
0
    return NULL;
363
0
}
364
365
static PyMethodDef calliter_methods[] = {
366
    {"__reduce__", calliter_reduce, METH_NOARGS, reduce_doc},
367
    {"__setstate__", calliter_setstate, METH_O, setstate_doc},
368
    {NULL,              NULL}           /* sentinel */
369
};
370
371
PyTypeObject PyCallIter_Type = {
372
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
373
    "callable_iterator",                        /* tp_name */
374
    sizeof(calliterobject),                     /* tp_basicsize */
375
    0,                                          /* tp_itemsize */
376
    /* methods */
377
    calliter_dealloc,                           /* tp_dealloc */
378
    0,                                          /* tp_vectorcall_offset */
379
    0,                                          /* tp_getattr */
380
    0,                                          /* tp_setattr */
381
    0,                                          /* tp_as_async */
382
    0,                                          /* tp_repr */
383
    0,                                          /* tp_as_number */
384
    0,                                          /* tp_as_sequence */
385
    0,                                          /* tp_as_mapping */
386
    0,                                          /* tp_hash */
387
    0,                                          /* tp_call */
388
    0,                                          /* tp_str */
389
    PyObject_GenericGetAttr,                    /* tp_getattro */
390
    0,                                          /* tp_setattro */
391
    0,                                          /* tp_as_buffer */
392
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
393
    0,                                          /* tp_doc */
394
    calliter_traverse,                          /* tp_traverse */
395
    0,                                          /* tp_clear */
396
    0,                                          /* tp_richcompare */
397
    0,                                          /* tp_weaklistoffset */
398
    PyObject_SelfIter,                          /* tp_iter */
399
    calliter_iternext,                          /* tp_iternext */
400
    calliter_methods,                           /* tp_methods */
401
};
402
403
404
/* -------------------------------------- */
405
406
static PyObject *
407
awaitable_getiter(PyObject *owner, PyObject *wrapped)
408
0
{
409
0
    assert(wrapped != NULL);
410
0
    PyObject *awaitable = _PyCoro_GetAwaitableIter(wrapped);
411
0
    if (awaitable == NULL) {
412
0
        return NULL;
413
0
    }
414
0
    if (Py_TYPE(awaitable)->tp_iternext == NULL) {
415
        /* _PyCoro_GetAwaitableIter returns a Coroutine, a Generator,
416
         * or an iterator. Of these, only coroutines lack tp_iternext.
417
         */
418
0
        assert(PyCoro_CheckExact(awaitable));
419
0
        unaryfunc getter = Py_TYPE(awaitable)->tp_as_async->am_await;
420
0
        PyObject *new_awaitable = getter(awaitable);
421
0
        if (new_awaitable == NULL) {
422
0
            Py_DECREF(awaitable);
423
0
            return NULL;
424
0
        }
425
0
        Py_SETREF(awaitable, new_awaitable);
426
0
        if (!PyIter_Check(awaitable)) {
427
0
            PyErr_Format(PyExc_TypeError,
428
0
                         "%T.__await__() must return an iterable, not %T",
429
0
                         owner, awaitable);
430
0
            Py_DECREF(awaitable);
431
0
            return NULL;
432
0
        }
433
0
    }
434
0
    return awaitable;
435
0
}
436
437
438
PyDoc_STRVAR(send_doc,
439
"send(arg) -> send 'arg' into the wrapped iterator,\n\
440
return next yielded value or raise StopIteration.");
441
442
443
PyDoc_STRVAR(throw_doc,
444
"throw(value)\n\
445
throw(typ[,val[,tb]])\n\
446
\n\
447
raise exception in the wrapped iterator, return next yielded value\n\
448
or raise StopIteration.\n\
449
the (type, val, tb) signature is deprecated, \n\
450
and may be removed in a future version of Python.");
451
452
453
PyDoc_STRVAR(close_doc,
454
"close() -> raise GeneratorExit inside generator.");
455
456
457
/* -------------------------------------- */
458
459
/* The asynchronous counterpart of calliterobject: the callable is called
460
   and its result is awaited for every __anext__(). */
461
462
typedef struct {
463
    PyObject_HEAD
464
    PyObject *it_callable;  /* set to NULL when the iterator is exhausted */
465
    PyObject *it_sentinel;  /* can be NULL, and is when exhausted */
466
    PyObject *it_stop_exc;  /* never NULL */
467
} acalliterobject;
468
469
0
#define acalliterobject_CAST(op)        ((acalliterobject *)(op))
470
471
/* The awaitable returned by acalliter_anext().  The callable is only
472
   called when this object is awaited. */
473
typedef struct {
474
    PyObject_HEAD
475
    PyObject *aw_iterator; /* the iterator which created this object */
476
    PyObject *aw_wrapped;  /* the awaitable returned by the callable */
477
    bool aw_closed;
478
} acallawaitableobject;
479
480
0
#define acallawaitableobject_CAST(op)   ((acallawaitableobject *)(op))
481
482
PyObject *
483
_PyACallIter_New(PyObject *callable, PyObject *sentinel, PyObject *stop_exc)
484
0
{
485
0
    if (stop_exc == NULL) {
486
0
        stop_exc = PyExc_StopAsyncIteration;
487
0
    }
488
0
    else if (_PyEval_CheckExceptTypeValid(_PyThreadState_GET(), stop_exc) < 0) {
489
0
        return NULL;
490
0
    }
491
0
    acalliterobject *it = PyObject_GC_New(acalliterobject, &_PyACallIter_Type);
492
0
    if (it == NULL) {
493
0
        return NULL;
494
0
    }
495
0
    it->it_callable = Py_NewRef(callable);
496
0
    it->it_sentinel = Py_XNewRef(sentinel);
497
0
    it->it_stop_exc = Py_NewRef(stop_exc);
498
0
    _PyObject_GC_TRACK(it);
499
0
    return (PyObject *)it;
500
0
}
501
502
static void
503
acalliter_exhaust(acalliterobject *it)
504
0
{
505
0
    Py_CLEAR(it->it_callable);
506
0
    Py_CLEAR(it->it_sentinel);
507
0
}
508
509
static void
510
acalliter_dealloc(PyObject *op)
511
0
{
512
0
    acalliterobject *it = acalliterobject_CAST(op);
513
0
    _PyObject_GC_UNTRACK(it);
514
0
    Py_XDECREF(it->it_callable);
515
0
    Py_XDECREF(it->it_sentinel);
516
0
    Py_XDECREF(it->it_stop_exc);
517
0
    PyObject_GC_Del(it);
518
0
}
519
520
static int
521
acalliter_traverse(PyObject *op, visitproc visit, void *arg)
522
0
{
523
0
    acalliterobject *it = acalliterobject_CAST(op);
524
0
    Py_VISIT(it->it_callable);
525
0
    Py_VISIT(it->it_sentinel);
526
0
    Py_VISIT(it->it_stop_exc);
527
0
    return 0;
528
0
}
529
530
static PyObject *acallawaitable_new(PyObject *iterator);
531
532
static PyObject *
533
acalliter_anext(PyObject *op)
534
0
{
535
0
    return acallawaitable_new(op);
536
0
}
537
538
static PyAsyncMethods acalliter_as_async = {
539
    0,                                          /* am_await */
540
    PyObject_SelfIter,                          /* am_aiter */
541
    acalliter_anext,                            /* am_anext */
542
    0,                                          /* am_send  */
543
};
544
545
PyTypeObject _PyACallIter_Type = {
546
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
547
    .tp_name = "async_callable_iterator",
548
    .tp_basicsize = sizeof(acalliterobject),
549
    .tp_dealloc = acalliter_dealloc,
550
    .tp_as_async = &acalliter_as_async,
551
    .tp_getattro = PyObject_GenericGetAttr,
552
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
553
    .tp_traverse = acalliter_traverse,
554
};
555
556
/* -------------------------------------- */
557
558
static PyObject *
559
acallawaitable_new(PyObject *iterator)
560
0
{
561
0
    acallawaitableobject *aw = PyObject_GC_New(
562
0
            acallawaitableobject, &_PyACallIterAwaitable_Type);
563
0
    if (aw == NULL) {
564
0
        return NULL;
565
0
    }
566
0
    aw->aw_iterator = Py_NewRef(iterator);
567
0
    aw->aw_wrapped = NULL;
568
0
    aw->aw_closed = false;
569
0
    _PyObject_GC_TRACK(aw);
570
0
    return (PyObject *)aw;
571
0
}
572
573
static void
574
acallawaitable_dealloc(PyObject *op)
575
0
{
576
0
    acallawaitableobject *aw = acallawaitableobject_CAST(op);
577
0
    _PyObject_GC_UNTRACK(aw);
578
0
    Py_XDECREF(aw->aw_iterator);
579
0
    Py_XDECREF(aw->aw_wrapped);
580
0
    PyObject_GC_Del(aw);
581
0
}
582
583
static int
584
acallawaitable_traverse(PyObject *op, visitproc visit, void *arg)
585
0
{
586
0
    acallawaitableobject *aw = acallawaitableobject_CAST(op);
587
0
    Py_VISIT(aw->aw_iterator);
588
0
    Py_VISIT(aw->aw_wrapped);
589
0
    return 0;
590
0
}
591
592
/* Call the callable.  Return 0 on success, -1 on failure. */
593
static int
594
acallawaitable_start(acallawaitableobject *aw)
595
0
{
596
0
    acalliterobject *it = acalliterobject_CAST(aw->aw_iterator);
597
598
0
    if (aw->aw_closed) {
599
0
        PyErr_SetString(PyExc_RuntimeError,
600
0
                        "cannot reuse already awaited __anext__()");
601
0
        return -1;
602
0
    }
603
0
    if (it->it_callable == NULL) {
604
0
        PyErr_SetNone(PyExc_StopAsyncIteration);
605
0
        return -1;
606
0
    }
607
0
    PyObject *awaitable = _PyObject_CallNoArgs(it->it_callable);
608
0
    if (awaitable == NULL) {
609
0
        if (PyErr_ExceptionMatches(it->it_stop_exc)) {
610
0
            PyErr_Clear();
611
0
            acalliter_exhaust(it);
612
0
            PyErr_SetNone(PyExc_StopAsyncIteration);
613
0
        }
614
0
        else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
615
            /* It would be mistaken for the result of the await (PEP 525). */
616
0
            _PyErr_FormatFromCause(PyExc_RuntimeError,
617
0
                                   "callable raised StopIteration");
618
0
        }
619
0
        else if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
620
            /* It would be mistaken for the end of the iteration (PEP 525). */
621
0
            _PyErr_FormatFromCause(PyExc_RuntimeError,
622
0
                                   "callable raised StopAsyncIteration");
623
0
        }
624
0
        return -1;
625
0
    }
626
0
    aw->aw_wrapped = awaitable;
627
0
    return 0;
628
0
}
629
630
/* Turn the exception raised by the wrapped awaitable into the result of
631
   the await.  Always returns NULL. */
632
static PyObject *
633
acallawaitable_handle_error(acallawaitableobject *aw)
634
0
{
635
0
    acalliterobject *it = acalliterobject_CAST(aw->aw_iterator);
636
637
0
    if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
638
0
        PyObject *value;
639
0
        if (_PyGen_FetchStopIterationValue(&value) < 0) {
640
0
            return NULL;
641
0
        }
642
0
        int ok = 0;
643
0
        if (it->it_sentinel != NULL) {
644
0
            ok = PyObject_RichCompareBool(it->it_sentinel, value, Py_EQ);
645
0
        }
646
0
        if (ok == 0) {
647
0
            (void)_PyGen_SetStopIterationValue(value);
648
0
        }
649
0
        else if (ok > 0) {
650
0
            acalliter_exhaust(it);
651
0
            PyErr_SetNone(PyExc_StopAsyncIteration);
652
0
        }
653
0
        Py_DECREF(value);
654
0
        return NULL;
655
0
    }
656
0
    if (PyErr_ExceptionMatches(it->it_stop_exc)) {
657
0
        PyErr_Clear();
658
0
        acalliter_exhaust(it);
659
0
        PyErr_SetNone(PyExc_StopAsyncIteration);
660
0
    }
661
0
    else if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
662
        /* It would be mistaken for the end of the iteration (see PEP 525). */
663
0
        _PyErr_FormatFromCause(PyExc_RuntimeError,
664
0
                               "callable raised StopAsyncIteration");
665
0
    }
666
0
    return NULL;
667
0
}
668
669
static PyObject *
670
acallawaitable_iternext(PyObject *op)
671
0
{
672
0
    acallawaitableobject *aw = acallawaitableobject_CAST(op);
673
674
0
    if (aw->aw_wrapped == NULL && acallawaitable_start(aw) < 0) {
675
0
        return NULL;
676
0
    }
677
0
    PyObject *awaitable = awaitable_getiter(op, aw->aw_wrapped);
678
0
    if (awaitable == NULL) {
679
0
        return NULL;
680
0
    }
681
0
    PyObject *result = (*Py_TYPE(awaitable)->tp_iternext)(awaitable);
682
0
    Py_DECREF(awaitable);
683
0
    if (result != NULL) {
684
0
        return result;
685
0
    }
686
0
    return acallawaitable_handle_error(aw);
687
0
}
688
689
static PyObject *
690
acallawaitable_proxy(acallawaitableobject *aw, char *meth, PyObject *arg)
691
0
{
692
0
    PyObject *awaitable = awaitable_getiter((PyObject *)aw, aw->aw_wrapped);
693
0
    if (awaitable == NULL) {
694
0
        return NULL;
695
0
    }
696
    // When specified, 'arg' may be a tuple (if coming from a METH_VARARGS
697
    // method) or a single object (if coming from a METH_O method).
698
0
    PyObject *ret = arg == NULL
699
0
        ? PyObject_CallMethod(awaitable, meth, NULL)
700
0
        : PyObject_CallMethod(awaitable, meth, "O", arg);
701
0
    Py_DECREF(awaitable);
702
0
    if (ret != NULL) {
703
0
        return ret;
704
0
    }
705
0
    return acallawaitable_handle_error(aw);
706
0
}
707
708
static PyObject *
709
acallawaitable_send(PyObject *op, PyObject *arg)
710
0
{
711
0
    acallawaitableobject *aw = acallawaitableobject_CAST(op);
712
713
0
    if (aw->aw_wrapped == NULL && acallawaitable_start(aw) < 0) {
714
0
        return NULL;
715
0
    }
716
0
    return acallawaitable_proxy(aw, "send", arg);
717
0
}
718
719
static PyObject *
720
acallawaitable_throw(PyObject *op, PyObject *args)
721
0
{
722
0
    acallawaitableobject *aw = acallawaitableobject_CAST(op);
723
724
0
    if (aw->aw_wrapped == NULL) {
725
        /* Not started, so the exception is raised at the point of the
726
           await, as for a not started coroutine. */
727
0
        PyObject *typ, *val = NULL, *tb = NULL;
728
0
        if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb)) {
729
0
            return NULL;
730
0
        }
731
0
        aw->aw_closed = true;
732
0
        (void)_PyGen_SetException(typ, val, tb);
733
0
        return NULL;
734
0
    }
735
0
    return acallawaitable_proxy(aw, "throw", args);
736
0
}
737
738
static PyObject *
739
acallawaitable_close(PyObject *op, PyObject *Py_UNUSED(dummy))
740
0
{
741
0
    acallawaitableobject *aw = acallawaitableobject_CAST(op);
742
743
0
    if (aw->aw_wrapped == NULL) {
744
        /* Not started, so there is nothing to close. */
745
0
        aw->aw_closed = true;
746
0
        Py_RETURN_NONE;
747
0
    }
748
0
    PyObject *result = acallawaitable_proxy(aw, "close", NULL);
749
    aw->aw_closed = true;
750
0
    return result;
751
0
}
752
753
static PyMethodDef acallawaitable_methods[] = {
754
    {"send", acallawaitable_send, METH_O, send_doc},
755
    {"throw", acallawaitable_throw, METH_VARARGS, throw_doc},
756
    {"close", acallawaitable_close, METH_NOARGS, close_doc},
757
    {NULL, NULL}        /* Sentinel */
758
};
759
760
static PyAsyncMethods acallawaitable_as_async = {
761
    PyObject_SelfIter,                          /* am_await */
762
    0,                                          /* am_aiter */
763
    0,                                          /* am_anext */
764
    0,                                          /* am_send  */
765
};
766
767
PyTypeObject _PyACallIterAwaitable_Type = {
768
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
769
    .tp_name = "async_callable_iterator_awaitable",
770
    .tp_basicsize = sizeof(acallawaitableobject),
771
    .tp_dealloc = acallawaitable_dealloc,
772
    .tp_as_async = &acallawaitable_as_async,
773
    .tp_getattro = PyObject_GenericGetAttr,
774
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
775
    .tp_traverse = acallawaitable_traverse,
776
    .tp_iter = PyObject_SelfIter,
777
    .tp_iternext = acallawaitable_iternext,
778
    .tp_methods = acallawaitable_methods,
779
};