Skip to content

Instantly share code, notes, and snippets.

@Awlexus
Last active November 3, 2020 22:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Awlexus/e01e3832dafa162dd23cd8967ba90707 to your computer and use it in GitHub Desktop.
Save Awlexus/e01e3832dafa162dd23cd8967ba90707 to your computer and use it in GitHub Desktop.
A simple implementation of a bencode decoder.
# There exists a library called "Bento", which is more sophisticated,
# but feel free to use this as a reference or just drop it into your code, if you don't care about errors
defmodule Bencode do
@spec parse_dictionary(binary()) :: {map(), binary()}
def parse_dictionary("d" <> rest), do: do_parse_dictionary(rest, %{})
@spec parse_list(binary()) :: {list(), binary()}
def parse_list("l" <> data), do: do_parse_list(data, [])
@spec parse_integer(binary()) :: {integer(), binary()}
def parse_integer("i" <> data) do
{int, "e" <> rest} = Integer.parse(data)
{int, rest}
end
@spec parse_string(binary()) :: {binary(), binary()}
def parse_string(string) do
{length, rest} = Integer.parse(string)
<<":", string::binary-size(length), rest::binary>> = rest
{string, rest}
end
# automatically recognize what value to parse
defp parse_value("d" <> _ = dict), do: parse_dictionary(dict)
defp parse_value("i" <> _ = integer), do: parse_integer(integer)
defp parse_value("l" <> _ = list), do: parse_list(list)
defp parse_value(string), do: parse_string(string)
# Helpers
defp do_parse_dictionary("e" <> rest, acc), do: {acc, rest}
defp do_parse_dictionary(data, acc) do
{key, value, rest} = parse_entry(data)
do_parse_dictionary(rest, Map.put(acc, key, value))
end
defp parse_entry(data) do
{key, rest} = parse_value(data)
{value, rest} = parse_value(rest)
{key, value, rest}
end
defp do_parse_list("e" <> rest, list), do: {Enum.reverse(list), rest}
defp do_parse_list(rest, list) do
{value, rest} = parse_value(rest)
do_parse_list(rest, [value | list])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment