Packages

Lazy, external iterators for Elixir.

Current section

Files

Jump to
iterex lib iter iterable while_chunker.ex
Raw

lib/iter/iterable/while_chunker.ex

defmodule Iter.Iterable.WhileChunker do
defstruct iterable: nil, acc: nil, chunk_fun: nil, after_fun: nil
@moduledoc """
An iterable that chunks based on a chunk function.
"""
alias Iter.{Impl, IntoIterable, Iterable}
@type acc :: any
@type chunk :: any
@type t :: %__MODULE__{
iterable: Iterable.t(),
acc: nil,
chunk_fun:
(Iterable.element(), acc -> {:cont, chunk, acc} | {:cont, acc} | {:halt, acc}),
after_fun: (acc -> {:cont, chunk, acc} | {:cont, acc})
}
@doc """
Creates an iterable that chunks based on a chunk function.
"""
@spec new(
Iterable.t(),
any,
(Iterable.element(), acc -> {:cont, chunk, acc} | {:cont, acc} | {:halt, acc}),
(acc -> {:cont, chunk, acc} | {:cont, acc})
) :: t
def new(iterable, acc, chunk_fun, after_fun)
when is_function(chunk_fun, 2) and is_function(after_fun, 1),
do: %__MODULE__{iterable: iterable, acc: acc, chunk_fun: chunk_fun, after_fun: after_fun}
defimpl Iterable do
use Impl
@doc false
@impl true
def next(chunk_while) do
case Iterable.next(chunk_while.iterable) do
{:ok, element, iterable} -> handle_chunk_fun(chunk_while, element, iterable)
:done -> handle_after_fun(chunk_while, chunk_while.acc)
end
end
defp handle_chunk_fun(chunk_while, element, iterable) do
case chunk_while.chunk_fun.(element, chunk_while.acc) do
{:cont, chunk, acc} -> {:ok, chunk, %{chunk_while | acc: acc, iterable: iterable}}
{:cont, acc} -> next(%{chunk_while | acc: acc, iterable: iterable})
{:halt, acc} -> handle_after_fun(chunk_while, acc)
end
end
defp handle_after_fun(chunk_while, acc) do
case chunk_while.after_fun.(acc) do
{:cont, chunk, _acc} -> {:ok, chunk, Iterable.Empty.new()}
{:cont, _acc} -> :done
end
end
end
defimpl IntoIterable do
@doc false
def into_iterable(self), do: self
end
end