Created
July 28, 2017 22:28
-
-
Save marysaka/0f52ef91629baff409b456c88c0e9ff5 to your computer and use it in GitHub Desktop.
Simple RESP (REdis Serialization Protocol) decoder/encoder in Elixir
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
defmodule Redis.Protocol.Decoder do | |
def decode(<<"*", elem_count :: binary-size(1), "\r\n", rest :: binary>>) do | |
elem_count = elem_count |> String.to_integer | |
decode_array(rest, elem_count, []) | |
end | |
def decode(<<"+", rest :: binary>>), do: decode_simple_string(rest) | |
def decode(<<"-", rest :: binary>>), do: decode_error_string(rest) | |
def decode(<<"$", size :: binary-size(1), rest :: binary>>), do: decode_bulk_string(size |> String.to_integer, rest) | |
def decode(<<":", rest :: binary>>), do: decode_integer_string(rest) | |
def decode(resp), do: {:error, "Cannot be parsed!", resp} | |
defp decode_simple_string(rest) do | |
{end_pos,_} = :binary.match(rest, "\r\n") | |
<<str :: binary-size(end_pos), "\r\n", rest :: binary>> = rest | |
{:simple_str, str, rest} | |
end | |
defp decode_error_string(rest), do: decode_simple_string(rest) |> put_elem(0, :error_str) | |
defp decode_integer_string(rest) do | |
{_, value, rest} = decode_simple_string(rest) | |
{:integer, value |> String.to_integer, rest} | |
end | |
defp decode_bulk_string(-1, rest), do: {:bulk_str, nil, rest} | |
defp decode_bulk_string(count, rest) do | |
<<"\r\n", bulk :: binary-size(count), "\r\n", rest :: binary>> = rest | |
{:bulk_str, bulk, rest} | |
end | |
defp decode_array(_, 0, accumulator), do: accumulator | |
defp decode_array(raw, count, accumulator) do | |
{type, value, raw} = decode(raw) | |
decode_array(raw, count - 1, accumulator ++ [{type, value}]) | |
end | |
end |
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
defmodule Redis.Protocol.Encoder do | |
def encode(data) when is_list(data), do: "*#{Enum.count(data)}\r\n" <>encode_array(data, "") | |
def encode({:simple_str, value}), do: "+" <> value <> "\r\n" | |
def encode({:error_str, value}), do: "-" <> value <> "\r\n" | |
def encode({:integer, value}), do: ":" <> Integer.to_string(value) <> "\r\n" | |
def encode({:bulk_str, nil}), do: "$-1\r\n" | |
def encode({:bulk_str, value}), do: "$#{String.length(value)}\r\n#{value}\r\n" | |
def encode(_), do: nil | |
defp encode_array([head | tail], accumulator), do: encode_array(tail, accumulator <> encode(head)) | |
defp encode_array([], accumulator), do: accumulator | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment