Created
October 12, 2018 18:18
-
-
Save WolfDan/c111ce204daf5a0b699b7bd84ea075a7 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 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