lib/validators/protocols/at.ex

defprotocol ValueAt do
  @moduledoc """
  A protocol to retrive an element at a specific position within a data structure.

  ## Default Implementations

  The protocol provides default implementations for common data types:
  - `BitString`: Retrieves the grapheme at the specified position.
  - `List`: Retrieves the element at the specified index.

  Position start from zero:
      iex> ValueAt.at("Hello! Dzień dobry!", 5)
      "!"

  Implementation return value at the given position:
      iex> ValueAt.at(["a", :b, ["c"], %{d: "d"}], 3)
      %{d: "d"}

  In both implementations, `List` and `BitString`, when an index is out of bounds, `nil` is returned.
      iex> ValueAt.at("Hello", 10)
      nil

  ## Custom implementation example
  Implementation of this protocl require a `ValueAt.at(data, position)` function.

      defmodule MyStruct do
        defstruct data: [1, 2, 3]
      end

      defimpl At, for: MyStruct do
        def at(%MyStruct{data: data}, index) when is_integer(index) and index >= 0 do
          Enum.at(data, index)
        end
      end



  """

  @doc """
  Retrieves an element at the specified position within the data structure.

  ## Parameters

  * `data` - The data structure from which to retrieve the element.
  * `index` - The position (index) at which to retrieve the element.

  ## Returns

  - The element at the specified position within the data structure.
  - If position is out of bound, `nil` should be returned.

  """
  def at(data, position)
end

defimpl ValueAt, for: List do
  def at(data, position), do: Enum.at(data, position)
end

# FindAny
defimpl ValueAt, for: BitString do
  def at(data, position), do: String.at(data, position)
end