<commit_before>defmodule Thrift.Protocol.Binary do
  @moduledoc """
  Provides a set of high-level functions for working with the Thrift binary
  protocol.

  The Thrift binary protocol uses a fairly simple binary encoding scheme in
  which the length and type of a field are encoded as bytes followed by the
  actual value of the field.
  """

  alias Thrift.TApplicationException

  require Thrift.Protocol.Binary.Type, as: Type

  @type deserializable :: :message_begin | :application_exception

  @stop 0

  @typedoc "Binary protocol message type identifier"
  @type message_type_id :: (1..4)

  @spec from_message_type(Thrift.message_type) :: message_type_id
  defp from_message_type(:call),      do: 1
  defp from_message_type(:reply),     do: 2
  defp from_message_type(:exception), do: 3
  defp from_message_type(:oneway),    do: 4

  @spec to_message_type(message_type_id) :: Thrift.message_type
  defp to_message_type(1), do: :call
  defp to_message_type(2), do: :reply
  defp to_message_type(3), do: :exception
  defp to_message_type(4), do: :oneway

  @typedoc "Binary protocol message sequence identifier"
  @type message_seq_id :: non_neg_integer

  @doc """
  Serializes a value as an IO list using Thrift's type-specific encoding rules.
  """
  @spec serialize(Thrift.data_type | :message_begin, any) :: iolist
  def serialize(:bool, false),   do: <<0::8-signed>>
  def serialize(:bool, true),    do: <<1::8-signed>>
  def serialize(:i8, value),     do: <<value::8-signed>>
  def serialize(:i16, value),    do: <<value::16-signed>>
  def serialize(:i32, value),    do: <<value::32-signed>>
  def serialize(:i64, value),    do: <<value::64-signed>>
  def serialize(:double, value), do: <<value::signed-float>>
  def serialize(:string, value), do: [<<byte_size(value)::size(32)>>, value]
  def serialize(:binary, value), do: [<<byte_size(value)::size(32)>>, value]

  def serialize({:list, elem_type}, elems) when is_list(elems) do
    rest = Enum.map(elems, &serialize(elem_type, &1))
    [<<Type.of(elem_type)::size(8), Enum.count(elems)::32-signed>>, rest]
  end
  def serialize({:set, elem_type}, %MapSet{} = elems) do
    rest = Enum.map(elems, &serialize(elem_type, &1))
    [<<Type.of(elem_type)::size(8), Enum.count(elems)::32-signed>>, rest]
  end
  def serialize({:map, {key_type, val_type}}, map) when is_map(map) do
    elem_count = map_size(map)
    rest = Enum.map(map, fn {key, value} ->
      [serialize(key_type, key), serialize(val_type, value)]
    end)
    [<<Type.of(key_type)::size(8), Type.of(val_type)::size(8), elem_count::32-signed>>, rest]
  end
  def serialize(:struct, %{__struct__: mod} = struct) do
    mod.serialize(struct, :binary)<commit_msg>Introduce a 'serializable' type (#210)<commit_after>defmodule Thrift.Protocol.Binary do
  @moduledoc """
  Provides a set of high-level functions for working with the Thrift binary
  protocol.

  The Thrift binary protocol uses a fairly simple binary encoding scheme in
  which the length and type of a field are encoded as bytes followed by the
  actual value of the field.
  """

  alias Thrift.TApplicationException

  require Thrift.Protocol.Binary.Type, as: Type

  @type serializable :: Thrift.data_type | :message_begin | :application_exception
  @type deserializable :: :message_begin | :application_exception

  @stop 0

  @typedoc "Binary protocol message type identifier"
  @type message_type_id :: (1..4)

  @spec from_message_type(Thrift.message_type) :: message_type_id
  defp from_message_type(:call),      do: 1
  defp from_message_type(:reply),     do: 2
  defp from_message_type(:exception), do: 3
  defp from_message_type(:oneway),    do: 4

  @spec to_message_type(message_type_id) :: Thrift.message_type
  defp to_message_type(1), do: :call
  defp to_message_type(2), do: :reply
  defp to_message_type(3), do: :exception
  defp to_message_type(4), do: :oneway

  @typedoc "Binary protocol message sequence identifier"
  @type message_seq_id :: non_neg_integer

  @doc """
  Serializes a value as an IO list using Thrift's type-specific encoding rules.
  """
  @spec serialize(serializable, any) :: iolist
  def serialize(:bool, false),   do: <<0::8-signed>>
  def serialize(:bool, true),    do: <<1::8-signed>>
  def serialize(:i8, value),     do: <<value::8-signed>>
  def serialize(:i16, value),    do: <<value::16-signed>>
  def serialize(:i32, value),    do: <<value::32-signed>>
  def serialize(:i64, value),    do: <<value::64-signed>>
  def serialize(:double, value), do: <<value::signed-float>>
  def serialize(:string, value), do: [<<byte_size(value)::size(32)>>, value]
  def serialize(:binary, value), do: [<<byte_size(value)::size(32)>>, value]

  def serialize({:list, elem_type}, elems) when is_list(elems) do
    rest = Enum.map(elems, &serialize(elem_type, &1))
    [<<Type.of(elem_type)::size(8), Enum.count(elems)::32-signed>>, rest]
  end
  def serialize({:set, elem_type}, %MapSet{} = elems) do
    rest = Enum.map(elems, &serialize(elem_type, &1))
    [<<Type.of(elem_type)::size(8), Enum.count(elems)::32-signed>>, rest]
  end
  def serialize({:map, {key_type, val_type}}, map) when is_map(map) do
    elem_count = map_size(map)
    rest = Enum.map(map, fn {key, value} ->
      [serialize(key_type, key), serialize(val_type, value)]
    end)
    [<<Type.of(key_type)::size(8), Type.of(val_type)::size(8), elem_count::32-signed>>, rest]
  end
  def serialize(:struct, %{__struct__: mod} = struct) do
    mod.serialize(struct, :binary)
{'fraction_non_alphanumeric': 0.1481616974574721, 'fraction_numerical': 0.017011157856228278, 'mean_word_length': 4.713688610240334, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4985296', 'n_tokens_mistral': 1957, 'n_tokens_neox': 1891, 'n_words': 495}