Current section
Files
Jump to
Current section
Files
lib/iter/iterable/zipper.ex
defmodule Iter.Iterable.Zipper do
defstruct iterables: nil, zipper: nil
@moduledoc """
An iterable which returns the elements of two iterables as tuple pairs.
"""
alias Iter.{Impl, IntoIterable, Iterable}
@type t :: %__MODULE__{
iterables: [Iterable.t()],
zipper: ([Iterable.element()] -> any)
}
@doc """
Create a new zip out of two iterables.
"""
@spec new(Iterable.t(), ([Iterable.element()] -> any)) :: Iterable.t()
def new(iterables, zipper) when is_function(zipper, 1),
do: %__MODULE__{iterables: Iterable.to_list(iterables), zipper: zipper}
defimpl Iterable do
use Impl
@doc false
@impl true
def next(zipper) do
with {:ok, element, iterables} <- get_next(zipper.iterables, [], [], zipper.zipper) do
{:ok, element, %{zipper | iterables: iterables}}
end
end
defp get_next([], iterables, elements, zipper) do
elements =
elements
|> :lists.reverse()
|> then(zipper)
iterables =
iterables
|> :lists.reverse()
{:ok, elements, iterables}
end
defp get_next([head | tail], iterables, elements, zipper) do
case Iterable.next(head) do
{:ok, element, head} -> get_next(tail, [head | iterables], [element | elements], zipper)
:done -> :done
end
end
end
defimpl IntoIterable do
@doc false
def into_iterable(self), do: self
end
end