lib/protocol.ex

defmodule Moar.Protocol do
  # @related [test](/test/protocol_test.exs)

  @moduledoc "Protocol-related functions."

  @doc """
  Returns `x` or raises if `x` does not implment `protocol`.

  ```elixir
  iex> Moar.Protocol.implements!(~D[2000-01-02], String.Chars)
  ~D[2000-01-02]
  ```
  """
  @spec implements!(any(), module()) :: any()
  def implements!(x, protocol) do
    if implements?(x, protocol),
      do: x,
      else: raise("Expected #{inspect(x)} to implement protocol #{inspect(protocol)}")
  end

  @doc """
  Returns true if `x` implements `protocol`.

  ```elixir
  iex> Moar.Protocol.implements?(~D[2000-01-02], String.Chars)
  true
  ```
  """
  @spec implements?(any(), module()) :: boolean()
  def implements?(x, protocol), do: protocol.impl_for(x) != nil
end