lib/tx_build/ledger_bounds.ex

defmodule Stellar.TxBuild.LedgerBounds do
  @moduledoc """
  `LedgerBounds` struct definition.
  """
  alias StellarBase.XDR.{UInt32, LedgerBounds, OptionalLedgerBounds}

  @behaviour Stellar.TxBuild.XDR

  @type validation :: {:ok, non_neg_integer()} | {:error, :atom}
  @type t :: %__MODULE__{min_ledger: non_neg_integer(), max_ledger: non_neg_integer()}

  defstruct [:min_ledger, :max_ledger]

  @impl true
  def new(ledger_bounds \\ [min_ledger: 0, max_ledger: 0], opts \\ [])

  def new(:none, _opts), do: new(min_ledger: 0, max_ledger: 0)

  def new([min_ledger: min_ledger, max_ledger: max_ledger], _opts) do
    with {:ok, min_ledger} <- validate_ledger_bounds(min_ledger),
         {:ok, max_ledger} <- validate_ledger_bounds(max_ledger) do
      %__MODULE__{min_ledger: min_ledger, max_ledger: max_ledger}
    end
  end

  @impl true
  def to_xdr(%__MODULE__{min_ledger: 0, max_ledger: 0}) do
    OptionalLedgerBounds.new()
  end

  def to_xdr(%__MODULE__{min_ledger: min_ledger, max_ledger: max_ledger}) do
    min_ledger = UInt32.new(min_ledger)
    max_ledger = UInt32.new(max_ledger)

    min_ledger
    |> LedgerBounds.new(max_ledger)
    |> OptionalLedgerBounds.new()
  end

  @spec validate_ledger_bounds(ledger_bound :: non_neg_integer()) :: validation()
  defp validate_ledger_bounds(ledger_bound) when is_integer(ledger_bound) and ledger_bound >= 0 do
    {:ok, ledger_bound}
  end

  defp validate_ledger_bounds(_ledger_bounds), do: {:error, :invalid_ledger_bounds}
end