 
   alias Xandra.{Batch, Error, Frame, Prepared, Page, Simple, TypeParser}
   alias Xandra.Cluster.StatusChange
+
+  # We need these two macros to make
+  # a single match context possible.
+
+  defmacrop decode_string({:<-, _, [value, buffer]}) do
+    quote do
+      <<size::16, unquote(value)::size(size)-bytes, unquote(buffer)::bits>> = unquote(buffer)
+    end
+  end
+
+  defmacrop decode_value({:<-, _, [value, buffer]}, type, do: block) do
+    quote do
+      <<size::32-signed, unquote(buffer)::bits>> = unquote(buffer)
+      if size < 0 do
+        unquote(value) = nil
+        unquote(block)
+      else
+        <<data::size(size)-bytes, unquote(buffer)::bits>> = unquote(buffer)
+        unquote(value) = decode_value(data, unquote(type))
+        unquote(block)
+      end
+    end
+  end
 
   @spec encode_request(Frame.t(kind), term, Keyword.t) :: Frame.t(kind) when kind: var
   def encode_request(frame, params, options \\ [])

    raise "cannot decode custom type #{inspect(class)}"
  end

  defp decode_type_udt(buffer, 0, acc) do
    {{:udt, Enum.reverse(acc)}, buffer}
  end

  defp decode_type_udt(buffer, count, acc) do
    {field_name, buffer} = decode_string(buffer)
    {field_type, buffer} = decode_type(buffer)

    decode_type_udt(buffer, count - 1, [{field_name, field_type} | acc])
  end

  defp decode_type_tuple(buffer, 0, acc) do
    {{:tuple, Enum.reverse(acc)}, buffer}
  end

  defp decode_type_tuple(buffer, count, acc) do
    {type, buffer} = decode_type(buffer)
    decode_type_tuple(buffer, count - 1, [type | acc])
  end

  defp decode_string_multimap(<<size::16>> <> buffer) do
    decode_string_multimap(buffer, size, [])
  end

  defp decode_string_multimap(buffer, 0, acc) do
    {Map.new(acc), buffer}
  end

  defp decode_string_multimap(buffer, size, acc) do
    {key, buffer} = decode_string(buffer)
    {value, buffer} = decode_string_list(buffer)
    decode_string_multimap(buffer, size - 1, [{key, value} | acc])
  end

  defp decode_string(<<size::16, content::size(size)-bytes>> <> buffer) do
    {content, buffer}
  end

  defp decode_string_list(<<size::16>> <> buffer) do
    decode_string_list(buffer, size, [])
  end

  defp decode_string_list(buffer, 0, acc) do
    {Enum.reverse(acc), buffer}
  end

  defp decode_string_list(buffer, size, acc) do
    {elem, buffer} = decode_string(buffer)
    decode_string_list(buffer, size - 1, [elem | acc])
  end
end

  end

  # Page
  defp decode_result_response(<<0x0002::32-signed, buffer::bits>>, query) do
    page = new_page(query)
    {page, buffer} = decode_metadata(buffer, page)
    content = decode_page_content(buffer, page.columns)
