lib/protobuf/transform_module.ex

defmodule Protobuf.TransformModule do
  @moduledoc """
  Behaviour for transformer modules.

  By defining a `transform_module/0` function on your protobuf message module
  you can add custom encoding and decoding logic for your message.

  The `c:Protobuf.new/1` function will not be called for structs that have a transform module, if
  you still want to emulate this behavior you can use `Protobuf.TransformModule.InferFieldsFromEnum`.

  As an example we can use this to implement a message that will be decoded as a string value:

      defmodule StringMessage do
        use Protobuf, syntax: :proto3

        defstruct [:value]

        field :value, 1, type: :string

        def transform_module(), do: MyTransformModule
      end

  The transformer behaviour implementation:

      defmodule MyTransformModule do
        @behaviour Protobuf.TransformModule

        @impl true
        def encode(string, StringMessage) when is_binary(string), do: %StringMessage{value: string}

        @impl true
        def decode(%StringMessage{value: string}, StringMessage), do: string
      end
  """

  @type value() :: term()
  @type type() :: module()
  @type message() :: struct()

  @doc """
  Takes any Elixir term and the protobuf message type and encodes it into
  that type.

  Called before a message is encoded.
  """
  @callback encode(value(), type()) :: message()

  @doc """
  Takes any protobuf message and the message type and encodes it into arbitrary
  Elixir term.

  Called after a message is decoded.
  """
  @callback decode(message(), type()) :: value()
end