Files
geef/lib/geef/tree.ex
2015-07-31 21:49:52 +02:00

108 lines
2.5 KiB
Elixir

require Record
defmodule Geef.TreeEntry do
defstruct mode: nil, type: nil, id: nil, name: nil
end
defmodule Geef.Tree do
alias Geef.Object
alias Geef.TreeEntry
@type t :: Object[type: :tree]
def lookup(repo, id) do
Object.lookup(repo, id, :tree)
end
defp maybe_entry({:ok, mode, type, id, name}) do
{:ok, %TreeEntry{mode: mode, type: type, id: id, name: name}}
end
defp maybe_entry(error = {:error, _}), do: error
def get(%Object{type: :tree, handle: handle}, path) do
:geef_nif.tree_bypath(handle, path) |> maybe_entry
end
def nth(%Object{type: :tree, handle: handle}, nth) do
:geef_nif.tree_nth(handle, nth) |> maybe_entry
end
def count(%Object{type: :tree, handle: handle}) do
:geef_nif.tree_count(handle)
end
end
defimpl Access, for: Geef.Object do
alias Geef.Object
alias Geef.Tree
def get(tree = %Object{type: :tree}, key) when is_number(key) do
case Tree.nth(tree, key) do
{:ok, entry} -> entry
{:error, _} -> nil
end
end
def get(tree = %Object{type: :tree}, key) do
case Tree.get(tree, key) do
{:ok, entry} -> entry
{:error, _} -> nil
end
end
# Git data is immutable
def get_and_update(_tree, _key, _fun) do
raise ArgumentError
end
end
defmodule Geef.TreeError do
defexception [reason: nil]
def message(%Geef.TreeError{reason: reason}) do
"tree error #{inspect reason}"
end
end
defimpl Enumerable, for: Geef.Object do
alias Geef.Object
alias Geef.Tree
alias Geef.TreeError
def count(tree = %Object{type: :tree}) do
{:ok, Tree.count(tree)}
end
def member?(tree = %Object{type: :tree}, key) do
case Tree.get(tree, key) do
{:ok, _} -> {:ok, true}
_ -> {:ok, false}
end
end
def reduce(tree = %Object{type: :tree}, acc, fun) do
reduce(tree, 0, Tree.count(tree), acc, fun)
end
# We're done when the index is equal to the number of entries
defp reduce(_, idx, idx, {:cont, acc}, _), do: {:done, acc}
# Call the user-passed function and recurse with the next index
defp reduce(tree, idx, count, {:cont, acc}, fun) do
case Tree.nth(tree, idx) do
{:ok, entry} ->
reduce(tree, idx + 1, count, fun.(entry, acc), fun)
{:error, error} ->
raise TreeError, reason: error
end
end
# Almost default Enumerable implementation
defp reduce(_, _, _, {:halt, acc}, _), do: {:halted, acc}
defp reduce(tree, idx, count, {:suspend, acc}, fun) do
{:suspended, acc, &reduce(tree, idx, count, &1, fun)}
end
end