exercism/elixir/take-a-number-deluxe/lib/take_a_number_deluxe.ex

95 lines
2.8 KiB
Elixir

defmodule TakeANumberDeluxe do
alias TakeANumberDeluxe.State
use GenServer
# Client API
@spec start_link(keyword()) :: {:ok, pid()} | {:error, atom()}
def start_link(init_arg) do
GenServer.start_link(__MODULE__, init_arg)
end
@spec report_state(pid()) :: State.t()
def report_state(machine) do
GenServer.call(machine, :report_state)
end
@spec queue_new_number(pid()) :: {:ok, integer()} | {:error, atom()}
def queue_new_number(machine) do
GenServer.call(machine, :queue_new_number)
end
@spec serve_next_queued_number(pid(), integer() | nil) :: {:ok, integer()} | {:error, atom()}
def serve_next_queued_number(machine, priority_number \\ nil) do
GenServer.call(machine, {:serve_next_queued_number, priority_number})
end
@spec reset_state(pid()) :: :ok
def reset_state(machine) do
GenServer.cast(machine, :reset_state)
end
# Server callbacks
@impl GenServer
def init(options) do
with min <- Keyword.get(options, :min_number),
max <- Keyword.get(options, :max_number),
shutdown <- Keyword.get(options, :auto_shutdown_timeout, :infinity),
{:ok, state} <- State.new(min, max, shutdown) do
{:ok, state, shutdown}
else
_ -> {:stop, :invalid_configuration}
end
end
@impl GenServer
def handle_call(:report_state, _from, state) do
{:reply, state, state, state.auto_shutdown_timeout}
end
@impl GenServer
def handle_call(:queue_new_number, _from, state) do
case State.queue_new_number(state) do
{:ok, new_number, new_state} -> {:reply, {:ok, new_number}, new_state, new_state.auto_shutdown_timeout}
error -> {:reply, error, state, state.auto_shutdown_timeout}
end
end
@impl GenServer
def handle_call({:serve_next_queued_number, priority_number}, _from, state) do
case State.serve_next_queued_number(state, priority_number) do
{:ok, new_number, new_state} -> {:reply, {:ok, new_number}, new_state, new_state.auto_shutdown_timeout}
error -> {:reply, error, state, state.auto_shutdown_timeout}
end
end
@impl GenServer
def handle_call(_request, _from, state) do
{:reply, :unknown_command, state, state.auto_shutdown_timeout}
end
@impl GenServer
def handle_cast(
:reset_state,
%State{min_number: min_number, max_number: max_number, auto_shutdown_timeout: auto_shutdown_timeout}
) do
{:ok, new_state} = State.new(min_number, max_number, auto_shutdown_timeout)
{:noreply, new_state, new_state.auto_shutdown_timeout}
end
@impl GenServer
def handle_cast(_request, state) do
{:noreply, state, state.auto_shutdown_timeout}
end
@impl GenServer
def handle_info(:timeout, state) do
{:stop, :normal, state}
end
@impl GenServer
def handle_info(_request, state) do
{:noreply, state, state.auto_shutdown_timeout}
end
end