Last active
November 3, 2020 22:24
-
-
Save Awlexus/e01e3832dafa162dd23cd8967ba90707 to your computer and use it in GitHub Desktop.
A simple implementation of a bencode decoder.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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