Skip to content

Instantly share code, notes, and snippets.

@WolfDan
Created October 12, 2018 18:18
Show Gist options
  • Save WolfDan/c111ce204daf5a0b699b7bd84ea075a7 to your computer and use it in GitHub Desktop.
Save WolfDan/c111ce204daf5a0b699b7bd84ea075a7 to your computer and use it in GitHub Desktop.
defmodule Nomure.Database.Coder.GraphValue do
@moduledoc """
A module that specifies how the data is serialized, pretty much as the `FDB.Coder.Dynamic` but without
the need of specifing the type
"""
use FDB.Coder.Behaviour
import Nomure.Database.Coder.Guards,
only: [is_int: 1, is_long: 1, is_short: 1, is_long_string: 1, is_byte: 1]
@uid_header <<0x01>>
@byte_header <<0x02>>
@short_header <<0x03>>
@int32_header <<0x04>>
@int64_header <<0x05>>
@float_header <<0x06>>
@bool_header <<0x07>>
@string_header <<0x08>>
@string_compressed_header <<0x09>>
@spec new() :: FDB.Coder.t()
def new() do
%FDB.Coder{module: __MODULE__, opts: nil}
end
@impl true
def encode(<<_value::little-integer-unsigned-size(128)>> = value, _) do
@uid_header <> value
end
# TODO use kind of SIMD compression integer? hmm (Tho I don't know if is a real use for it here)
def encode(value, _) when is_byte(value) do
@byte_header <> <<value::8>>
end
def encode(value, _) when is_short(value) do
@short_header <> <<value::16>>
end
def encode(value, _) when is_int(value) do
@int32_header <> <<value::32>>
end
def encode(value, _) when is_long(value) do
@int64_header <> <<value::64>>
end
def encode(value, _) when is_float(value) do
@float_header <> <<value::float-64>>
end
def encode(value, _) when is_long_string(value) do
# header - string size - string value
# we compress it to save storage space, tho small string can be a bit bigger (due to zstd header)
# can help you a lot of compressing large pieces of text
# TODO make it optional to the user? Tho it just will consume more storage space, with no
# performance impact at all
compressed = :zstd.compress(value)
@string_compressed_header <> <<byte_size(compressed)::32>> <> compressed
end
def encode(value, _) when is_binary(value) do
# header - string size - string value
@string_header <> <<byte_size(value)::32>> <> value
end
def encode(true, _) do
@bool_header <> <<0x01>>
end
def encode(false, _) do
@bool_header <> <<0x00>>
end
@impl true
def decode(@uid_header <> <<value::little-integer-unsigned-size(128), rest::binary>>, _) do
{value, rest}
end
def decode(@byte_header <> <<value::8, rest::binary>>, _) do
{value, rest}
end
def decode(@short_header <> <<value::16, rest::binary>>, _) do
{value, rest}
end
def decode(@int32_header <> <<value::32, rest::binary>>, _) do
{value, rest}
end
def decode(@int64_header <> <<value::64, rest::binary>>, _) do
{value, rest}
end
def decode(@float_header <> <<value::float-64, rest::binary>>, _) do
{value, rest}
end
def decode(@bool_header <> <<0x01, rest::binary>>, _) do
{true, rest}
end
def decode(@bool_header <> <<0x00, rest::binary>>, _) do
{false, rest}
end
def decode(
@string_header <> <<string_size::32, string::binary-size(string_size), rest::binary>>,
_
) do
{string, rest}
end
def decode(
@string_compressed_header <>
<<string_size::32, compressed::binary-size(string_size), rest::binary>>,
_
) do
{compressed |> :zstd.decompress(), rest}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment