// SPDX-FileCopyrightText: 2026 dcel contributors
//
// SPDX-License-Identifier: MIT OR Apache-2.0

use maplike::Get;

use crate::{Dcel, EdgeId, FaceId, HalfEdge, HalfEdgeId, VertexId};

macro_rules! create_walker_and_iter {
    (
        $(#[$walker_meta:meta])*
        $walker:ident { $($field:ident: $type:ty),* $(,)? },
        $(#[$iter_meta:meta])*
        $iter:ident
    ) => {
        $(#[$walker_meta])*
        pub struct $walker {
            $(pub(crate) $field: $type,)*
        }

        impl $walker {
            /// Convert this walker to a [`Dcel`]-borrowing iterator.
            pub fn iter<'a, VW, HEW, FW, VC, HEC, FC>(
                self,
                dcel: &'a Dcel<VW, HEW, FW, VC, HEC, FC>,
            ) -> $iter<'a, VW, HEW, FW, VC, HEC, FC> {
                $iter { walker: self, dcel }
            }
        }

        $(#[$iter_meta])*
        pub struct $iter<'a, VW, HEW, FW, VC, HEC, FC> {
            walker: $walker,
            dcel: &'a Dcel<VW, HEW, FW, VC, HEC, FC>,
        }

        impl<'a, VW, HEW, FW, VC, HEC, FC> $iter<'a, VW, HEW, FW, VC, HEC, FC> {
            /// Detach the walker from iterator, thus allowing traversal without borrowing
            /// [`Dcel`].
            pub fn walker(self) -> $walker {
                self.walker
            }
        }
    };
}

create_walker_and_iter!(
    /// Walker to circulate over vertices in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateVertexesWithExcludesWalker {
        circulator: CirculateHalfEdgesWithExcludesWalker,
    },
    /// Iterator to circulate over vertices in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateVertexesWithExcludesIter
);

impl CirculateVertexesWithExcludesWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<VertexId> {
        self.circulator
            .next(dcel)
            .map(|half_edge| dcel.source(half_edge))
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculateVertexesWithExcludesIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = VertexId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker to circulate over vertices in backward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateVertexesWithExcludesReverseWalker {
        circulator: CirculateHalfEdgesWithExcludesReverseWalker,
    },
    /// Iterator to circulate over half-edges in backward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateVertexesWithExcludesReverseIter
);

impl CirculateVertexesWithExcludesReverseWalker {
    /// Advance the walker , returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<VertexId> {
        self.circulator
            .next(dcel)
            .map(|half_edge| dcel.source(half_edge))
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculateVertexesWithExcludesReverseIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = VertexId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker over half-spokes of a vertex in forward direction.
    HalfSpokesWalker {
        initial_half_edge: HalfEdgeId,
        curr_half_edge: Option<HalfEdgeId>,
    },
    /// Iterator over half-spokes of a vertex in forward direction. This is
    /// [`HalfSpokesWalker`], together with an immutably borrowed [`Dcel`],
    /// wrapped in an iterator.
    HalfSpokesIter
);

impl HalfSpokesWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<HalfEdgeId> {
        let next_half_edge = dcel.turn(self.curr_half_edge?);

        std::mem::replace(
            &mut self.curr_half_edge,
            (next_half_edge != self.initial_half_edge).then_some(next_half_edge),
        )
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for HalfSpokesIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = HalfEdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker over half-spokes of a vertex in backward direction.
    HalfSpokesReverseWalker {
        initial_half_edge: HalfEdgeId,
        curr_half_edge: Option<HalfEdgeId>,
    },
    /// Iterator over half-spokes of a vertex in backward direction. This is
    /// [`HalfSpokesReverseWalker`], together with an immutably borrowed [`Dcel`],
    /// wrapped in an iterator.
    HalfSpokesReverseIter
);

impl HalfSpokesReverseWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<HalfEdgeId> {
        let next_half_edge = dcel.turn_back(self.curr_half_edge?);

        std::mem::replace(
            &mut self.curr_half_edge,
            (next_half_edge != self.initial_half_edge).then_some(next_half_edge),
        )
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for HalfSpokesReverseIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = HalfEdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker over spokes of a vertex in forward direction.
    SpokesWalker {
        circulator: HalfSpokesWalker,
    },
    /// Iterator over spokes of a vertex in forward direction. This is
    /// [`SpokesWalker`], together with an immutably borrowed [`Dcel`], wrapped in
    /// an iterator.
    SpokesIter
);

impl SpokesWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<EdgeId> {
        self.circulator
            .next(dcel)
            .map(|half_edge| dcel.full_edge(half_edge))
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for SpokesIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = EdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker over spokes of a vertex in backward direction.
    SpokesReverseWalker {
        circulator: HalfSpokesReverseWalker,
    },
    /// Iterator over spokes of a vertex in backward direction. This is
    /// [`SpokesReverseWalker`], together with an immutably borrowed [`Dcel`],
    /// wrapped in an iterator.
    SpokesReverseIter
);

impl SpokesReverseWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<EdgeId> {
        self.circulator
            .next(dcel)
            .map(|half_edge| dcel.full_edge(half_edge))
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for SpokesReverseIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = EdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker over interspokes of a vertex in forward direction.
    InterspokesWalker {
        initial_half_edge: HalfEdgeId,
        curr_half_edge: Option<HalfEdgeId>,
    },
    /// Iterator over interspokes of a vertex in forward direction. This is
    /// [`InterspokesWalker`], together with an immutably borrowed [`Dcel`],
    /// wrapped in an iterator.
    InterspokesIter
);

impl InterspokesWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<HalfEdgeId> {
        let next_half_edge = dcel.turn(self.curr_half_edge?);

        std::mem::replace(
            &mut self.curr_half_edge,
            (next_half_edge != self.initial_half_edge).then_some(next_half_edge),
        )
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for InterspokesIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = FaceId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker
            .next(self.dcel)
            .map(|half_edge| self.dcel.incident_face(half_edge))
    }
}

create_walker_and_iter!(
    /// Walker over interspokes of a circulation in backward direction.
    InterspokesReverseWalker {
        initial_half_edge: HalfEdgeId,
        curr_half_edge: Option<HalfEdgeId>,
    },
    /// Iterator over interspokes of a circulation in backward direction. This is
    /// [`InterspokesReverseWalker`], together with an immutably borrowed
    /// [`Dcel`], wrapped in an iterator.
    InterspokesReverseIter
);

impl InterspokesReverseWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<HalfEdgeId> {
        let next_half_edge = dcel.turn_back(self.curr_half_edge?);

        std::mem::replace(
            &mut self.curr_half_edge,
            (next_half_edge != self.initial_half_edge).then_some(next_half_edge),
        )
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for InterspokesReverseIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = FaceId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker
            .next(self.dcel)
            .map(|half_edge| self.dcel.incident_face(half_edge))
    }
}

create_walker_and_iter!(
    /// Walker to circulate over half-edges in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateHalfEdgesWithExcludesWalker {
        initial_half_edge: HalfEdgeId,
        curr_half_edge: Option<HalfEdgeId>,
        excluded_half_edges: Vec<HalfEdgeId>,
    },
    /// Iterator to circulate over half-edges in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateHalfEdgesWithExcludesIter
);

impl CirculateHalfEdgesWithExcludesWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<HalfEdgeId> {
        let mut candidate_next_half_edge = dcel.next(self.curr_half_edge?);

        while self.excluded_half_edges.contains(&candidate_next_half_edge) {
            candidate_next_half_edge = dcel.turn(candidate_next_half_edge);
        }

        let next_half_edge = candidate_next_half_edge;

        std::mem::replace(
            &mut self.curr_half_edge,
            (next_half_edge != self.initial_half_edge).then_some(next_half_edge),
        )
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculateHalfEdgesWithExcludesIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = HalfEdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker to circulate over half-edges in backward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateHalfEdgesWithExcludesReverseWalker {
        initial_half_edge: HalfEdgeId,
        curr_half_edge: Option<HalfEdgeId>,
        excluded_half_edges: Vec<HalfEdgeId>,
    },
    /// Iterator to circulate over half-edges in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateHalfEdgesWithExcludesReverseIter
);

impl CirculateHalfEdgesWithExcludesReverseWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<HalfEdgeId> {
        let mut candidate_next_half_edge = dcel.prev(self.curr_half_edge?);

        while self.excluded_half_edges.contains(&candidate_next_half_edge) {
            candidate_next_half_edge =
                dcel.twin(dcel.turn_back(dcel.twin(candidate_next_half_edge)));
        }

        let next_half_edge = candidate_next_half_edge;

        std::mem::replace(
            &mut self.curr_half_edge,
            (next_half_edge != self.initial_half_edge).then_some(next_half_edge),
        )
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculateHalfEdgesWithExcludesReverseIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = HalfEdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker to circulate over edges in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateEdgesWithExcludesWalker {
        circulator: CirculateHalfEdgesWithExcludesWalker,
    },
    /// Iterator to circulate over edges in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateEdgesWithExcludesIter
);

impl CirculateEdgesWithExcludesWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<EdgeId> {
        self.circulator
            .next(dcel)
            .map(|half_edge| dcel.full_edge(half_edge))
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculateEdgesWithExcludesIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = EdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker to circulate over edges in backward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateEdgesWithExcludesReverseWalker {
        circulator: CirculateHalfEdgesWithExcludesReverseWalker,
    },
    /// Iterator to circulate over edges in backward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateEdgesWithExcludesReverseIter
);

impl CirculateEdgesWithExcludesReverseWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<EdgeId> {
        self.circulator
            .next(dcel)
            .map(|half_edge| dcel.full_edge(half_edge))
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculateEdgesWithExcludesReverseIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = EdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker over half-spokes of a circulation in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculationHalfSpokesWalker {
        circulator: CirculateHalfEdgesWithExcludesWalker,
        half_spokes_walker: HalfSpokesWalker,
        prev_half_edge: HalfEdgeId,
    },
    /// Iterator over half-spokes of a circulation in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculationHalfSpokesIter
);

impl CirculationHalfSpokesWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<HalfEdgeId> {
        loop {
            while let Some(candidate_half_spoke) = self.half_spokes_walker.next(dcel) {
                if !self
                    .circulator
                    .excluded_half_edges
                    .contains(&candidate_half_spoke)
                    && self.prev_half_edge != candidate_half_spoke
                    && dcel.twin(candidate_half_spoke) != self.prev_half_edge
                    && self.circulator.curr_half_edge.is_none_or(|half_edge| {
                        candidate_half_spoke != half_edge
                            && dcel.twin(candidate_half_spoke) != half_edge
                    })
                {
                    return Some(candidate_half_spoke);
                }
            }

            self.prev_half_edge = self.circulator.next(dcel)?;
            self.half_spokes_walker = dcel.half_spokes(self.circulator.curr_half_edge?).walker();
        }
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculationHalfSpokesIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = HalfEdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker over half-spokes of a circulation in backward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculationHalfSpokesReverseWalker {
        circulator: CirculateHalfEdgesWithExcludesReverseWalker,
        half_spokes_walker: HalfSpokesWalker,
        prev_half_edge: HalfEdgeId,
    },
    /// Iterator over half-spokes of a circulation in backward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculateHalfSpokesReverseIter
);

impl CirculationHalfSpokesReverseWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<HalfEdgeId> {
        loop {
            while let Some(candidate_half_spoke) = self.half_spokes_walker.next(dcel) {
                if !self
                    .circulator
                    .excluded_half_edges
                    .contains(&candidate_half_spoke)
                    && self.prev_half_edge != candidate_half_spoke
                    && dcel.twin(candidate_half_spoke) != self.prev_half_edge
                    && self.circulator.curr_half_edge.is_none_or(|half_edge| {
                        candidate_half_spoke != half_edge
                            && dcel.twin(candidate_half_spoke) != half_edge
                    })
                {
                    return Some(candidate_half_spoke);
                }
            }

            self.prev_half_edge = self.circulator.next(dcel)?;
            self.half_spokes_walker = dcel.half_spokes(self.circulator.curr_half_edge?).walker();
        }
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculateHalfSpokesReverseIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = HalfEdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker over spokes of a circulation in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculationSpokesWalker {
        circulator: CirculationHalfSpokesWalker,
    },
    /// Iterator over spokes of a circulation in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculationSpokesIter
);

impl CirculationSpokesWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<EdgeId> {
        self.circulator
            .next(dcel)
            .map(|half_spoke| dcel.full_edge(half_spoke))
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculationSpokesIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = EdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker over spokes of a circulation in reverse direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculationSpokesReverseWalker {
        circulator: CirculationHalfSpokesReverseWalker,
    },
    /// Iterator over spokes of a circulation in reverse direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculationSpokesReverseIter
);

impl CirculationSpokesReverseWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<EdgeId> {
        self.circulator
            .next(dcel)
            .map(|half_spoke| dcel.full_edge(half_spoke))
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculationSpokesReverseIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = EdgeId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker over interspokes of a circulation in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculationInterspokesWalker {
        circulator: CirculationHalfSpokesWalker,
    },
    /// Iterator over interspokes of a circulation in forward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculationInterspokesIter
);

impl CirculationInterspokesWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<FaceId> {
        self.circulator
            .next(dcel)
            .map(|half_spoke| dcel.incident_face(half_spoke))
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculationInterspokesIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = FaceId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}

create_walker_and_iter!(
    /// Walker over interspokes of a circulation in backward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculationInterspokesReverseWalker {
        circulator: CirculationHalfSpokesReverseWalker,
    },
    /// Iterator over interspokes of a circulation in backward direction.
    ///
    /// Provided half-edges are excluded from traversal.
    CirculationInterspokesReverseIter
);

impl CirculationInterspokesReverseWalker {
    /// Advance the walker, returning the next value, or `None` when walk is
    /// finished.
    #[inline]
    pub fn next<VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC>(
        &mut self,
        dcel: &Dcel<VW, HEW, FW, VC, HEC, FC>,
    ) -> Option<FaceId> {
        self.circulator
            .next(dcel)
            .map(|half_spoke| dcel.incident_face(half_spoke))
    }
}

impl<'a, VW, HEW, FW, VC, HEC: Get<usize, Value = HalfEdge<HEW>>, FC> Iterator
    for CirculationInterspokesReverseIter<'a, VW, HEW, FW, VC, HEC, FC>
{
    type Item = FaceId;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.next(self.dcel)
    }
}
