Current section
Files
Jump to
Current section
Files
lib/igc/extensions.ex
defmodule IGC.Extensions do
defstruct extensions: []
@type definitions :: [{String.t(), integer(), integer()}]
@type values :: %{String.t() => String.t()}
@type t :: %__MODULE__{
extensions: definitions()
}
@spec parse_line(String.t()) :: {:ok, t()} | {:error, atom}
def parse_line(line) do
with {:ok, nr_extensions, rest} <- IGC.Parser.take(line, 2, :int),
{:ok, extensions} <- read_all_extensions(rest, nr_extensions) do
{:ok, %__MODULE__{extensions: Enum.sort_by(extensions, &elem(&1, 1))}}
end
end
@spec read_all_extensions(String.t(), integer(), definitions()) ::
{:ok, definitions()} | {:error, atom}
defp read_all_extensions(line, left, extensions \\ [])
defp read_all_extensions(_line, left, extensions) when left == 0, do: {:ok, extensions}
defp read_all_extensions(line, left, _extensions) when line == "" and left > 0,
do: {:error, :bad_extensions_count}
defp read_all_extensions(line, left, extensions) do
with {:ok, extensions, rest} <- read_extension(line, extensions) do
read_all_extensions(rest, left - 1, extensions)
end
end
@spec read_extension(String.t(), definitions()) ::
{:ok, definitions(), String.t()} | {:error, atom}
defp read_extension(line, extensions) do
with {:ok, start_byte, rest} <- IGC.Parser.take(line, 2, :int),
{:ok, end_byte, rest} <- IGC.Parser.take(rest, 2, :int),
{:ok, short_code, rest} <- IGC.Parser.take(rest, 3) do
{:ok, extensions ++ [{short_code, start_byte, end_byte}], rest}
end
end
@spec parse_values(String.t(), definitions(), values()) :: {:ok, values()} | {:error, atom}
def parse_values(line, extensions_def, extensions_values \\ %{})
def parse_values(_line, [], extensions_values), do: {:ok, extensions_values}
def parse_values("", extensions_def, _extensions_values) when length(extensions_def) > 0 do
{:error, :missing_extension_value}
end
def parse_values(line, extensions_def, extensions_values) do
with [{short_code, start_byte, end_byte} | next_extensions] <- extensions_def,
{:ok, value, rest} <- IGC.Parser.take(line, end_byte - start_byte + 1) do
parse_values(rest, next_extensions, Map.put(extensions_values, short_code, value))
end
end
end