Current section
Files
Jump to
Current section
Files
lib/iter/iterable/flat_mapper.ex
defmodule Iter.Iterable.FlatMapper do
defstruct iterable: nil, mapper: nil
@moduledoc """
An iterable which works like `map/2` but flattens nested iterables.
"""
alias Iter.{Impl, IntoIterable, Iterable}
@type mapper :: (Iterable.t() -> Iterable.t() | Iterable.element())
@type t :: %__MODULE__{iterable: Iterable.t(), mapper: mapper}
@doc """
Creates an iterable which works like `map/2` but flattens nested iterables.
"""
@spec new(Iterable.t(), mapper) :: t
def new(iterable, mapper) when is_function(mapper, 1),
do: %__MODULE__{iterable: iterable, mapper: mapper}
defimpl Iterable do
use Impl
@doc false
@impl true
def next(flat_map) do
with {:ok, element, iterable} <- Iterable.next(flat_map.iterable) do
maybe_wrap(flat_map.mapper.(element), %{flat_map | iterable: iterable})
end
end
defp maybe_wrap(element, tail) do
head = IntoIterable.into_iterable(element)
concat = Iterable.Concatenator.new([head, tail])
Iterable.next(concat)
rescue
Protocol.UndefinedError -> {:ok, element, tail}
end
end
defimpl IntoIterable do
@doc false
def into_iterable(self), do: self
end
end