lib/phoenix_micro/utils/encoding.ex

defmodule PhoenixMicro.Utils.Encoding do
  @moduledoc """
  Shared encoding/decoding helpers used across transports and the producer.

  Provides a unified entry point for payload serialization so all transports
  produce and consume messages in the same format regardless of the underlying
  broker's wire format.
  """

  @doc """
  Encodes `payload` using the configured serializer.
  Returns a binary.
  """
  @spec encode!(term()) :: binary()
  def encode!(payload) do
    serializer().encode!(payload)
  end

  @doc """
  Decodes `binary` using the configured serializer.
  Returns the decoded term.
  """
  @spec decode!(binary()) :: term()
  def decode!(binary) do
    serializer().decode!(binary)
  end

  @doc """
  Returns the MIME content-type for the configured serializer.
  """
  @spec content_type() :: String.t()
  def content_type do
    serializer().content_type()
  end

  @doc """
  Safely encodes a term — returns `{:ok, binary}` or `{:error, reason}`.
  """
  @spec encode(term()) :: {:ok, binary()} | {:error, Exception.t()}
  def encode(payload) do
    {:ok, encode!(payload)}
  rescue
    e -> {:error, e}
  end

  @doc """
  Safely decodes a binary — returns `{:ok, term}` or `{:error, reason}`.
  """
  @spec decode(binary()) :: {:ok, term()} | {:error, Exception.t()}
  def decode(binary) do
    {:ok, decode!(binary)}
  rescue
    e -> {:error, e}
  end

  # ---------------------------------------------------------------------------
  # Private
  # ---------------------------------------------------------------------------

  defp serializer do
    # Guard against Config being unavailable (e.g. in minimal test environments)
    if Code.ensure_loaded?(PhoenixMicro.Config) do
      PhoenixMicro.Config.get(:serializer, PhoenixMicro.Serializer.JSON)
    else
      Application.get_env(:phoenix_micro, :serializer, PhoenixMicro.Serializer.JSON)
    end
  end
end