defmodule Queue do
@moduledoc """
Module for work queue.
This module implement protocol Enumerable.
"""
@keys [:queue]
@enforce_keys @keys
defstruct @keys
@type t :: %__MODULE__{}
@doc """
Return new queue structure
## Example:
iex> Queue.new()
#Queue<Empty>
"""
@spec new :: Queue.t()
def new do
queue = :queue.new()
%__MODULE__{queue: queue}
end
@doc """
Return the queue is empty
## Example:
iex> queue = Queue.new()
iex> Queue.empty?(queue)
true
iex> queue = Queue.inside(queue, 1)
iex> Queue.empty?(queue)
false
"""
@spec empty?(Queue.t()) :: boolean()
def empty?(%__MODULE__{queue: queue}) do
:queue.is_empty(queue)
end
@doc """
Put element in queue
## Example:
iex> queue = Queue.new() |> Queue.inside(1)
#Queue<1>
iex> {1, queue} = Queue.out(queue)
iex> queue
#Queue<Empty>
"""
@spec inside(Queue.t(), any()) :: any()
def inside(%__MODULE__{queue: queue}, item) do
queue = :queue.in(item, queue)
%__MODULE__{queue: queue}
end
@doc """
Get element of queue
## Example:
iex> queue = Queue.new() |> Queue.inside(1)
#Queue<1>
iex> {1, queue} = Queue.out(queue)
iex> queue
#Queue<Empty>
iex> {nil, ^queue} = Queue.out(queue)
"""
@spec out(Queue.t()) :: any()
def out(%__MODULE__{queue: queue}) do
case :queue.out(queue) do
{{:value, item}, queue} -> {item, %Queue{queue: queue}}
{:empty, queue} -> {nil, %Queue{queue: queue}}
end
end
@doc """
Get head element of queue
## Example:
iex> queue = Queue.new() |> Queue.inside(1)
iex> Queue.head(queue)
1
iex> Queue.new() |> Queue.head()
nil
"""
@spec head(Queue.t()) :: any()
def head(%__MODULE__{queue: queue}) do
try do
:queue.head(queue)
rescue
ErlangError -> nil
end
end
@doc """
Get first element of queue.
This function is equals head function.
## Example:
iex> queue = Queue.new() |> Queue.inside(1)
iex> Queue.first(queue)
1
iex> Queue.new() |> Queue.first()
nil
"""
@spec first(Queue.t()) :: any()
def first(queue) do
head(queue)
end
@doc """
Get last element of queue.
## Example:
iex> queue = Queue.new() |> Queue.inside(1)
iex> Queue.last(queue)
1
iex> queue = Queue.inside(queue, 2)
iex> Queue.last(queue)
2
iex> Queue.new() |> Queue.last()
nil
"""
@spec last(Queue.t()) :: any()
def last(%Queue{queue: queue}) do
try do
:queue.last(queue)
rescue
ErlangError -> nil
end
end
@doc """
Returns a list with all values of queue.
## Examples:
iex> queue = Queue.new() |> Queue.inside(1) |> Queue.inside(2)
iex> Queue.to_list(queue)
[1, 2]
"""
@spec to_list(Queue.t()) :: list()
def to_list(%Queue{queue: queue}), do: :queue.to_list(queue)
@doc """
Returns a list of values.
It's equal to to_list/1
## Examples:
iex> queue = Queue.new() |> Queue.inside(1) |> Queue.inside(2)
iex> Queue.values(queue)
[1, 2]
"""
@spec values(Queue.t()) :: list()
def values(%Queue{} = queue), do: to_list(queue)
@doc """
Returns the size of the queue.
## Examples
iex> queue = Queue.new() |> Queue.inside(1) |> Queue.inside(2)
iex> Queue.count(queue)
2
"""
@spec count(Queue.t()) :: non_neg_integer()
def count(%Queue{queue: queue}) do
:queue.len(queue)
end
end