Implement deserialization for varints and varlongs
All checks were successful
Build & Test / nix-build (push) Successful in 1m7s

This commit is contained in:
Kodi Craft 2024-07-07 18:23:14 +02:00
parent 502ca17bd3
commit 92325c05b1
Signed by: kodi
GPG Key ID: 69D9EED60B242822
2 changed files with 79 additions and 2 deletions

View File

@ -77,7 +77,7 @@ defmodule Amethyst.Minecraft.Read do
{[], binary} {[], binary}
end end
def bool({acc, <<value, rest::bitstring>>}) do def bool({acc, <<value, rest::binary>>}) do
{[value != 0 | acc], rest} {[value != 0 | acc], rest}
end end
@ -112,4 +112,42 @@ defmodule Amethyst.Minecraft.Read do
def double({acc, <<value::64-float-big, rest::binary>>}) do def double({acc, <<value::64-float-big, rest::binary>>}) do
{[value | acc], rest} {[value | acc], rest}
end end
def varint(tuple, read \\ 0, nacc \\ 0)
def varint({acc, <<1::1, value::7, rest::binary>>}, read, nacc) when read < 5 do
varint({acc, rest}, read + 1, nacc + (value <<< (7 * read)))
end
def varint({acc, <<0::1, value::7, rest::binary>>}, read, nacc) do
total = nacc + (value <<< (7 * read))
<<value::32-signed>> = <<total::32-unsigned>>
{[value | acc], rest}
end
def varint(_, read, _) when read >= 5 do
raise RuntimeError, "Got a varint which is too big!"
end
def varint({_, ""}, _, _) do
raise RuntimeError, "Got an incomplete varint!"
end
def varlong(tuple, read \\ 0, nacc \\ 0)
def varlong({acc, <<1::1, value::7, rest::binary>>}, read, nacc) when read < 10 do
varlong({acc, rest}, read + 1, nacc + (value <<< (7 * read)))
end
def varlong({acc, <<0::1, value::7, rest::binary>>}, read, nacc) do
total = nacc + (value <<< (7 * read))
<<value::64-signed>> = <<total::64-unsigned>>
{[value | acc], rest}
end
def varlong(_, read, _) when read >= 10 do
raise RuntimeError, "Got a varint which is too big!"
end
def varlong({_, ""}, _, _) do
raise RuntimeError, "Got an incomplete varint!"
end
def string({acc, data}) do
{[length], rest} = start(data) |> varint()
<<value::binary-size(length), rest::binary>> = rest
{[value | acc], rest}
end
end end

View File

@ -1,7 +1,11 @@
defmodule WriteTest do defmodule WriteTest do
use ExUnit.Case use ExUnit.Case
@moduledoc """
This module contains tests for the Amethyst.Minecraft.Write module.
"""
doctest Amethyst.Minecraft.Write doctest Amethyst.Minecraft.Write
doctest Amethyst.Minecraft.Read
test "writing a varint" do test "writing a varint" do
assert Amethyst.Minecraft.Write.varint(0) == <<0x00>> assert Amethyst.Minecraft.Write.varint(0) == <<0x00>>
@ -28,3 +32,38 @@ defmodule WriteTest do
assert Amethyst.Minecraft.Write.string("") == <<0x00>> assert Amethyst.Minecraft.Write.string("") == <<0x00>>
end end
end end
defmodule ReadTest do
use ExUnit.Case
@moduledoc """
This module contains tests for the Amethyst.Minecraft.Read module.
"""
doctest Amethyst.Minecraft.Read
test "reading a varint" do
assert Amethyst.Minecraft.Read.start(<<0x00>>) |> Amethyst.Minecraft.Read.varint() == {[0], ""}
assert Amethyst.Minecraft.Read.start(<<0x7F>>) |> Amethyst.Minecraft.Read.varint() == {[127], ""}
assert Amethyst.Minecraft.Read.start(<<0x80, 0x01>>) |> Amethyst.Minecraft.Read.varint() == {[128], ""}
assert Amethyst.Minecraft.Read.start(<<0xFF, 0x01>>) |> Amethyst.Minecraft.Read.varint() == {[255], ""}
assert Amethyst.Minecraft.Read.start(<<0xFF, 0xFF, 0xFF, 0xFF, 0x07>>) |> Amethyst.Minecraft.Read.varint() == {[2_147_483_647], ""}
assert Amethyst.Minecraft.Read.start(<<0xFF, 0xFF, 0xFF, 0xFF, 0x0F>>) |> Amethyst.Minecraft.Read.varint() == {[-1], ""}
assert Amethyst.Minecraft.Read.start(<<0x80, 0x80, 0x80, 0x80, 0x08>>) |> Amethyst.Minecraft.Read.varint() == {[-2_147_483_648], ""}
end
test "reading a varlong" do
assert Amethyst.Minecraft.Read.start(<<0x00>>) |> Amethyst.Minecraft.Read.varlong() == {[0], ""}
assert Amethyst.Minecraft.Read.start(<<0x7F>>) |> Amethyst.Minecraft.Read.varlong() == {[127], ""}
assert Amethyst.Minecraft.Read.start(<<0x80, 0x01>>) |> Amethyst.Minecraft.Read.varlong() == {[128], ""}
assert Amethyst.Minecraft.Read.start(<<0xFF, 0x01>>) |> Amethyst.Minecraft.Read.varlong() == {[255], ""}
assert Amethyst.Minecraft.Read.start(<<0xFF, 0xFF, 0xFF, 0xFF, 0x07>>) |> Amethyst.Minecraft.Read.varlong() == {[2_147_483_647], ""}
assert Amethyst.Minecraft.Read.start(<<0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F>>) |> Amethyst.Minecraft.Read.varlong() == {[9_223_372_036_854_775_807], ""}
assert Amethyst.Minecraft.Read.start(<<0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01>>) |> Amethyst.Minecraft.Read.varlong() == {[-1], ""}
end
test "reading a string" do
assert Amethyst.Minecraft.Read.start(<<0x0D, "Hello, world!">>) |> Amethyst.Minecraft.Read.string() == {["Hello, world!"], ""}
assert Amethyst.Minecraft.Read.start(<<0x00>>) |> Amethyst.Minecraft.Read.string() == {[""], ""}
end
end