Skip to content

Commit 74b6645

Browse files
committed
First commit
0 parents  commit 74b6645

File tree

9 files changed

+294
-0
lines changed

9 files changed

+294
-0
lines changed

.formatter.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
4+
]

.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# The directory Mix will write compiled artifacts to.
2+
/_build/
3+
4+
# If you run "mix test --cover", coverage assets end up here.
5+
/cover/
6+
7+
# The directory Mix downloads your dependencies sources to.
8+
/deps/
9+
10+
# Where third-party dependencies like ExDoc output generated docs.
11+
/doc/
12+
13+
# Ignore .fetch files in case you like to edit your project deps locally.
14+
/.fetch
15+
16+
# If the VM crashes, it generates a dump, let's ignore it too.
17+
erl_crash.dump
18+
19+
# Also ignore archive artifacts (built via "mix archive.build").
20+
*.ez
21+
22+
# Ignore package tarball (built via "mix hex.build").
23+
binary_reader-*.tar
24+

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# BinaryReader
2+
3+
A Elixir Binary Reader that running with side effects.
4+
5+
## Installation
6+
7+
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
8+
by adding `binary_reader` to your list of dependencies in `mix.exs`:
9+
10+
```elixir
11+
def deps do
12+
[
13+
{:binary_reader, "~> 0.1.0"}
14+
]
15+
end
16+
```
17+
18+
## Usage
19+
20+
### Normal Usage
21+
```elixir
22+
iex> {:ok, pid} = BinaryReader.start_link(<<65, 66, 67, 68, 2, 0, 0, 0>>)
23+
{:ok, #PID<0.0.0>}
24+
iex> BinaryReader.read_string(pid)
25+
"ABCD"
26+
iex> BinaryReader.remains_byte_size(pid)
27+
4
28+
iex> BinaryReader.read_int32(pid)
29+
2
30+
iex> BinaryReader.stop(pid)
31+
:ok
32+
```
33+
34+
### Extend BinaryReader
35+
```elixir
36+
defmodule SpecialBinaryReader do
37+
use BinaryReader
38+
39+
def special_read(pid) do
40+
length = read_int32(pid)
41+
read_bytes(pid, length)
42+
end
43+
end
44+
45+
iex> {:ok, pid} = SpecialBinaryReader.start_link(<<.....>>)
46+
iex> SpecialBinaryReader.special_read(pid)
47+
```

lib/binary_reader.ex

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
defmodule BinaryReader do
2+
@moduledoc """
3+
Warning: This module has side effects.
4+
5+
a_int = BinaryReader.read_int32(pid)
6+
7+
Each action like this will cost a side effect, chaging the binary content that inputed initailly.
8+
Be careful to use it according to your needs.
9+
"""
10+
alias BinaryReader.Server
11+
12+
defmacro __using__(_opt) do
13+
quote do
14+
import BinaryReader
15+
end
16+
end
17+
18+
@doc """
19+
Start the GenServer
20+
"""
21+
@spec start_link(binary()) :: {:ok, pid()}
22+
def start_link(content) do
23+
GenServer.start_link(Server, content)
24+
end
25+
26+
@doc """
27+
Stop the GenServer
28+
"""
29+
@spec stop(pid()) :: :ok
30+
def stop(pid), do: GenServer.stop(pid, :normal)
31+
32+
@doc """
33+
Read one byte
34+
"""
35+
@spec read_byte(pid()) :: binary()
36+
def read_byte(pid), do: read_bytes(pid, 1)
37+
38+
@doc """
39+
Read number of bytes
40+
"""
41+
@spec read_bytes(pid(), integer()) :: binary()
42+
def read_bytes(pid, size) when is_integer(size) do
43+
GenServer.call(pid, {:read_bytes, size})
44+
end
45+
46+
@doc """
47+
Read 8 bytes for int64
48+
"""
49+
@spec read_int64(pid()) :: integer()
50+
def read_int64(pid), do: GenServer.call(pid, :read_int64)
51+
52+
@doc """
53+
Read 4 bytes for int32
54+
"""
55+
@spec read_int32(pid()) :: integer()
56+
def read_int32(pid), do: GenServer.call(pid, :read_int32)
57+
58+
@doc """
59+
Read 2 bytes for int16
60+
"""
61+
@spec read_int16(pid()) :: integer()
62+
def read_int16(pid), do: GenServer.call(pid, :read_int16)
63+
64+
@doc """
65+
Read 4 bytes for string
66+
"""
67+
@spec read_string(pid()) :: String.t()
68+
def read_string(pid), do: GenServer.call(pid, :read_string)
69+
70+
@doc """
71+
Return remains size of bytes
72+
"""
73+
@spec remains_byte_size(pid()) :: binary()
74+
def remains_byte_size(pid), do: GenServer.call(pid, :remains)
75+
76+
@doc """
77+
Move the reading pivot to certain index
78+
"""
79+
@spec move_pivot_to(pid(), integer()) :: :ok
80+
def move_pivot_to(pid, index) when is_integer(index) do
81+
GenServer.call(pid, {:move_pivot_to, index})
82+
end
83+
84+
end

lib/binary_reader/server.ex

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
defmodule BinaryReader.Server do
2+
use GenServer
3+
4+
@impl true
5+
def init(content) do
6+
{:ok, content}
7+
end
8+
9+
@impl true
10+
def handle_call({:read_bytes, size}, _from, content) do
11+
<<head::binary-size(size), rest::binary>> = content
12+
{:reply, head, rest}
13+
end
14+
15+
@impl true
16+
def handle_call(:read_int64, _from, content) do
17+
<<head::binary-size(8), rest::binary>> = content
18+
<<int64::little-signed-integer-size(64)>> = head
19+
20+
{:reply, int64, rest}
21+
end
22+
23+
@impl true
24+
def handle_call(:read_int32, _from, content) do
25+
<<head::binary-size(4), rest::binary>> = content
26+
<<int32::little-signed-integer-size(32)>> = head
27+
28+
{:reply, int32, rest}
29+
end
30+
31+
@impl true
32+
def handle_call(:read_int16, _from, content) do
33+
<<head::binary-size(2), rest::binary>> = content
34+
<<int32::little-signed-integer-size(16)>> = head
35+
36+
{:reply, int32, rest}
37+
end
38+
39+
@impl true
40+
def handle_call(:read_string, _from, content) do
41+
<<head::binary-size(4), rest::binary>> = content
42+
43+
string = head
44+
|> :binary.bin_to_list()
45+
|> to_string()
46+
47+
{:reply, string, rest}
48+
end
49+
50+
@impl true
51+
def handle_call({:move_pivot_to, index}, _from, content) do
52+
<<_head::binary-size(index), rest::binary>> = content
53+
{:reply, :ok, rest}
54+
end
55+
56+
@impl true
57+
def handle_call(:remains_byte_size, _from, content) do
58+
{:reply, byte_size(content), content}
59+
end
60+
61+
end

mix.exs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
defmodule BinaryReader.MixProject do
2+
use Mix.Project
3+
4+
def project do
5+
[
6+
app: :binary_reader,
7+
version: "0.1.0",
8+
elixir: "~> 1.10",
9+
start_permanent: Mix.env() == :prod,
10+
deps: deps()
11+
]
12+
end
13+
14+
# Run "mix help compile.app" to learn about applications.
15+
def application do
16+
[
17+
extra_applications: [:logger]
18+
]
19+
end
20+
21+
# Run "mix help deps" to learn about dependencies.
22+
defp deps do
23+
[
24+
# {:dep_from_hexpm, "~> 0.3.0"},
25+
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
26+
]
27+
end
28+
end

test/binary_reader_test.exs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
defmodule BinaryReaderTest do
2+
use ExUnit.Case, async: true
3+
@moduledoc"""
4+
<<
5+
71, 86, 65, 83, # string
6+
2, 0, 0, 0, # int32
7+
5, 2, 0, 0, # int32
8+
4, 0, # int16
9+
22, 0, # int16
10+
3, 0,
11+
0, 0, 0, 0,
12+
19, 0, 0, 0,
13+
43, 43, 85, 69, 52, 43, 82, 101, 108, 101, 97, 115, 101, 45, 52, 46, 50....
14+
"""
15+
16+
setup_all do
17+
file = Path.relative("test/fixtures/test.binary")
18+
{:ok, content} = File.read(file)
19+
{:ok, pid} = BinaryReader.start_link(content)
20+
{:ok, pid: pid}
21+
end
22+
23+
test "read string", %{pid: pid} do
24+
assert "GVAS" == BinaryReader.read_string(pid)
25+
end
26+
27+
test "read int32", %{pid: pid} do
28+
assert 2 == BinaryReader.read_int32(pid)
29+
assert 517 == BinaryReader.read_int32(pid)
30+
end
31+
32+
test "read int16", %{pid: pid} do
33+
assert 4 == BinaryReader.read_int16(pid)
34+
end
35+
36+
test "read bytes", %{pid: pid} do
37+
assert <<22, 0>> == BinaryReader.read_bytes(pid, 2)
38+
end
39+
40+
test "stop", %{pid: pid} do
41+
assert :ok == BinaryReader.stop(pid)
42+
end
43+
44+
end

test/fixtures/test.binary

154 KB
Binary file not shown.

test/test_helper.exs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ExUnit.configure seed: 0
2+
ExUnit.start()

0 commit comments

Comments
 (0)