lib/icon/schema/types/integer.ex

defmodule Icon.Schema.Types.Integer do
  @moduledoc """
  This module defines an ICON 2.0 integer.
  """
  use Icon.Schema.Type

  @typedoc """
  An integer.
  """
  @type t :: integer()

  @spec load(any()) :: {:ok, t()} | :error
  @impl Icon.Schema.Type
  def load(value)

  def load(int) when is_integer(int) do
    {:ok, int}
  end

  def load("-0x" <> hex) do
    with {:ok, int} <- load("0x" <> hex) do
      {:ok, -int}
    end
  end

  def load("0x" <> hex) do
    case Integer.parse(hex, 16) do
      {int, ""} when int >= 0 -> {:ok, int}
      _ -> :error
    end
  end

  def load(str) when is_binary(str) do
    case Integer.parse(str) do
      {int, ""} -> {:ok, int}
      _ -> :error
    end
  end

  def load(_value) do
    :error
  end

  @spec dump(any()) :: {:ok, binary()} | :error
  @impl Icon.Schema.Type
  def dump(int) when is_integer(int) and int < 0 do
    with {:ok, "0x" <> hex} <- dump(-int) do
      {:ok, "-0x" <> hex}
    end
  end

  def dump(int) when is_integer(int) and int >= 0 do
    value =
      int
      |> Integer.to_string(16)
      |> String.downcase()

    {:ok, "0x" <> value}
  end

  def dump(_value) do
    :error
  end
end