Skip to content

Instantly share code, notes, and snippets.

@kevsmith
Created September 7, 2015 23:17
Show Gist options
  • Save kevsmith/c29f03a24d0cf9022324 to your computer and use it in GitHub Desktop.
Save kevsmith/c29f03a24d0cf9022324 to your computer and use it in GitHub Desktop.
Dynamically generate protocol impl w/no runtime overhead
defmodule Fstop.Model do
defmacro __using__(_) do
quote do
use Ecto.Model
@after_compile {Fstop.Enumerator, :generate}
end
end
end
defmodule Fstop.Enumerator do
def generate(env, _bytecode) do
quoted = define_enumerable(env.module)
write_beam(quoted)
end
defp define_enumerable(module) do
quote do
defimpl Enumerable, for: unquote(module) do
def count(v), do: Map.size(v) - 2
def member?(v, :__struct__), do: {:ok, false}
def member?(v, :__meta__), do: {:ok, false}
def member?(v, key) do
{:ok, Map.has_key?(v, key)}
end
# Too lazy to write this one :(
def reduce(v, acc, fun) do
raise RuntimeException, "Not implemented"
end
end
end
end
defp write_beam(quoted) do
[{module, bytecode}] = Code.compile_quoted(quoted)
file_name = "#{Atom.to_string(module)}.beam"
beam_path = Path.join(Mix.Project.compile_path, file_name)
File.write!(beam_path, bytecode, [:write])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment