lib/agent.ex

defmodule Queue.Agent do
  @moduledoc """
  Agent for work with queue
  """

  use Agent

  def start_link(_initial_state) do
    Agent.start_link(fn -> Queue.new() end, name: __MODULE__)
  end

  @doc ~S"""
  Inside element in queue

  ## Examples:

      iex> {:ok, _pid} = Queue.Agent.start_link(nil)
      iex> Queue.Agent.inside("first")
      :ok
      iex> Queue.Agent.out()
      "first"
  """
  @spec inside(any()) :: :ok
  def inside(item) do
    Agent.update(__MODULE__, &update_state(&1, :in, item))
  end

  @doc ~S"""
  Outside element of queue

  ## Examples:

      iex> {:ok, _pid} = Queue.Agent.start_link(nil)
      iex> Queue.Agent.inside("first")
      :ok
      iex> Queue.Agent.out()
      "first"
  """
  @spec out :: any()
  def out do
    {item, _} = Agent.get(__MODULE__, fn queue -> Queue.out(queue) end)

    Agent.update(__MODULE__, &update_state(&1, :out))

    item
  end

  defp update_state(queue, :in, item) do
    Queue.inside(queue, item)
  end

  defp update_state(queue, :out) do
    {_, queue} = Queue.out(queue)

    queue
  end
end