# iter.rs - source
Source of the Rust file `/home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/pyo3-0.13.2/src/class/iter.rs`.
Keywords: rust, rustlang, rust-lang

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120

    // Copyright (c) 2017-present PyO3 Project and Contributors
    //! Python Iterator Interface.
    //! Trait and support implementation for implementing iterators

    use crate::callback::IntoPyCallbackOutput;
    use crate::derive_utils::TryFromPyCell;
    use crate::err::PyResult;
    use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, Python};

    /// Python Iterator Interface.
    ///
    /// Check [CPython doc](https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_iter)
    /// for more.
    ///
    /// # Example
    /// The following example shows how to implement a simple Python iterator in Rust which yields
    /// the integers 1 to 5, before raising `StopIteration("Ended")`.
    ///
    /// ```rust
    /// use pyo3::prelude::*;
    /// use pyo3::PyIterProtocol;
    /// use pyo3::class::iter::IterNextOutput;
    ///
    /// #[pyclass]
    /// struct Iter {
    ///     count: usize
    /// }
    ///
    /// #[pyproto]
    /// impl PyIterProtocol for Iter {
    ///     fn __next__(mut slf: PyRefMut<Self>) -> IterNextOutput<usize, &'static str> {
    ///         if slf.count < 5 {
    ///             slf.count += 1;
    ///             IterNextOutput::Yield(slf.count)
    ///         } else {
    ///             IterNextOutput::Return("Ended")
    ///         }
    ///     }
    /// }
    ///
    /// # let gil = Python::acquire_gil();
    /// # let py = gil.python();
    /// # let inst = Py::new(py, Iter { count: 0 }).unwrap();
    /// # pyo3::py_run!(py, inst, "assert next(inst) == 1");
    /// # // test of StopIteration is done in examples/rustapi_module/pyclass_iter.rs
    /// ```
    #[allow(unused_variables)]
    pub trait PyIterProtocol<'p>: PyClass {
        fn __iter__(slf: Self::Receiver) -> Self::Result
        where
            Self: PyIterIterProtocol<'p>,
        {
            unimplemented!()
        }

        fn __next__(slf: Self::Receiver) -> Self::Result
        where
            Self: PyIterNextProtocol<'p>,
        {
            unimplemented!()
        }
    }

    pub trait PyIterIterProtocol<'p>: PyIterProtocol<'p> {
        type Receiver: TryFromPyCell<'p, Self>;
        type Result: IntoPyCallbackOutput<PyObject>;
    }

    pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> {
        type Receiver: TryFromPyCell<'p, Self>;
        type Result: IntoPyCallbackOutput<PyIterNextOutput>;
    }

    py_unarys_func!(iter, PyIterIterProtocol, Self::__iter__);
    py_unarys_func!(iternext, PyIterNextProtocol, Self::__next__);

    /// Output of `__next__` which can either `yield` the next value in the iteration, or
    /// `return` a value to raise `StopIteration` in Python.
    ///
    /// See [`PyIterProtocol`](trait.PyIterProtocol.html) for an example.
    pub enum IterNextOutput<T, U> {
        Yield(T),
        Return(U),
    }

    pub type PyIterNextOutput = IterNextOutput<PyObject, PyObject>;

    impl IntoPyCallbackOutput<*mut ffi::PyObject> for PyIterNextOutput {
        fn convert(self, _py: Python) -> PyResult<*mut ffi::PyObject> {
            match self {
                IterNextOutput::Yield(o) => Ok(o.into_ptr()),
                IterNextOutput::Return(opt) => Err(crate::exceptions::PyStopIteration::new_err((opt,))),
            }
        }
    }

    impl<T, U> IntoPyCallbackOutput<PyIterNextOutput> for IterNextOutput<T, U>
    where
        T: IntoPy<PyObject>,
        U: IntoPy<PyObject>,
    {
        fn convert(self, py: Python) -> PyResult<PyIterNextOutput> {
            match self {
                IterNextOutput::Yield(o) => Ok(IterNextOutput::Yield(o.into_py(py))),
                IterNextOutput::Return(o) => Ok(IterNextOutput::Return(o.into_py(py))),
            }
        }
    }

    impl<T> IntoPyCallbackOutput<PyIterNextOutput> for Option<T>
    where
        T: IntoPy<PyObject>,
    {
        fn convert(self, py: Python) -> PyResult<PyIterNextOutput> {
            match self {
                Some(o) => Ok(PyIterNextOutput::Yield(o.into_py(py))),
                None => Ok(PyIterNextOutput::Return(py.None())),
            }
        }
    }