Current section
Files
Jump to
Current section
Files
lib/expline.ex
defmodule Expline do
use GenServer
require Logger
@moduledoc """
`Expline` is a `GenServer` that wraps the `Expline.Spline` module. It builds
the `Expline.Spline` after being supplied the input parameters in `start/3` or
`start_link/3`. After initializing, use the `interpolate/2` and
`interpolate/3` functions to find the corresponding points for each value you
wish to interpolate.
For more information regarding the mathematics and performance of the spline
building, read the `Expline.Spline` module documentation.
"""
@typep state() :: Expline.Spline.t
@doc """
Builds a spline from the provided list of points and holds the state in a
process without links (outside of a supervision tree).
See `start_link/2` for more information.
"""
@spec start(list(Expline.Spline.point()), GenServer.options()) :: {:ok, pid()}
| {:error, {:already_started, pid()}}
| {:error, Expline.Spline.creation_error()}
def start(points, opts \\ []) do
GenServer.start(__MODULE__, [points], opts)
end
@doc """
Builds a spline from the provided list of points and holds the state in a
process linked to the current process.
This is often used to start the server process as part of a supervision tree.
## Options and more information
See `GenServer.start_link/3` for more information.
"""
@spec start_link(list(Expline.Spline.point()), GenServer.options()) :: {:ok, pid()}
| {:error, {:already_started, pid()}}
| {:error, Expline.Spline.creation_error()}
def start_link(points, opts \\ []) do
GenServer.start_link(__MODULE__, [points], opts)
end
def init([list_of_points]) do
case Expline.Spline.from_points(list_of_points) do
{:ok, spline} ->
{:ok, spline}
{:error, reason} ->
{:stop, reason}
end
end
@doc """
Interpolate a `t:Expline.Spline.point/0` from its independent value.
When an error arises with the interpolation, an error found in
`t:Expline.Spline.interpolation_error/0` will be returned.
"""
@spec interpolate(GenServer.server(), float(), timeout()) :: {:ok, Expline.Spline.point()}
| {:error, Expline.Spline.interpolation_error()}
def interpolate(server, x, timeout \\ 5000) when is_float(x) do
GenServer.call(server, {:interpolate, x}, timeout)
end
@spec handle_call({:interpolate, Expline.Spline.dependent_value()}, GenServer.from(), state()) :: {:reply, {:ok, Expline.Spline.point()}, state()}
def handle_call({:interpolate, x}, _from, spline) do
case Expline.Spline.interpolate(spline, x) do
{:ok, y} ->
{:reply, {:ok, {x, y}}, spline}
{:error, reason} ->
{:reply, {:error, reason}, spline}
end
end
end