lib/ton/common_message_info.ex

defmodule Ton.CommonMessageInfo do
  @moduledoc """
  Common message info used in an external message
  """

  alias Ton.Bitstring
  alias Ton.Cell
  alias Ton.Wallet

  defstruct [
    :wallet,
    :body
  ]

  @type t :: %__MODULE__{
          wallet: Wallet.t(),
          body: Cell.t()
        }

  @spec new(Wallet.t() | nil, Cell.t() | nil) :: t()
  def new(wallet \\ nil, body \\ nil) do
    %__MODULE__{wallet: wallet, body: body}
  end

  @spec serialize(t(), Cell.t() | nil) :: Cell.t()
  def serialize(info, cell \\ nil) do
    cell = cell || Cell.new()

    cell_with_state_init =
      if info.wallet do
        cell = %{cell | data: Bitstring.write_bit(cell.data, 1)}
        state_init_cell = Wallet.state_init_cell(info.wallet)

        if Bitstring.available(cell.data) - 1 >= state_init_cell.data.cursor do
          data = Bitstring.write_bit(cell.data, 0)

          Cell.write_cell(%{cell | data: data}, state_init_cell)
        else
          data = Bitstring.write_bit(cell.data, 1)

          %{cell | data: data, refs: cell.refs ++ [state_init_cell]}
        end
      else
        data = Bitstring.write_bit(cell.data, 0)

        %{cell | data: data}
      end

    if info.body do
      if Bitstring.available(cell_with_state_init.data) >= info.body.data.cursor do
        data = Bitstring.write_bit(cell_with_state_init.data, 0)

        Cell.write_cell(%{cell_with_state_init | data: data}, info.body)
      else
        data = Bitstring.write_bit(cell_with_state_init.data, 1)

        %{cell_with_state_init | data: data, refs: cell.refs ++ [info.body]}
      end
    else
      data = Bitstring.write_bit(cell_with_state_init.data, 0)

      %{cell | data: data}
    end
  end
end