lib/elven_gard/network/network_codec.ex

defmodule ElvenGard.Network.NetworkCodec do
  @moduledoc ~S"""
  Behavior for Defining Packet Encoding and Decoding

  Implementations of this behavior are responsible for parsing incoming 
  raw binary data into structured packets and encoding structured packets into
  binary data for transmission over the network.

  For more information on how to implement this behavior and use packet encoding
  and decoding, please refer to the 
  [NetworkCodec guide](https://hexdocs.pm/elvengard_network/network_codec.html).
  """

  alias ElvenGard.Network.Socket

  @doc """
  Identifies and extracts the first packet from raw binary data.

  This function searches for the first packet within the raw binary data and
  returns it along with the remaining binary data. The extracted packet will
  be passed to the `decode/2` callback for further processing.

  ## Examples

      raw = <<packet1::binary, remaining::binary>>
      {^packet1, ^remaining} = MyNetworkCodec.next(raw, socket)

  """
  @callback next(raw :: bitstring, socket :: Socket.t()) ::
              {packet_raw :: bitstring, remaining :: bitstring}

  @doc """
  Decodes a packet from raw binary data.

  This callback function is responsible for decoding a packet from the provided
  raw binary data. The decoded packet should be returned as a struct containing
  the parsed fields.

  ## Examples

      raw_packet = <<1::8, 123::8, "some data"::binary>>  # Example raw packet data
      %MessageStruct{id: 123, data: "some data"} = MyNetworkCodec.decode(raw_packet, socket)

  """
  @callback decode(raw :: bitstring, socket :: Socket.t()) :: struct

  @doc """
  Encodes a packet for network transmission.

  This callback function is responsible for encoding a structured packet or raw
  binary data into the binary format suitable for transmission over the network.
  The resulting encoded data, in the form of `iodata()`, can be directly sent
  over the network.

  ## Examples

      packet = %MessageStruct{id: 1, data: "Hello"}
      <<header::8, id::8, data::binary>> = MyNetworkCodec.encode(packet, socket)

  """
  @callback encode(packet :: struct() | iodata(), socket :: Socket.t()) :: iodata()
end