You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2019/11/19 18:23:12 UTC

[couchdb-thrift-protocol] branch master created (now 1c86c26)

This is an automated email from the ASF dual-hosted git repository.

davisp pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git.


      at 1c86c26  v0.1.3

This branch includes the following new commits:

     new 10f29d1  Initial commit
     new 1a7bc50  Add `decode_message` for binary format
     new 69a661b  Add test for `thrift_protocol_binary` module
     new 98734e7  Add `thrift_protocol_compact` module
     new 4e8a794  Set default values
     new 5f02bba  Add .travis.yml
     new 4802b2d  Update .travis.yml
     new 69be7e9  Update .travis.yml
     new 8b26cc2  Add covertool
     new 337c263  Add documentation
     new cfbe8dc  Update thrift_protocol.app.src
     new 5532c18  Update README.md
     new 811b3d3  Remove parameterized types
     new 2ee78cb  version bump
     new 85df07b  Use little-endian in compact-encoding
     new 4bb0071  version bump
     new 6474da8  Update .travis.yml
     new 9b9b92f  Update rebar.config
     new 1c86c26  v0.1.3

The 19 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[couchdb-thrift-protocol] 18/19: Update rebar.config

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 9b9b92f3ae9e58b4baadcadc430e130a221a385d
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Tue Dec 25 23:18:35 2018 +0900

    Update rebar.config
---
 rebar.config | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/rebar.config b/rebar.config
index 50acdc0..6f806ec 100644
--- a/rebar.config
+++ b/rebar.config
@@ -27,8 +27,6 @@
 
 {shell, [{apps, [thrift_protocol]}]}.
 
-{plugins, [rebar_covertool]}.
-
 {dialyzer,
  [
   {warnings, [error_handling, race_conditions, unmatched_returns, unknown, no_improper_lists]}
@@ -37,3 +35,11 @@
 {deps,
  [
  ]}.
+
+{profiles,
+ [
+  {test,
+   [
+    {plugins, [covertool]}
+   ]}
+ ]}.


[couchdb-thrift-protocol] 15/19: Use little-endian in compact-encoding

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 85df07b68bd28de8967a92ffb192890aecb657f1
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 22:55:56 2017 +0900

    Use little-endian in compact-encoding
---
 src/thrift_protocol_compact.erl        | 12 ++++++++++--
 test/thrift_protocol_binary_tests.erl  | 10 ++++++++++
 test/thrift_protocol_compact_tests.erl |  9 +++++++++
 3 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/src/thrift_protocol_compact.erl b/src/thrift_protocol_compact.erl
index 5641530..4d12e81 100644
--- a/src/thrift_protocol_compact.erl
+++ b/src/thrift_protocol_compact.erl
@@ -1,4 +1,12 @@
 %% @private
+%%
+%% === NOTE ===
+%%
+%% The specification says "We are using big-endian",
+%% but actually, implementations are using little-endian.
+%%
+%% - Specification: https://github.com/apache/thrift/blob/8b8a8efea13d1c97f856053af0a5c0e6a8a76354/doc/specs/thrift-compact-protocol.md
+%% - Java Implementation: https://github.com/apache/thrift/blob/8b8a8efea13d1c97f856053af0a5c0e6a8a76354/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java#L466
 -module(thrift_protocol_compact).
 
 -include("thrift_protocol.hrl").
@@ -80,7 +88,7 @@ encode_data({i8, N}) -> <<N:8>>;
 encode_data({i16, N}) -> encode_data({i32, N});
 encode_data({i32, N}) -> encode_varint32(int32_to_zigzag(N));
 encode_data({i64, N}) -> encode_varint64(int64_to_zigzag(N));
-encode_data(N) when is_float(N) -> <<N/float>>;
+encode_data(N) when is_float(N) -> <<N/float-little>>;
 encode_data(B) when is_binary(B) -> encode_binary(B);
 encode_data(X = #thrift_protocol_struct{}) -> encode_struct(X);
 encode_data(#thrift_protocol_map{elements = M}) when M =:= #{} ->
@@ -186,7 +194,7 @@ decode_data(Bin0, i32) ->
 decode_data(Bin0, i64) ->
     {N, Bin1} = decode_varint64(Bin0),
     {{i64, zigzag_to_int(N)}, Bin1};
-decode_data(<<N/float, Bin/binary>>, float) ->
+decode_data(<<N/float-little, Bin/binary>>, float) ->
     {N, Bin};
 decode_data(Bin0, binary) ->
     {Size, Bin1} = decode_varint32(Bin0),
diff --git a/test/thrift_protocol_binary_tests.erl b/test/thrift_protocol_binary_tests.erl
index fe97d89..716bb4e 100644
--- a/test/thrift_protocol_binary_tests.erl
+++ b/test/thrift_protocol_binary_tests.erl
@@ -15,6 +15,16 @@ encode_test() ->
     ?assertEqual(lists:sort(binary_to_list(bytes())),
                  lists:sort(binary_to_list(list_to_binary(Bytes)))).
 
+float_test() ->
+    Message = #thrift_protocol_message{method_name = <<"foo">>, message_type = call, sequence_id = 1000,
+                                       body = #thrift_protocol_struct{fields = #{1 => 123.456}}},
+    Encoded = list_to_binary(thrift_protocol_binary:encode_message(Message)),
+    ?assertEqual(<<128,1,0,1,0,0,0,3,102,111,111,0,0,3,232,4,0,1,64,94,221,47,26,159,190,119,0>>,
+                 Encoded),
+
+    {Decoded, <<>>} = thrift_protocol_binary:decode_message(Encoded),
+    ?assertEqual(Message, Decoded).
+
 -spec bytes() -> binary().
 bytes() ->
     <<128,1,0,4,0,0,0,9,101,109,105,116,66,97,116,99,104,0,0,0,1, 12,
diff --git a/test/thrift_protocol_compact_tests.erl b/test/thrift_protocol_compact_tests.erl
index 4824ef4..3b2960c 100644
--- a/test/thrift_protocol_compact_tests.erl
+++ b/test/thrift_protocol_compact_tests.erl
@@ -15,6 +15,15 @@ encode_test() ->
     ?assertEqual(lists:sort(binary_to_list(bytes())),
                  lists:sort(binary_to_list(list_to_binary(Bytes)))).
 
+float_test() ->
+    Message = #thrift_protocol_message{method_name = <<"foo">>, message_type = call, sequence_id = 1000,
+                                       body = #thrift_protocol_struct{fields = #{1 => 123.456}}},
+    Encoded = list_to_binary(thrift_protocol_compact:encode_message(Message)),
+    ?assertEqual(<<130,33,232,7,3,102,111,111,23,119,190,159,26,47,221,94,64,0>>, Encoded),
+
+    {Decoded, <<>>} = thrift_protocol_compact:decode_message(Encoded),
+    ?assertEqual(Message, Decoded).
+
 -spec bytes() -> binary().
 bytes() ->
     <<130,129,1,9,101,109,105,116,66,97,116,99,104,28,28,24,11,102,


[couchdb-thrift-protocol] 19/19: v0.1.3

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 1c86c2695ece2de8828e41d73325ff12b3d06adf
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Tue Dec 25 23:26:51 2018 +0900

    v0.1.3
---
 src/thrift_protocol.app.src | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/thrift_protocol.app.src b/src/thrift_protocol.app.src
index 7fbf021..1c7896a 100644
--- a/src/thrift_protocol.app.src
+++ b/src/thrift_protocol.app.src
@@ -1,6 +1,6 @@
 {application,thrift_protocol,
              [{description,"An Erlang implementation of Thrift protocol."},
-              {vsn,"0.1.2"},
+              {vsn,"0.1.3"},
               {registered,[]},
               {applications,[kernel,stdlib]},
               {env,[]},


[couchdb-thrift-protocol] 14/19: version bump

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 2ee78cb1d0cd88b75e472a2546954ce6f0a8f6be
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 05:22:07 2017 +0900

    version bump
---
 src/thrift_protocol.app.src | 25 ++++++++++---------------
 1 file changed, 10 insertions(+), 15 deletions(-)

diff --git a/src/thrift_protocol.app.src b/src/thrift_protocol.app.src
index 19544cb..4414762 100644
--- a/src/thrift_protocol.app.src
+++ b/src/thrift_protocol.app.src
@@ -1,15 +1,10 @@
-{application, thrift_protocol,
- [{description, "An Erlang implementation of Thrift protocol."},
-  {vsn, "0.1.0"},
-  {registered, []},
-  {applications,
-   [kernel,
-    stdlib
-   ]},
-  {env,[]},
-  {modules, []},
-
-  {maintainers, ["Takeru Ohta"]},
-  {licenses, ["MIT"]},
-  {links, [{"GitHub","https://github.com/sile/thrift_protocol"}]}
- ]}.
+{application,thrift_protocol,
+             [{description,"An Erlang implementation of Thrift protocol."},
+              {vsn,"0.1.1"},
+              {registered,[]},
+              {applications,[kernel,stdlib]},
+              {env,[]},
+              {modules,[]},
+              {maintainers,["Takeru Ohta"]},
+              {licenses,["MIT"]},
+              {links,[{"GitHub","https://github.com/sile/thrift_protocol"}]}]}.


[couchdb-thrift-protocol] 09/19: Add covertool

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 8b26cc2ddf2eb8a8596ca059853c2d196ceefaca
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 01:00:53 2017 +0900

    Add covertool
---
 .travis.yml  | 3 +++
 rebar.config | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/.travis.yml b/.travis.yml
index 0f5fbfd..92a44f7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,6 +16,9 @@ script:
   - ./rebar3 eunit
   - ./rebar3 dialyzer
   - ./rebar3 edoc
+  - ./rebar3 cover
+  - ./rebar3 covertool generate
+  - cp _build/test/covertool/thrift_protocol.covertool.xml ./cobertura.xml
 
 after_success:
   - codecov
diff --git a/rebar.config b/rebar.config
index a1eda38..50acdc0 100644
--- a/rebar.config
+++ b/rebar.config
@@ -27,6 +27,8 @@
 
 {shell, [{apps, [thrift_protocol]}]}.
 
+{plugins, [rebar_covertool]}.
+
 {dialyzer,
  [
   {warnings, [error_handling, race_conditions, unmatched_returns, unknown, no_improper_lists]}


[couchdb-thrift-protocol] 07/19: Update .travis.yml

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 4802b2dde0c22796ebb8d6eccefba2f723ab8735
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 00:26:08 2017 +0900

    Update .travis.yml
---
 .travis.yml | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index a6f6418..92a44f7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,5 @@
 language: erlang
 
-sudo: false
 os: linux
 otp_release:
   - 20.0
@@ -10,13 +9,16 @@ otp_release:
 script: rebar3 eunit
 install:
   - wget https://s3.amazonaws.com/rebar3/rebar3 && chmod +x rebar3
-  - pip install codecov
+  - sudo pip install codecov
 script:
   - ./rebar3 compile
   - ./rebar3 xref
   - ./rebar3 eunit
   - ./rebar3 dialyzer
   - ./rebar3 edoc
+  - ./rebar3 cover
+  - ./rebar3 covertool generate
+  - cp _build/test/covertool/thrift_protocol.covertool.xml ./cobertura.xml
 
 after_success:
   - codecov


[couchdb-thrift-protocol] 01/19: Initial commit

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 10f29d1071e5c47f3ceb408bd67f936ef201d177
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Wed Oct 18 03:26:38 2017 +0900

    Initial commit
---
 .gitignore                     | 18 +++++++++
 LICENSE                        | 21 +++++++++++
 README.md                      |  9 +++++
 include/thrift_protocol.hrl    | 31 ++++++++++++++++
 rebar.config                   | 37 +++++++++++++++++++
 rebar.lock                     |  1 +
 src/constants.hrl              | 16 ++++++++
 src/thrift_protocol.app.src    | 15 ++++++++
 src/thrift_protocol.erl        | 82 +++++++++++++++++++++++++++++++++++++++++
 src/thrift_protocol_binary.erl | 84 ++++++++++++++++++++++++++++++++++++++++++
 10 files changed, 314 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..40ca652
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+.rebar3
+_*
+.eunit
+*.o
+*.beam
+*.plt
+*.swp
+*.swo
+.erlang.cookie
+ebin
+log
+erl_crash.dump
+.rebar
+logs
+_build
+.idea
+*.iml
+rebar3.crashdump
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..5f58f62
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2017 Takeru Ohta <ph...@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..52350e6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+thrift_protocol
+=====
+
+An OTP library
+
+Build
+-----
+
+    $ rebar3 compile
diff --git a/include/thrift_protocol.hrl b/include/thrift_protocol.hrl
new file mode 100644
index 0000000..327a25b
--- /dev/null
+++ b/include/thrift_protocol.hrl
@@ -0,0 +1,31 @@
+-record(thrift_protocol_message,
+        {
+          method_name  :: binary(),
+          message_type :: thrift_protocol:message_type(),
+          sequence_id  :: integer(),
+          body         :: thrift_protocol:struct()
+        }).
+
+-record(thrift_protocol_struct,
+        {
+          fields :: #{thrift_protocol:field_id() => thrift_protocol:data()}
+        }).
+
+-record(thrift_protocol_map,
+        {
+          key_type   :: thrift_protocol:data_type() | undefined,
+          value_type :: thrift_protocol:data_type() | undefined,
+          elements   :: #{thrift_protocol:data() => thrift_protocol:data()}
+        }).
+
+-record(thrift_protocol_set,
+        {
+          element_type :: thrift_protocol:data_type(),
+          elements     :: [thrift_protocol:data()]
+        }).
+
+-record(thrift_protocol_list,
+        {
+          element_type :: thrift_protocol:data_type(),
+          elements     :: [thrift_protocol:data()]
+        }).
diff --git a/rebar.config b/rebar.config
new file mode 100644
index 0000000..a1eda38
--- /dev/null
+++ b/rebar.config
@@ -0,0 +1,37 @@
+%% -*- erlang -*-
+{erl_opts,
+ [
+  warnings_as_errors,
+  warn_export_all,
+  warn_untyped_record,
+  debug_info
+ ]}.
+
+{xref_checks,
+ [
+  fail_on_warning,
+  undefined_function_calls
+ ]}.
+
+{cover_enabled, true}.
+
+{edoc_opts,
+ [
+  {dialyzer_specs, all},
+  {report_missing_type, true},
+  {report_type_mismatch, true},
+  {pretty_print, erl_pp},
+  {preprocess, true}
+ ]}.
+{validate_app_modules, true}.
+
+{shell, [{apps, [thrift_protocol]}]}.
+
+{dialyzer,
+ [
+  {warnings, [error_handling, race_conditions, unmatched_returns, unknown, no_improper_lists]}
+ ]}.
+
+{deps,
+ [
+ ]}.
diff --git a/rebar.lock b/rebar.lock
new file mode 100644
index 0000000..57afcca
--- /dev/null
+++ b/rebar.lock
@@ -0,0 +1 @@
+[].
diff --git a/src/constants.hrl b/src/constants.hrl
new file mode 100644
index 0000000..2306751
--- /dev/null
+++ b/src/constants.hrl
@@ -0,0 +1,16 @@
+-define(MESSAGE_TYPE_CALL, 1).
+-define(MESSAGE_TYPE_REPLY, 2).
+-define(MESSAGE_TYPE_EXCEPTION, 3).
+-define(MESSAGE_TYPE_ONEWAY, 4).
+
+-define(DATA_TYPE_BOOLEAN, 2).
+-define(DATA_TYPE_I8, 3).
+-define(DATA_TYPE_I16, 6).
+-define(DATA_TYPE_I32, 8).
+-define(DATA_TYPE_I64, 10).
+-define(DATA_TYPE_FLOAT, 4).
+-define(DATA_TYPE_BINARY, 11).
+-define(DATA_TYPE_STRUCT, 12).
+-define(DATA_TYPE_MAP, 13).
+-define(DATA_TYPE_SET, 14).
+-define(DATA_TYPE_LIST, 15).
diff --git a/src/thrift_protocol.app.src b/src/thrift_protocol.app.src
new file mode 100644
index 0000000..dfb0c68
--- /dev/null
+++ b/src/thrift_protocol.app.src
@@ -0,0 +1,15 @@
+{application, thrift_protocol,
+ [{description, "An OTP library"},
+  {vsn, "0.1.0"},
+  {registered, []},
+  {applications,
+   [kernel,
+    stdlib
+   ]},
+  {env,[]},
+  {modules, []},
+
+  {maintainers, []},
+  {licenses, ["MIT"]},
+  {links, []}
+ ]}.
diff --git a/src/thrift_protocol.erl b/src/thrift_protocol.erl
new file mode 100644
index 0000000..9a5b5cf
--- /dev/null
+++ b/src/thrift_protocol.erl
@@ -0,0 +1,82 @@
+-module(thrift_protocol).
+
+-include("thrift_protocol.hrl").
+
+-export([encode_message/2]).
+-export([data_type/1]).
+
+-export_type([message/0, message_type/0, struct/0]).
+-export_type([field_id/0, data/0, data_type/0]).
+-export_type([thrift_map/0, thrift_list/0, set/0]).
+-export_type([format/0, i8/0, i16/0, i32/0, i64/0]).
+
+-type format() :: binary | compact.
+
+-type message() :: #thrift_protocol_message{}.
+
+-type message_type() :: call | reply | exception | oneway.
+
+-type struct() :: #thrift_protocol_struct{}.
+-type thrift_map() :: #thrift_protocol_map{}.
+-type thrift_list() :: #thrift_protocol_list{}.
+-type set() :: #thrift_protocol_set{}.
+
+-type field_id() :: integer().
+-type i8() :: {i8, integer()}.
+-type i16() :: {i16, integer()}.
+-type i32() :: {i32, integer()}.
+-type i64() :: {i64, integer()}.
+
+-type data_type() :: boolean
+                   | i8
+                   | i16
+                   | i32
+                   | i64
+                   | float
+                   | binary
+                   | struct
+                   | map
+                   | set
+                   | list.
+
+-type data() :: boolean()
+              | i8()
+              | i16()
+              | i32()
+              | i64()
+              | float()
+              | binary()
+              | struct()
+              | thrift_map()
+              | set()
+              | thrift_list().
+
+-spec encode_message(message(), format()) -> iodata().
+encode_message(Message, binary) ->
+    thrift_protocol_binary:encode_message(Message);
+encode_message(Message, compact) ->
+    thrift_protocol_compact:encode_message(Message).
+
+-spec data_type(data()) -> data_type().
+data_type(X) when is_boolean(X) ->
+    boolean;
+data_type({i8, _}) ->
+    i8;
+data_type({i16, _}) ->
+    i16;
+data_type({i32, _}) ->
+    i32;
+data_type({i64, _}) ->
+    i64;
+data_type(X) when is_float(X) ->
+    float;
+data_type(X) when is_binary(X) ->
+    binary;
+data_type(#thrift_protocol_struct{}) ->
+    struct;
+data_type(#thrift_protocol_map{}) ->
+    map;
+data_type(#thrift_protocol_set{}) ->
+    set;
+data_type(#thrift_protocol_list{}) ->
+    list.
diff --git a/src/thrift_protocol_binary.erl b/src/thrift_protocol_binary.erl
new file mode 100644
index 0000000..c4edaa9
--- /dev/null
+++ b/src/thrift_protocol_binary.erl
@@ -0,0 +1,84 @@
+-module(thrift_protocol_binary).
+
+-include("thrift_protocol.hrl").
+-include("constants.hrl").
+
+-export([encode_message/1]).
+
+-define(VERSION, 1).
+
+-spec encode_message(thrift_protocol:message()) -> iodata().
+encode_message(Message) ->
+    #thrift_protocol_message{method_name = Name, sequence_id = SeqId, body = Body} = Message,
+    Type =
+        case Message#thrift_protocol_message.message_type of
+            call      -> ?MESSAGE_TYPE_CALL;
+            reply     -> ?MESSAGE_TYPE_REPLY;
+            exception -> ?MESSAGE_TYPE_EXCEPTION;
+            oneway    -> ?MESSAGE_TYPE_ONEWAY
+        end,
+    [<<1:1, ?VERSION:15, 0:8, 0:5, Type:3, (byte_size(Name)):32, Name/binary, SeqId:32>> | encode_data(Body)].
+
+-spec encode_data(thrift_protocol:data()) -> iodata().
+encode_data(true) ->
+    <<1:8>>;
+encode_data(false) ->
+    <<0:8>>;
+encode_data({i8, N}) ->
+    <<N:8>>;
+encode_data({i16, N}) ->
+    <<N:16>>;
+encode_data({i32, N}) ->
+    <<N:32>>;
+encode_data({i64, N}) ->
+    <<N:64>>;
+encode_data(N) when is_float(N)->
+    <<N/float>>;
+encode_data(B) when is_binary(B) ->
+    [<<(byte_size(B)):32>> | B];
+encode_data(#thrift_protocol_struct{fields = Fields}) ->
+    maps:fold(
+      fun (Id, Data, Acc) ->
+              Type = data_type_to_byte(thrift_protocol:data_type(Data)),
+              [<<Type:8, Id:32>>, encode_data(Data) | Acc]
+      end,
+      [<<0:32>>],
+      Fields);
+encode_data(#thrift_protocol_map{key_type = KeyType, value_type = ValueType, elements = Elements}) ->
+    IoData =
+        maps:fold(
+          fun (K, V, Acc) ->
+                  KeyType = thrift_protocol:data_type(K),
+                  ValueType = thrift_protocol:data_type(V),
+                  [encode_data(K), encode_data(V) | Acc]
+          end,
+          [],
+          Elements),
+    [<<(data_type_to_byte(KeyType)):8, (data_type_to_byte(ValueType)):8, (maps:size(Elements)):32>> | IoData];
+encode_data(#thrift_protocol_set{element_type = Type, elements = Elements}) ->
+    Size = length(Elements),
+    [<<(data_type_to_byte(Type)):8, Size:32>> |
+     [begin
+          Type = thrift_protocol:data_type(E),
+          encode_data(E)
+      end || E <- Elements]];
+encode_data(#thrift_protocol_list{element_type = Type, elements = Elements}) ->
+    Size = length(Elements),
+    [<<(data_type_to_byte(Type)):8, Size:32>> |
+     [begin
+          Type = thrift_protocol:data_type(E),
+          encode_data(E)
+      end || E <- Elements]].
+
+-spec data_type_to_byte(thrift_protocol:data_type()) -> byte().
+data_type_to_byte(boolean) -> ?DATA_TYPE_BOOLEAN;
+data_type_to_byte(i8)      -> ?DATA_TYPE_I8;
+data_type_to_byte(i16)     -> ?DATA_TYPE_I16;
+data_type_to_byte(i32)     -> ?DATA_TYPE_I32;
+data_type_to_byte(i64)     -> ?DATA_TYPE_I64;
+data_type_to_byte(float)   -> ?DATA_TYPE_FLOAT;
+data_type_to_byte(binary)  -> ?DATA_TYPE_BINARY;
+data_type_to_byte(struct)  -> ?DATA_TYPE_STRUCT;
+data_type_to_byte(map)     -> ?DATA_TYPE_MAP;
+data_type_to_byte(set)     -> ?DATA_TYPE_SET;
+data_type_to_byte(list)    -> ?DATA_TYPE_LIST.


[couchdb-thrift-protocol] 13/19: Remove parameterized types

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 811b3d3db22fbcd40f1f5221f30d89e169f85fad
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 05:21:24 2017 +0900

    Remove parameterized types
---
 src/thrift_protocol.erl | 20 ++++----------------
 1 file changed, 4 insertions(+), 16 deletions(-)

diff --git a/src/thrift_protocol.erl b/src/thrift_protocol.erl
index ac01bbe..4c80023 100644
--- a/src/thrift_protocol.erl
+++ b/src/thrift_protocol.erl
@@ -38,10 +38,10 @@
 
 -export_type([message/0, message_type/0]).
 -export_type([data/0, data_type/0]).
--export_type([struct/0, struct/1, field_id/0]).
--export_type([thrift_map/0, thrift_map/2]).
--export_type([thrift_list/0, thrift_list/1]).
--export_type([set/0, set/1]).
+-export_type([struct/0, field_id/0]).
+-export_type([thrift_map/0]).
+-export_type([thrift_list/0]).
+-export_type([set/0]).
 -export_type([i8/0, i16/0, i32/0, i64/0]).
 -export_type([format/0]).
 
@@ -57,30 +57,18 @@
 -type struct() :: #thrift_protocol_struct{}.
 %% Struct.
 
--type struct(Fields) :: #thrift_protocol_struct{fields :: Fields}.
-%% Struct.
-
 -type field_id() :: integer().
 %% The identifier of a struct field (16-bit signed integer).
 
 -type thrift_map() :: #thrift_protocol_map{}.
 %% Map.
 
--type thrift_map(KeyType, ValueType) :: #thrift_protocol_map{key_type :: KeyType, value_type :: ValueType}.
-%% Map.
-
 -type thrift_list() :: #thrift_protocol_list{}.
 %% List.
 
--type thrift_list(ElementType) :: #thrift_protocol_list{element_type :: ElementType}.
-%% List
-
 -type set() :: #thrift_protocol_set{}.
 %% Set.
 
--type set(ElementType) :: #thrift_protocol_set{element_type :: ElementType}.
-%% Set.
-
 -type i8() :: {i8, integer()}.
 %% 8-bit signed integer.
 


[couchdb-thrift-protocol] 02/19: Add `decode_message` for binary format

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 1a7bc50f257b3b06755ab08035138b17e751da5d
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Wed Oct 18 06:55:54 2017 +0900

    Add `decode_message` for binary format
---
 src/thrift_protocol.erl        |   8 ++-
 src/thrift_protocol_binary.erl | 122 +++++++++++++++++++++++++++++------------
 src/thrift_protocol_byte.erl   |  44 +++++++++++++++
 3 files changed, 139 insertions(+), 35 deletions(-)

diff --git a/src/thrift_protocol.erl b/src/thrift_protocol.erl
index 9a5b5cf..3b59cfb 100644
--- a/src/thrift_protocol.erl
+++ b/src/thrift_protocol.erl
@@ -2,7 +2,7 @@
 
 -include("thrift_protocol.hrl").
 
--export([encode_message/2]).
+-export([encode_message/2, decode_message/2]).
 -export([data_type/1]).
 
 -export_type([message/0, message_type/0, struct/0]).
@@ -57,6 +57,12 @@ encode_message(Message, binary) ->
 encode_message(Message, compact) ->
     thrift_protocol_compact:encode_message(Message).
 
+-spec decode_message(binary(), format()) -> {message(), binary()}.
+decode_message(Bin, binary) ->
+    thrift_protocol_binary:decode_message(Bin);
+decode_message(Bin, compact) ->
+    thrift_protocol_compact:decode_message(Bin).
+
 -spec data_type(data()) -> data_type().
 data_type(X) when is_boolean(X) ->
     boolean;
diff --git a/src/thrift_protocol_binary.erl b/src/thrift_protocol_binary.erl
index c4edaa9..0bccf20 100644
--- a/src/thrift_protocol_binary.erl
+++ b/src/thrift_protocol_binary.erl
@@ -1,23 +1,94 @@
 -module(thrift_protocol_binary).
 
 -include("thrift_protocol.hrl").
--include("constants.hrl").
 
--export([encode_message/1]).
+-export([encode_message/1, decode_message/1]).
 
 -define(VERSION, 1).
 
+-spec decode_message(binary()) -> {thrift_protocol:message(), binary()}.
+decode_message(<<1:1, ?VERSION:15, _:8, 0:5, TypeByte:3, NameLen:32, Name:NameLen/binary, SeqId:32/signed, Rest0/binary>>) ->
+    Type = thrift_protocol_byte:to_message_type(TypeByte),
+    {Body, Rest1} = decode_struct(Rest0, #{}),
+    Message =
+        #thrift_protocol_message{
+           method_name = Name,
+           message_type = Type,
+           sequence_id = SeqId,
+           body = Body
+          },
+    {Message, Rest1}.
+
+-spec decode_struct(binary(), Fields) -> {thrift_protocol:struct(), binary()} when
+      Fields :: #{thrift_protocol:field_id() => thrift_protocol:data()}.
+decode_struct(<<0:32, Rest/binary>>, Fields) ->
+    {#thrift_protocol_struct{fields = Fields}, Rest};
+decode_struct(<<TypeByte:8, Id:16/signed, Rest0/binary>>, Fields0) ->
+    Type = thrift_protocol_struct:to_data_type(TypeByte),
+    {Data, Rest1} = decode_data(Type, Rest0),
+    Fields1 = maps:put(Id, Data, Fields0),
+    decode_struct(Rest1, Fields1).
+
+-spec decode_elements(binary(), thrift_protocol:data_type(), non_neg_integer(), [thrift_protocol:data()]) ->
+                             {[thrift_protocol:data()], binary()}.
+decode_elements(Bin, _Type, 0, Elements) ->
+    {lists:reverse(Elements), Bin};
+decode_elements(Bin, Type, Size, Elements) ->
+    {Element, Rest} = decode_data(Type, Bin),
+    decode_elements(Rest, Type, Size - 1, [Element | Elements]).
+
+-spec decode_pairs(binary(), KeyType, ValueType, Size, Acc) -> {Acc, binary()} when
+      KeyType :: thrift_protocol:data_type(),
+      ValueType :: thrift_protocol:data_type(),
+      Size :: non_neg_integer(),
+      Acc :: #{thrift_protocol:data() => thrift_protocol:data()}.
+decode_pairs(Bin, _, _, 0, Pairs) ->
+    {Pairs, Bin};
+decode_pairs(Bin, KeyType, ValueType, Size, Pairs0) ->
+    {Key, Rest0} = decode_data(KeyType, Bin),
+    {Value, Rest1} = decode_data(ValueType, Rest0),
+    Pairs1 = maps:put(Key, Value, Pairs0),
+    decode_pairs(Rest1, KeyType, ValueType, Size - 1, Pairs1).
+
+-spec decode_data(thrift_protocol:data_type(), binary()) -> {thrift_protocol:data(), binary()}.
+decode_data(boolean, <<0, Rest/binary>>) -> {false, Rest};
+decode_data(boolean, <<1, Rest/binary>>) -> {true, Rest};
+decode_data(i8, <<N:8/signed, Rest/binary>>) -> {{i8, N}, Rest};
+decode_data(i16, <<N:16/signed, Rest/binary>>) -> {{i16, N}, Rest};
+decode_data(i32, <<N:32/signed, Rest/binary>>) -> {{i32, N}, Rest};
+decode_data(i64, <<N:64/signed, Rest/binary>>) -> {{i64, N}, Rest};
+decode_data(float, <<N/float, Rest/binary>>) -> {N, Rest};
+decode_data(binary, <<Len:32, Bin:Len/binary, Rest/binary>>) -> {Bin, Rest};
+decode_data(struct, Bin) -> decode_struct(Bin, #{});
+decode_data(map, <<K:8, V:8, Size:32, Bin/binary>>) ->
+    KeyType = thrift_protocol_byte:to_data_type(K),
+    ValueType = thrift_protocol_byte:to_data_type(V),
+    {Pairs, Rest} = decode_pairs(Bin, KeyType, ValueType, Size, #{}),
+    {#thrift_protocol_map{key_type = KeyType, value_type = ValueType, elements = Pairs}, Rest};
+decode_data(set, <<TypeByte:8, Size:32, Bin/binary>>) ->
+    Type = thrift_protocol_byte:to_data_type(TypeByte),
+    {Elements, Rest} = decode_elements(Bin, Type, Size, []),
+    {#thrift_protocol_set{element_type = Type, elements = Elements}, Rest};
+decode_data(list, <<TypeByte:8, Size:32, Bin/binary>>) ->
+    Type = thrift_protocol_byte:to_data_type(TypeByte),
+    {Elements, Rest} = decode_elements(Bin, Type, Size, []),
+    {#thrift_protocol_list{element_type = Type, elements = Elements}, Rest}.
+
 -spec encode_message(thrift_protocol:message()) -> iodata().
 encode_message(Message) ->
     #thrift_protocol_message{method_name = Name, sequence_id = SeqId, body = Body} = Message,
-    Type =
-        case Message#thrift_protocol_message.message_type of
-            call      -> ?MESSAGE_TYPE_CALL;
-            reply     -> ?MESSAGE_TYPE_REPLY;
-            exception -> ?MESSAGE_TYPE_EXCEPTION;
-            oneway    -> ?MESSAGE_TYPE_ONEWAY
-        end,
-    [<<1:1, ?VERSION:15, 0:8, 0:5, Type:3, (byte_size(Name)):32, Name/binary, SeqId:32>> | encode_data(Body)].
+    Type = thrift_protocol_byte:from_message_type(Message#thrift_protocol_message.message_type),
+    [<<1:1, ?VERSION:15, 0:8, 0:5, Type:3, (byte_size(Name)):32, Name/binary, SeqId:32>> | encode_struct(Body)].
+
+-spec encode_struct(thrift_protocol:struct()) -> iodata().
+encode_struct(#thrift_protocol_struct{fields = Fields}) ->
+    maps:fold(
+      fun (Id, Data, Acc) ->
+              Type = thrift_protocol_byte:from_data_type(thrift_protocol:data_type(Data)),
+              [<<Type:8, Id:16>>, encode_data(Data) | Acc]
+      end,
+      [<<0:32>>],
+      Fields).
 
 -spec encode_data(thrift_protocol:data()) -> iodata().
 encode_data(true) ->
@@ -36,14 +107,8 @@ encode_data(N) when is_float(N)->
     <<N/float>>;
 encode_data(B) when is_binary(B) ->
     [<<(byte_size(B)):32>> | B];
-encode_data(#thrift_protocol_struct{fields = Fields}) ->
-    maps:fold(
-      fun (Id, Data, Acc) ->
-              Type = data_type_to_byte(thrift_protocol:data_type(Data)),
-              [<<Type:8, Id:32>>, encode_data(Data) | Acc]
-      end,
-      [<<0:32>>],
-      Fields);
+encode_data(X = #thrift_protocol_struct{}) ->
+    encode_struct(X);
 encode_data(#thrift_protocol_map{key_type = KeyType, value_type = ValueType, elements = Elements}) ->
     IoData =
         maps:fold(
@@ -54,31 +119,20 @@ encode_data(#thrift_protocol_map{key_type = KeyType, value_type = ValueType, ele
           end,
           [],
           Elements),
-    [<<(data_type_to_byte(KeyType)):8, (data_type_to_byte(ValueType)):8, (maps:size(Elements)):32>> | IoData];
+    [<<(thrift_protocol_byte:from_data_type(KeyType)):8,
+       (thrift_protocol_byte:from_data_type(ValueType)):8,
+       (maps:size(Elements)):32>> | IoData];
 encode_data(#thrift_protocol_set{element_type = Type, elements = Elements}) ->
     Size = length(Elements),
-    [<<(data_type_to_byte(Type)):8, Size:32>> |
+    [<<(thrift_protocol_byte:from_data_type(Type)):8, Size:32>> |
      [begin
           Type = thrift_protocol:data_type(E),
           encode_data(E)
       end || E <- Elements]];
 encode_data(#thrift_protocol_list{element_type = Type, elements = Elements}) ->
     Size = length(Elements),
-    [<<(data_type_to_byte(Type)):8, Size:32>> |
+    [<<(thrift_protocol_byte:from_data_type(Type)):8, Size:32>> |
      [begin
           Type = thrift_protocol:data_type(E),
           encode_data(E)
       end || E <- Elements]].
-
--spec data_type_to_byte(thrift_protocol:data_type()) -> byte().
-data_type_to_byte(boolean) -> ?DATA_TYPE_BOOLEAN;
-data_type_to_byte(i8)      -> ?DATA_TYPE_I8;
-data_type_to_byte(i16)     -> ?DATA_TYPE_I16;
-data_type_to_byte(i32)     -> ?DATA_TYPE_I32;
-data_type_to_byte(i64)     -> ?DATA_TYPE_I64;
-data_type_to_byte(float)   -> ?DATA_TYPE_FLOAT;
-data_type_to_byte(binary)  -> ?DATA_TYPE_BINARY;
-data_type_to_byte(struct)  -> ?DATA_TYPE_STRUCT;
-data_type_to_byte(map)     -> ?DATA_TYPE_MAP;
-data_type_to_byte(set)     -> ?DATA_TYPE_SET;
-data_type_to_byte(list)    -> ?DATA_TYPE_LIST.
diff --git a/src/thrift_protocol_byte.erl b/src/thrift_protocol_byte.erl
new file mode 100644
index 0000000..711d8df
--- /dev/null
+++ b/src/thrift_protocol_byte.erl
@@ -0,0 +1,44 @@
+-module(thrift_protocol_byte).
+
+-include("constants.hrl").
+
+-export([from_message_type/1, from_data_type/1]).
+-export([to_message_type/1, to_data_type/1]).
+
+-spec to_message_type(byte()) -> thrift_protocol:message_type().
+to_message_type(?MESSAGE_TYPE_CALL)      -> call;
+to_message_type(?MESSAGE_TYPE_REPLY)     -> reply;
+to_message_type(?MESSAGE_TYPE_EXCEPTION) -> exception;
+to_message_type(?MESSAGE_TYPE_ONEWAY)    -> oneway.
+
+-spec to_data_type(byte()) -> thrift_protocol:data_type().
+to_data_type(?DATA_TYPE_BOOLEAN) -> boolean;
+to_data_type(?DATA_TYPE_I8)      -> i8;
+to_data_type(?DATA_TYPE_I16)     -> i16;
+to_data_type(?DATA_TYPE_I32)     -> i32;
+to_data_type(?DATA_TYPE_I64)     -> i64;
+to_data_type(?DATA_TYPE_FLOAT)   -> float;
+to_data_type(?DATA_TYPE_BINARY)  -> binary;
+to_data_type(?DATA_TYPE_STRUCT)  -> struct;
+to_data_type(?DATA_TYPE_MAP)     -> map;
+to_data_type(?DATA_TYPE_SET)     -> set;
+to_data_type(?DATA_TYPE_LIST)    -> list.
+
+-spec from_message_type(thrift_protocol:message_type()) -> byte().
+from_message_type(call)      -> ?MESSAGE_TYPE_CALL;
+from_message_type(reply)     -> ?MESSAGE_TYPE_REPLY;
+from_message_type(exception) -> ?MESSAGE_TYPE_EXCEPTION;
+from_message_type(oneway)    -> ?MESSAGE_TYPE_ONEWAY.
+
+-spec from_data_type(thrift_protocol:data_type()) -> byte().
+from_data_type(boolean) -> ?DATA_TYPE_BOOLEAN;
+from_data_type(i8)      -> ?DATA_TYPE_I8;
+from_data_type(i16)     -> ?DATA_TYPE_I16;
+from_data_type(i32)     -> ?DATA_TYPE_I32;
+from_data_type(i64)     -> ?DATA_TYPE_I64;
+from_data_type(float)   -> ?DATA_TYPE_FLOAT;
+from_data_type(binary)  -> ?DATA_TYPE_BINARY;
+from_data_type(struct)  -> ?DATA_TYPE_STRUCT;
+from_data_type(map)     -> ?DATA_TYPE_MAP;
+from_data_type(set)     -> ?DATA_TYPE_SET;
+from_data_type(list)    -> ?DATA_TYPE_LIST.


[couchdb-thrift-protocol] 03/19: Add test for `thrift_protocol_binary` module

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 69a661b687b5e2d7546618cfddf83e9344f46a10
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Wed Oct 18 19:46:16 2017 +0900

    Add test for `thrift_protocol_binary` module
---
 src/thrift_protocol_binary.erl        |  6 +--
 test/thrift_protocol_binary_tests.erl | 80 +++++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+), 3 deletions(-)

diff --git a/src/thrift_protocol_binary.erl b/src/thrift_protocol_binary.erl
index 0bccf20..26af1cc 100644
--- a/src/thrift_protocol_binary.erl
+++ b/src/thrift_protocol_binary.erl
@@ -21,10 +21,10 @@ decode_message(<<1:1, ?VERSION:15, _:8, 0:5, TypeByte:3, NameLen:32, Name:NameLe
 
 -spec decode_struct(binary(), Fields) -> {thrift_protocol:struct(), binary()} when
       Fields :: #{thrift_protocol:field_id() => thrift_protocol:data()}.
-decode_struct(<<0:32, Rest/binary>>, Fields) ->
+decode_struct(<<0:8, Rest/binary>>, Fields) ->
     {#thrift_protocol_struct{fields = Fields}, Rest};
 decode_struct(<<TypeByte:8, Id:16/signed, Rest0/binary>>, Fields0) ->
-    Type = thrift_protocol_struct:to_data_type(TypeByte),
+    Type = thrift_protocol_byte:to_data_type(TypeByte),
     {Data, Rest1} = decode_data(Type, Rest0),
     Fields1 = maps:put(Id, Data, Fields0),
     decode_struct(Rest1, Fields1).
@@ -87,7 +87,7 @@ encode_struct(#thrift_protocol_struct{fields = Fields}) ->
               Type = thrift_protocol_byte:from_data_type(thrift_protocol:data_type(Data)),
               [<<Type:8, Id:16>>, encode_data(Data) | Acc]
       end,
-      [<<0:32>>],
+      [<<0:8>>],
       Fields).
 
 -spec encode_data(thrift_protocol:data()) -> iodata().
diff --git a/test/thrift_protocol_binary_tests.erl b/test/thrift_protocol_binary_tests.erl
new file mode 100644
index 0000000..fe97d89
--- /dev/null
+++ b/test/thrift_protocol_binary_tests.erl
@@ -0,0 +1,80 @@
+-module(thrift_protocol_binary_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+-include("thrift_protocol.hrl").
+
+decode_test() ->
+    Input = bytes(),
+    {Message, <<>>} = thrift_protocol_binary:decode_message(Input),
+    ?assertEqual(message(), Message).
+
+encode_test() ->
+    Bytes = thrift_protocol_binary:encode_message(message()),
+    {Message, <<>>} = thrift_protocol_binary:decode_message(list_to_binary(Bytes)),
+    ?assertEqual(message(), Message),
+    ?assertEqual(lists:sort(binary_to_list(bytes())),
+                 lists:sort(binary_to_list(list_to_binary(Bytes)))).
+
+-spec bytes() -> binary().
+bytes() ->
+    <<128,1,0,4,0,0,0,9,101,109,105,116,66,97,116,99,104,0,0,0,1, 12,
+      0,1,12,0,1,11,0,1,0,0,0,11,102,111,111,95,115,101,114,118, 105,99,
+      101,15,0,2,12,0,0,0,3,11,0,1,0,0,0,14,106,97,101,103, 101,114,46,
+      118,101,114,115,105,111,110,8,0,2,0,0,0,0,11,0,3, 0,0,0,8,71,
+      111,45,50,46,57,46,48,0,11,0,1,0,0,0,8,104,111,115,116,110,97,
+      109,101,8,0,2,0,0,0,0,11,0,3,0,0,0,3,117,98,117,0,11,0,1,0,0,
+      0,2,105,112,8,0,2,0,0,0,0,11,0,3,0,0,0,9,49,48,46,48,46,50,46,
+      49,53,0,0,15,0,2,12,0,0,0,1,10,0,1,0,5,91,207,149,156,234,128,10,
+      0,2,0,0,0,0,0,0,0,0,10,0,3,0,0,0,0,0,0,3,21,10,0,4,0,0,0,0,0,0,
+      0,0,11,0,5,0,0,0,4,109,97,105,110,8,0,7,0,0,0,1,10,0,8,0,5,
+      91,207,149,156,234,128,10,0,9,0,0,0,0,0,1,226,64,0,0,0>>.
+
+-spec message() -> thrift_protocol:message().
+message() ->
+    Process =
+        #thrift_protocol_struct{
+           fields =
+               #{1 => <<"foo_service">>,
+                 2 => #thrift_protocol_list{
+                         element_type = struct,
+                         elements =
+                             [
+                              #thrift_protocol_struct{
+                                 fields = #{1 => <<"jaeger.version">>,
+                                            2 => {i32,0},
+                                            3 => <<"Go-2.9.0">>}},
+                              #thrift_protocol_struct{
+                                 fields = #{1 => <<"hostname">>,
+                                            2 => {i32,0},
+                                            3 => <<"ubu">>}},
+                              #thrift_protocol_struct{
+                                 fields = #{1 => <<"ip">>,
+                                            2 => {i32,0},
+                                            3 => <<"10.0.2.15">>}}
+                             ]
+                        }
+                }
+          },
+    Spans =
+        #thrift_protocol_list{
+           element_type = struct,
+           elements =
+               [#thrift_protocol_struct{
+                   fields =
+                       #{1 => {i64,1508322010000000},
+                         2 => {i64,0},
+                         3 => {i64,789},
+                         4 => {i64,0},
+                         5 => <<"main">>,
+                         7 => {i32,1},
+                         8 => {i64,1508322010000000},
+                         9 => {i64,123456}}}]
+          },
+    Batch =
+        #thrift_protocol_struct{fields = #{1 => Process, 2 => Spans}},
+    #thrift_protocol_message{
+       method_name = <<"emitBatch">>,
+       message_type = oneway,
+       sequence_id = 1,
+       body = #thrift_protocol_struct{fields = #{1 => Batch}}
+      }.


[couchdb-thrift-protocol] 17/19: Update .travis.yml

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 6474da88f8c51db0d21aca9b667f75e79e4db56b
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Tue Dec 25 23:17:58 2018 +0900

    Update .travis.yml
---
 .travis.yml | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 92a44f7..d54e000 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,22 +2,21 @@ language: erlang
 
 os: linux
 otp_release:
+  - 21.0
   - 20.0
   - 19.3
   - 18.3
 
-script: rebar3 eunit
 install:
-  - wget https://s3.amazonaws.com/rebar3/rebar3 && chmod +x rebar3
   - sudo pip install codecov
 script:
-  - ./rebar3 compile
-  - ./rebar3 xref
-  - ./rebar3 eunit
-  - ./rebar3 dialyzer
-  - ./rebar3 edoc
-  - ./rebar3 cover
-  - ./rebar3 covertool generate
+  - rebar3 compile
+  - rebar3 xref
+  - rebar3 eunit
+  - rebar3 dialyzer
+  - rebar3 edoc
+  - rebar3 cover
+  - rebar3 as test covertool generate
   - cp _build/test/covertool/thrift_protocol.covertool.xml ./cobertura.xml
 
 after_success:


[couchdb-thrift-protocol] 05/19: Set default values

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 4e8a79408e7359b102ab927212bdbf30dbddbadb
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 00:17:03 2017 +0900

    Set default values
---
 include/thrift_protocol.hrl | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/include/thrift_protocol.hrl b/include/thrift_protocol.hrl
index 327a25b..e01f31e 100644
--- a/include/thrift_protocol.hrl
+++ b/include/thrift_protocol.hrl
@@ -1,31 +1,31 @@
--record(thrift_protocol_message,
+-record(thrift_protocol_struct,
         {
-          method_name  :: binary(),
-          message_type :: thrift_protocol:message_type(),
-          sequence_id  :: integer(),
-          body         :: thrift_protocol:struct()
+          fields = #{} :: #{thrift_protocol:field_id() => thrift_protocol:data()}
         }).
 
--record(thrift_protocol_struct,
+-record(thrift_protocol_message,
         {
-          fields :: #{thrift_protocol:field_id() => thrift_protocol:data()}
+          method_name  = <<>> :: binary(),
+          message_type = call :: thrift_protocol:message_type(),
+          sequence_id  = 0    :: integer(),
+          body         = #thrift_protocol_struct{} :: thrift_protocol:struct()
         }).
 
 -record(thrift_protocol_map,
         {
           key_type   :: thrift_protocol:data_type() | undefined,
           value_type :: thrift_protocol:data_type() | undefined,
-          elements   :: #{thrift_protocol:data() => thrift_protocol:data()}
+          elements = #{} :: #{thrift_protocol:data() => thrift_protocol:data()}
         }).
 
 -record(thrift_protocol_set,
         {
-          element_type :: thrift_protocol:data_type(),
-          elements     :: [thrift_protocol:data()]
+          element_type = boolean :: thrift_protocol:data_type(),
+          elements = [] :: [thrift_protocol:data()]
         }).
 
 -record(thrift_protocol_list,
         {
-          element_type :: thrift_protocol:data_type(),
-          elements     :: [thrift_protocol:data()]
+          element_type = boolean :: thrift_protocol:data_type(),
+          elements = [] :: [thrift_protocol:data()]
         }).


[couchdb-thrift-protocol] 16/19: version bump

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 4bb007181d80f87928b193e816ad3ec17e22bc98
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 22:56:24 2017 +0900

    version bump
---
 src/thrift_protocol.app.src | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/thrift_protocol.app.src b/src/thrift_protocol.app.src
index 4414762..7fbf021 100644
--- a/src/thrift_protocol.app.src
+++ b/src/thrift_protocol.app.src
@@ -1,6 +1,6 @@
 {application,thrift_protocol,
              [{description,"An Erlang implementation of Thrift protocol."},
-              {vsn,"0.1.1"},
+              {vsn,"0.1.2"},
               {registered,[]},
               {applications,[kernel,stdlib]},
               {env,[]},


[couchdb-thrift-protocol] 11/19: Update thrift_protocol.app.src

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit cfbe8dc6ae4e2df4709f6dee573637429519326a
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 01:31:50 2017 +0900

    Update thrift_protocol.app.src
---
 src/thrift_protocol.app.src | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/thrift_protocol.app.src b/src/thrift_protocol.app.src
index dfb0c68..19544cb 100644
--- a/src/thrift_protocol.app.src
+++ b/src/thrift_protocol.app.src
@@ -1,5 +1,5 @@
 {application, thrift_protocol,
- [{description, "An OTP library"},
+ [{description, "An Erlang implementation of Thrift protocol."},
   {vsn, "0.1.0"},
   {registered, []},
   {applications,
@@ -9,7 +9,7 @@
   {env,[]},
   {modules, []},
 
-  {maintainers, []},
+  {maintainers, ["Takeru Ohta"]},
   {licenses, ["MIT"]},
-  {links, []}
+  {links, [{"GitHub","https://github.com/sile/thrift_protocol"}]}
  ]}.


[couchdb-thrift-protocol] 10/19: Add documentation

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 337c263185f43a858951266c5d9cf7e0218ec20a
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 01:30:09 2017 +0900

    Add documentation
---
 include/thrift_protocol.hrl     |  24 ++++-----
 src/thrift_protocol.erl         | 109 +++++++++++++++++++++++++++++++++++++---
 src/thrift_protocol_binary.erl  |   1 +
 src/thrift_protocol_byte.erl    |   1 +
 src/thrift_protocol_compact.erl |   1 +
 5 files changed, 116 insertions(+), 20 deletions(-)

diff --git a/include/thrift_protocol.hrl b/include/thrift_protocol.hrl
index e01f31e..f439ba7 100644
--- a/include/thrift_protocol.hrl
+++ b/include/thrift_protocol.hrl
@@ -3,29 +3,29 @@
           fields = #{} :: #{thrift_protocol:field_id() => thrift_protocol:data()}
         }).
 
--record(thrift_protocol_message,
-        {
-          method_name  = <<>> :: binary(),
-          message_type = call :: thrift_protocol:message_type(),
-          sequence_id  = 0    :: integer(),
-          body         = #thrift_protocol_struct{} :: thrift_protocol:struct()
-        }).
-
 -record(thrift_protocol_map,
         {
-          key_type   :: thrift_protocol:data_type() | undefined,
-          value_type :: thrift_protocol:data_type() | undefined,
+          key_type       :: thrift_protocol:data_type() | undefined,
+          value_type     :: thrift_protocol:data_type() | undefined,
           elements = #{} :: #{thrift_protocol:data() => thrift_protocol:data()}
         }).
 
 -record(thrift_protocol_set,
         {
           element_type = boolean :: thrift_protocol:data_type(),
-          elements = [] :: [thrift_protocol:data()]
+          elements     = []      :: [thrift_protocol:data()]
         }).
 
 -record(thrift_protocol_list,
         {
           element_type = boolean :: thrift_protocol:data_type(),
-          elements = [] :: [thrift_protocol:data()]
+          elements     = []      :: [thrift_protocol:data()]
+        }).
+
+-record(thrift_protocol_message,
+        {
+          method_name  = <<>>              :: binary(),
+          message_type = call              :: thrift_protocol:message_type(),
+          sequence_id  = 0                 :: integer(),
+          body = #thrift_protocol_struct{} :: thrift_protocol:struct()
         }).
diff --git a/src/thrift_protocol.erl b/src/thrift_protocol.erl
index 3b59cfb..ac01bbe 100644
--- a/src/thrift_protocol.erl
+++ b/src/thrift_protocol.erl
@@ -1,3 +1,34 @@
+%% @doc An Erlang implementation of Thrift protocol.
+%%
+%% == Examples ==
+%%
+%% ```
+%% Body =
+%%     #thrift_protocol_struct{
+%%         fields = #{1 => true, 2 => {i8, -1}}
+%%     },
+%% Message =
+%%     #thrift_protocol_message{
+%%         method_name = <<"foo">>,
+%%         message_type = call,
+%%         sequence_id = 0,
+%%         body = Body
+%%     },
+%%
+%% Encoded = list_to_binary(thrift_protocol:encode_message(Message, compact)),
+%% <<130,33,0,3,102,111,111,17,19,255,0>> = Encoded,
+%%
+%% {Decoded, <<>>} = thrift_protocol:decode_message(Encoded, compact),
+%% Message = Decoded.
+%% '''
+%%
+%% == References ==
+%%
+%% <ul>
+%%   <li><a href="https://github.com/apache/thrift/blob/master/doc/specs/thrift-protocol-spec.md">Thrift Protocol Structure</a></li>
+%%   <li><a href="https://github.com/apache/thrift/blob/master/doc/specs/thrift-binary-protocol.md">Thrift Binary protocol encoding</a></li>
+%%   <li><a href="https://github.com/apache/thrift/blob/master/doc/specs/thrift-compact-protocol.md">Thrift Compact protocol encoding</a></li>
+%% </ul>
 -module(thrift_protocol).
 
 -include("thrift_protocol.hrl").
@@ -5,27 +36,62 @@
 -export([encode_message/2, decode_message/2]).
 -export([data_type/1]).
 
--export_type([message/0, message_type/0, struct/0]).
--export_type([field_id/0, data/0, data_type/0]).
--export_type([thrift_map/0, thrift_list/0, set/0]).
--export_type([format/0, i8/0, i16/0, i32/0, i64/0]).
+-export_type([message/0, message_type/0]).
+-export_type([data/0, data_type/0]).
+-export_type([struct/0, struct/1, field_id/0]).
+-export_type([thrift_map/0, thrift_map/2]).
+-export_type([thrift_list/0, thrift_list/1]).
+-export_type([set/0, set/1]).
+-export_type([i8/0, i16/0, i32/0, i64/0]).
+-export_type([format/0]).
 
 -type format() :: binary | compact.
+%% Protocol encoding format.
 
 -type message() :: #thrift_protocol_message{}.
+%% Message.
 
 -type message_type() :: call | reply | exception | oneway.
+%% Message type.
 
 -type struct() :: #thrift_protocol_struct{}.
+%% Struct.
+
+-type struct(Fields) :: #thrift_protocol_struct{fields :: Fields}.
+%% Struct.
+
+-type field_id() :: integer().
+%% The identifier of a struct field (16-bit signed integer).
+
 -type thrift_map() :: #thrift_protocol_map{}.
+%% Map.
+
+-type thrift_map(KeyType, ValueType) :: #thrift_protocol_map{key_type :: KeyType, value_type :: ValueType}.
+%% Map.
+
 -type thrift_list() :: #thrift_protocol_list{}.
+%% List.
+
+-type thrift_list(ElementType) :: #thrift_protocol_list{element_type :: ElementType}.
+%% List
+
 -type set() :: #thrift_protocol_set{}.
+%% Set.
+
+-type set(ElementType) :: #thrift_protocol_set{element_type :: ElementType}.
+%% Set.
 
--type field_id() :: integer().
 -type i8() :: {i8, integer()}.
+%% 8-bit signed integer.
+
 -type i16() :: {i16, integer()}.
+%% 16-bit signed integer.
+
 -type i32() :: {i32, integer()}.
+%% 32-bit signed integer.
+
 -type i64() :: {i64, integer()}.
+%% 64-bit signed integer.
 
 -type data_type() :: boolean
                    | i8
@@ -38,6 +104,7 @@
                    | map
                    | set
                    | list.
+%% Data type.
 
 -type data() :: boolean()
               | i8()
@@ -50,20 +117,24 @@
               | thrift_map()
               | set()
               | thrift_list().
+%% Data.
 
--spec encode_message(message(), format()) -> iodata().
+%% @doc Encodes `Message'.
+-spec encode_message(message(), Format :: format()) -> iodata().
 encode_message(Message, binary) ->
     thrift_protocol_binary:encode_message(Message);
 encode_message(Message, compact) ->
     thrift_protocol_compact:encode_message(Message).
 
--spec decode_message(binary(), format()) -> {message(), binary()}.
+%% @doc Decodes a message from the given binary.
+-spec decode_message(binary(), Format :: format()) -> {message(), binary()}.
 decode_message(Bin, binary) ->
     thrift_protocol_binary:decode_message(Bin);
 decode_message(Bin, compact) ->
     thrift_protocol_compact:decode_message(Bin).
 
--spec data_type(data()) -> data_type().
+%% @doc Returns the type of `Data'.
+-spec data_type(Data :: data()) -> data_type().
 data_type(X) when is_boolean(X) ->
     boolean;
 data_type({i8, _}) ->
@@ -86,3 +157,25 @@ data_type(#thrift_protocol_set{}) ->
     set;
 data_type(#thrift_protocol_list{}) ->
     list.
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+example_test() ->
+    Body =
+        #thrift_protocol_struct{
+           fields = #{1 => true, 2 => {i8, -1}}
+          },
+    Message =
+        #thrift_protocol_message{
+           method_name = <<"foo">>,
+           message_type = call,
+           sequence_id = 0,
+           body = Body
+          },
+
+    Encoded = list_to_binary(thrift_protocol:encode_message(Message, compact)),
+    ?assertEqual(<<130,33,0,3,102,111,111,17,19,255,0>>, Encoded),
+
+    {Decoded, <<>>} = thrift_protocol:decode_message(Encoded, compact),
+    ?assertEqual(Message, Decoded).
+-endif.
diff --git a/src/thrift_protocol_binary.erl b/src/thrift_protocol_binary.erl
index 26af1cc..301a9f1 100644
--- a/src/thrift_protocol_binary.erl
+++ b/src/thrift_protocol_binary.erl
@@ -1,3 +1,4 @@
+%% @private
 -module(thrift_protocol_binary).
 
 -include("thrift_protocol.hrl").
diff --git a/src/thrift_protocol_byte.erl b/src/thrift_protocol_byte.erl
index 711d8df..0723005 100644
--- a/src/thrift_protocol_byte.erl
+++ b/src/thrift_protocol_byte.erl
@@ -1,3 +1,4 @@
+%% @private
 -module(thrift_protocol_byte).
 
 -include("constants.hrl").
diff --git a/src/thrift_protocol_compact.erl b/src/thrift_protocol_compact.erl
index 4f42a84..5641530 100644
--- a/src/thrift_protocol_compact.erl
+++ b/src/thrift_protocol_compact.erl
@@ -1,3 +1,4 @@
+%% @private
 -module(thrift_protocol_compact).
 
 -include("thrift_protocol.hrl").


[couchdb-thrift-protocol] 08/19: Update .travis.yml

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 69be7e9bf9c05d3c4134b37c83371435029e7688
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 00:36:02 2017 +0900

    Update .travis.yml
---
 .travis.yml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 92a44f7..0f5fbfd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,9 +16,6 @@ script:
   - ./rebar3 eunit
   - ./rebar3 dialyzer
   - ./rebar3 edoc
-  - ./rebar3 cover
-  - ./rebar3 covertool generate
-  - cp _build/test/covertool/thrift_protocol.covertool.xml ./cobertura.xml
 
 after_success:
   - codecov


[couchdb-thrift-protocol] 06/19: Add .travis.yml

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 5f02bba9dd32f123dcf6c6218b22adc0eac01ffb
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 00:19:22 2017 +0900

    Add .travis.yml
---
 .travis.yml | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..a6f6418
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,22 @@
+language: erlang
+
+sudo: false
+os: linux
+otp_release:
+  - 20.0
+  - 19.3
+  - 18.3
+
+script: rebar3 eunit
+install:
+  - wget https://s3.amazonaws.com/rebar3/rebar3 && chmod +x rebar3
+  - pip install codecov
+script:
+  - ./rebar3 compile
+  - ./rebar3 xref
+  - ./rebar3 eunit
+  - ./rebar3 dialyzer
+  - ./rebar3 edoc
+
+after_success:
+  - codecov


[couchdb-thrift-protocol] 12/19: Update README.md

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 5532c18d585cb93c891f76c45d100363d5ec0e03
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Thu Oct 19 01:35:21 2017 +0900

    Update README.md
---
 README.md | 46 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 41 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index 52350e6..8be8eb0 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,45 @@
 thrift_protocol
-=====
+================
 
-An OTP library
+[![hex.pm version](https://img.shields.io/hexpm/v/thrift_protocol.svg)](https://hex.pm/packages/thrift_protocol)
+[![Build Status](https://travis-ci.org/sile/thrift_protocol.svg?branch=master)](https://travis-ci.org/sile/thrift_protocol)
+[![Code Coverage](https://codecov.io/gh/sile/thrift_protocol/branch/master/graph/badge.svg)](https://codecov.io/gh/sile/thrift_protocol/branch/master)
+[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
 
-Build
------
+An Erlang implementation of [Thrift](https://thrift.apache.org/) protocol.
 
-    $ rebar3 compile
+[Documentation](https://hexdocs.pm/thrift_protocol/)
+
+Examples
+---------
+
+```erlang
+Body =
+    #thrift_protocol_struct{
+        fields = #{1 => true, 2 => {i8, -1}}
+    },
+Message =
+    #thrift_protocol_message{
+        method_name = <<"foo">>,
+        message_type = call,
+        sequence_id = 0,
+        body = Body
+    },
+
+Encoded = list_to_binary(thrift_protocol:encode_message(Message, compact)),
+<<130,33,0,3,102,111,111,17,19,255,0>> = Encoded,
+
+{Decoded, <<>>} = thrift_protocol:decode_message(Encoded, compact),
+Message = Decoded.
+```
+
+References
+-----------
+
+- [Thrift Protocol Structure][protocol-structure]
+- [Thrift Binary protocol encoding][binary-encoding]
+- [Thrift Compact protocol encoding][compact-encoding]
+
+[protocol-structure]: https://github.com/apache/thrift/blob/master/doc/specs/thrift-protocol-spec.md
+[binary-encoding]: https://github.com/apache/thrift/blob/master/doc/specs/thrift-binary-protocol.md
+[compact-encoding]: https://github.com/apache/thrift/blob/master/doc/specs/thrift-compact-protocol.md


[couchdb-thrift-protocol] 04/19: Add `thrift_protocol_compact` module

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-thrift-protocol.git

commit 98734e7c31d42ceb7377a91074eb94d282d0a853
Author: Takeru Ohta <ph...@gmail.com>
AuthorDate: Wed Oct 18 23:46:34 2017 +0900

    Add `thrift_protocol_compact` module
---
 src/thrift_protocol_compact.erl        | 293 +++++++++++++++++++++++++++++++++
 test/thrift_protocol_compact_tests.erl |  77 +++++++++
 2 files changed, 370 insertions(+)

diff --git a/src/thrift_protocol_compact.erl b/src/thrift_protocol_compact.erl
new file mode 100644
index 0000000..4f42a84
--- /dev/null
+++ b/src/thrift_protocol_compact.erl
@@ -0,0 +1,293 @@
+-module(thrift_protocol_compact).
+
+-include("thrift_protocol.hrl").
+
+-export([decode_message/1, encode_message/1]).
+
+-define(PROTOCOL_ID, 16#82).
+-define(VERSION, 1).
+
+-define(FIELD_TRUE, 1).
+-define(FIELD_FALSE, 2).
+-define(FIELD_I8, 3).
+-define(FIELD_I16, 4).
+-define(FIELD_I32, 5).
+-define(FIELD_I64, 6).
+-define(FIELD_FLOAT, 7).
+-define(FIELD_BINARY, 8).
+-define(FIELD_LIST, 9).
+-define(FIELD_SET, 10).
+-define(FIELD_MAP, 11).
+-define(FIELD_STRUCT, 12).
+
+-spec encode_message(thrift_protocol:message()) -> iodata().
+encode_message(Message) ->
+    Type =
+        thrift_protocol_byte:from_message_type(Message#thrift_protocol_message.message_type),
+    [<<?PROTOCOL_ID, Type:3, ?VERSION:5>>,
+     encode_varint32(Message#thrift_protocol_message.sequence_id),
+     encode_binary(Message#thrift_protocol_message.method_name) |
+     encode_struct(Message#thrift_protocol_message.body)].
+
+-spec encode_binary(binary()) -> iodata().
+encode_binary(Bin) ->
+    [encode_varint32(byte_size(Bin)) | Bin].
+
+-spec encode_struct(thrift_protocol:struct()) -> iodata().
+encode_struct(#thrift_protocol_struct{fields = Fields0}) ->
+    encode_struct_fields(lists:sort(maps:to_list(Fields0)), 0).
+
+-spec encode_struct_fields(Fields, PrevFieldId) -> iodata() when
+      Fields :: [{thrift_protocol:field_id(), thrift_protocol:data()}],
+      PrevFieldId :: thrift_protocol:field_id().
+encode_struct_fields([], _PrevFieldId) ->
+    <<0>>;
+encode_struct_fields([{Id, Data} | Fields], PrevId) ->
+    Type =
+        case Data of
+            true                      -> ?FIELD_TRUE;
+            false                     -> ?FIELD_FALSE;
+            {i8, _}                   -> ?FIELD_I8;
+            {i16, _}                  -> ?FIELD_I16;
+            {i32, _}                  -> ?FIELD_I32;
+            {i64, _}                  -> ?FIELD_I64;
+            N when is_float(N)        -> ?FIELD_FLOAT;
+            N when is_binary(N)       -> ?FIELD_BINARY;
+            #thrift_protocol_list{}   -> ?FIELD_LIST;
+            #thrift_protocol_set{}    -> ?FIELD_SET;
+            #thrift_protocol_map{}    -> ?FIELD_MAP;
+            #thrift_protocol_struct{} -> ?FIELD_STRUCT
+        end,
+    Header =
+        case Id - PrevId of
+            Delta when 0 < Delta, Delta < 16 ->
+                <<Delta:4, Type:4>>;
+            _ ->
+                [<<0:4, Type:4>> | encode_data({i16, Id})]
+        end,
+    DataBytes =
+        case is_boolean(Data) of
+            true  -> [];
+            false -> encode_data(Data)
+        end,
+    [Header, DataBytes | encode_struct_fields(Fields, Id)].
+
+-spec encode_data(thrift_protocol:data()) -> iodata().
+encode_data(false) -> <<0>>;
+encode_data(true) -> <<1>>;
+encode_data({i8, N}) -> <<N:8>>;
+encode_data({i16, N}) -> encode_data({i32, N});
+encode_data({i32, N}) -> encode_varint32(int32_to_zigzag(N));
+encode_data({i64, N}) -> encode_varint64(int64_to_zigzag(N));
+encode_data(N) when is_float(N) -> <<N/float>>;
+encode_data(B) when is_binary(B) -> encode_binary(B);
+encode_data(X = #thrift_protocol_struct{}) -> encode_struct(X);
+encode_data(#thrift_protocol_map{elements = M}) when M =:= #{} ->
+    <<0>>;
+encode_data(X = #thrift_protocol_map{}) ->
+    #thrift_protocol_map{key_type = KeyType, value_type = ValueType} = X,
+    [encode_varint32(maps:size(X#thrift_protocol_map.elements)),
+     <<(thrift_protocol_byte:from_data_type(KeyType)):4,
+       (thrift_protocol_byte:from_data_type(ValueType)):4>>,
+     encode_pairs(maps:to_list(X#thrift_protocol_map.elements), KeyType, ValueType)];
+encode_data(#thrift_protocol_set{element_type = Type, elements = Elements}) ->
+    encode_elements(Elements, length(Elements), Type);
+encode_data(#thrift_protocol_list{element_type = Type, elements = Elements}) ->
+    encode_elements(Elements, length(Elements), Type).
+
+-spec encode_pairs(Pairs, KeyType, ValueType) -> iodata() when
+      Pairs :: [{thrift_protocol:data(), thrift_protocol:data()}],
+      KeyType :: thrift_protocol:data_type(),
+      ValueType :: thrift_protocol:data_type().
+encode_pairs([], _, _) -> [];
+encode_pairs([{K, V} | Pairs], KeyType, ValueType) ->
+    KeyType = thrift_protocol:data_type(K),
+    ValueType = thrift_protocol:data_type(V),
+    [encode_data(K), encode_data(V) | encode_pairs(Pairs, KeyType, ValueType)].
+
+-spec encode_elements(Elements, non_neg_integer(), thrift_protocol:data_type()) ->
+                             iodata() when
+      Elements :: [thrift_protocol:data()].
+encode_elements(Elements, Size, Type) when Size < 15 ->
+    TypeByte = thrift_protocol_byte:from_data_type(Type),
+    [<<Size:4, TypeByte:4>> | encode_elements(Elements, Type)];
+encode_elements(Elements, Size, Type) ->
+    TypeByte = thrift_protocol_byte:from_data_type(Type),
+    [<<1111:4, TypeByte:4>>, encode_varint32(Size) | encode_elements(Elements, Type)].
+
+-spec encode_elements([thrift_protocol:data()], thrift_protocol:data_type()) -> iodata().
+encode_elements([], _Type) -> [];
+encode_elements([E | Elements], Type) ->
+    Type = thrift_protocol:data_type(E),
+    [encode_data(E) | encode_elements(Elements, Type)].
+
+-spec decode_message(binary()) -> {thrift_protocol:message(), binary()}.
+decode_message(<<?PROTOCOL_ID, Type:3, ?VERSION:5, Rest0/binary>>) ->
+    MessageType = thrift_protocol_byte:to_message_type(Type),
+    {SeqId, Rest1} = decode_varint32(Rest0),
+    {NameLen, Rest2} = decode_varint32(Rest1),
+    <<Name:NameLen/binary, Rest3/binary>> = Rest2,
+    {Body, Rest4} = decode_struct(Rest3, 0, #{}),
+    Message =
+        #thrift_protocol_message{
+           method_name = Name,
+           message_type = MessageType,
+           sequence_id = SeqId,
+           body = Body
+          },
+    {Message, Rest4}.
+
+-spec decode_struct(binary(), PrevId, Fields) -> {thrift_protocol:struct(), binary()} when
+      PrevId :: thrift_protocol:field_id(),
+      Fields :: #{thrift_protocol:field_id() => thrift_protocol:data()}.
+decode_struct(<<0:8, Rest/binary>>, _PrevId, Fields) ->
+    {#thrift_protocol_struct{fields = Fields}, Rest};
+decode_struct(<<Delta:4, Type:4, Rest0/binary>>, PrevId, Fields0) ->
+    {Id, Rest1} = decode_field_id(Rest0, Delta, PrevId),
+    {Data, Rest2} = decode_field_data(Rest1, Type),
+    Fields1 = maps:put(Id, Data, Fields0),
+    decode_struct(Rest2, Id, Fields1).
+
+-spec decode_field_id(binary(), 0..15, thrift_protocol:field_id()) ->
+                             {thrift_protocol:field_id(), binary()}.
+decode_field_id(Bin, 0, _PrevId) ->
+    {{i16, Id}, Rest} = decode_data(Bin, i16),
+    {Id, Rest};
+decode_field_id(Bin, Delta, PrevId) ->
+    {PrevId + Delta, Bin}.
+
+-spec decode_field_data(binary(), byte()) -> {thrift_protocol:data(), binary()}.
+decode_field_data(Bin, ?FIELD_TRUE)   -> {true, Bin};
+decode_field_data(Bin, ?FIELD_FALSE)  -> {false, Bin};
+decode_field_data(Bin, ?FIELD_I8)     -> decode_data(Bin, i8);
+decode_field_data(Bin, ?FIELD_I16)    -> decode_data(Bin, i16);
+decode_field_data(Bin, ?FIELD_I32)    -> decode_data(Bin, i32);
+decode_field_data(Bin, ?FIELD_I64)    -> decode_data(Bin, i64);
+decode_field_data(Bin, ?FIELD_FLOAT)  -> decode_data(Bin, float);
+decode_field_data(Bin, ?FIELD_BINARY) -> decode_data(Bin, binary);
+decode_field_data(Bin, ?FIELD_LIST)   -> decode_data(Bin, list);
+decode_field_data(Bin, ?FIELD_SET)    -> decode_data(Bin, set);
+decode_field_data(Bin, ?FIELD_MAP)    -> decode_data(Bin, map);
+decode_field_data(Bin, ?FIELD_STRUCT) -> decode_data(Bin, struct).
+
+-spec decode_data(binary(), thrift_protocol:data_type()) ->
+                         {thrift_protocol:data(), binary()}.
+decode_data(<<0, Bin/binary>>, boolean) -> {false, Bin};
+decode_data(<<1, Bin/binary>>, boolean) -> {true, Bin};
+decode_data(<<N:8/signed, Bin/binary>>, i8) -> {{i8, N}, Bin};
+decode_data(Bin0, i16) ->
+    {{i32, N}, Bin1} = decode_data(Bin0, i32),
+    <<M:16/signed>> = <<N:16>>,
+    {{i16, M}, Bin1};
+decode_data(Bin0, i32) ->
+    {N, Bin1} = decode_varint32(Bin0),
+    {{i32, zigzag_to_int(N)}, Bin1};
+decode_data(Bin0, i64) ->
+    {N, Bin1} = decode_varint64(Bin0),
+    {{i64, zigzag_to_int(N)}, Bin1};
+decode_data(<<N/float, Bin/binary>>, float) ->
+    {N, Bin};
+decode_data(Bin0, binary) ->
+    {Size, Bin1} = decode_varint32(Bin0),
+    <<Bytes:Size/binary, Bin2/binary>> = Bin1,
+    {Bytes, Bin2};
+decode_data(Bin, struct) ->
+    decode_struct(Bin, 0, #{});
+decode_data(Bin0, set) ->
+    {Type, Elements, Bin1} = decode_elements(Bin0),
+    {#thrift_protocol_set{element_type = Type, elements = Elements}, Bin1};
+decode_data(Bin0, list) ->
+    {Type, Elements, Bin1} = decode_elements(Bin0),
+    {#thrift_protocol_list{element_type = Type, elements = Elements}, Bin1};
+decode_data(<<0, Bin/binary>>, map) ->
+    Map = #thrift_protocol_map{key_type = undefined, value_type = undefined, elements = #{}},
+    {Map, Bin};
+decode_data(Bin0, map) ->
+    {Size, Bin1} = decode_varint32(Bin0),
+    <<KeyTypeByte:4, ValueTypeByte:4, Bin2/binary>> = Bin1,
+    KeyType = thrift_protocol_byte:to_data_type(KeyTypeByte),
+    ValueType = thrift_protocol_byte:to_data_type(ValueTypeByte),
+    {Pairs, Bin3} = decode_pairs(Bin2, KeyType, ValueType, Size, #{}),
+    Map = #thrift_protocol_map{key_type = KeyType, value_type = ValueType, elements = Pairs},
+    {Map, Bin3}.
+
+-spec decode_pairs(binary(), KeyType, ValueType, non_neg_integer(), Pairs) ->
+                          {Pairs, binary()} when
+      KeyType :: thrift_protocol:data_type(),
+      ValueType :: thrift_protocol:data_type(),
+      Pairs :: #{thrift_protocol:data() => thrift_protocol:data()}.
+decode_pairs(Bin, _KeyType, _ValueType, 0, Pairs) ->
+    {Pairs, Bin};
+decode_pairs(Bin0, KeyType, ValueType, Size, Pairs) ->
+    {Key, Bin1} = decode_data(Bin0, KeyType),
+    {Value, Bin2} = decode_data(Bin1, ValueType),
+    decode_pairs(Bin2, KeyType, ValueType, Size - 1, maps:put(Key, Value, Pairs)).
+
+-spec decode_elements(binary()) -> {ElementType, Elements, binary()} when
+      ElementType :: thrift_protocol:data_type(),
+      Elements :: [thrift_protocol:data()].
+decode_elements(<<2#1111:4, TypeByte:4, Bin0/binary>>) ->
+    Type = thrift_protocol_byte:to_data_type(TypeByte),
+    {Size, Bin1} = decode_varint32(Bin0),
+    decode_elements(Bin1, Type, Size, []);
+decode_elements(<<Size:4, TypeByte:4, Bin/binary>>) ->
+    Type = thrift_protocol_byte:to_data_type(TypeByte),
+    decode_elements(Bin, Type, Size, []).
+
+-spec decode_elements(binary(), ElementType, non_neg_integer(), Elements) ->
+                             {ElementType, Elements, binary()} when
+      ElementType :: thrift_protocol:data_type(),
+      Elements :: [thrift_protocol:data()].
+decode_elements(Bin, Type, 0, Acc) ->
+    {Type, lists:reverse(Acc), Bin};
+decode_elements(Bin0, Type, Size, Acc) ->
+    {Data, Bin1} = decode_data(Bin0, Type),
+    decode_elements(Bin1, Type, Size - 1, [Data | Acc]).
+
+-spec zigzag_to_int(integer()) -> integer().
+zigzag_to_int(N) ->
+    (N bsr 1) bxor -(N band 1).
+
+-spec int32_to_zigzag(integer()) -> integer().
+int32_to_zigzag(N) ->
+    (N bsl 1) bxor (N bsr 31).
+
+-spec int64_to_zigzag(integer()) -> integer().
+int64_to_zigzag(N) ->
+    (N bsl 1) bxor (N bsr 63).
+
+-spec encode_varint32(integer()) -> binary().
+encode_varint32(N) ->
+    encode_varint(N band 16#FFFFFFFF, <<>>).
+
+-spec encode_varint64(integer()) -> binary().
+encode_varint64(N) ->
+    encode_varint(N band 16#FFFFFFFFFFFFFFFF, <<>>).
+
+-spec encode_varint(non_neg_integer(), binary()) -> binary().
+encode_varint(N, Acc) ->
+    A = N band 2#01111111,
+    B = N bsr 7,
+    case B =:= 0 of
+        true  -> <<Acc/binary, 0:1, A:7>>;
+        false -> encode_varint(B, <<Acc/binary, 1:1, A:7>>)
+    end.
+
+-spec decode_varint32(binary()) -> {integer(), binary()}.
+decode_varint32(Bin0) ->
+    {N, Bin1} = decode_varint(Bin0, 0, 5, 0),
+    <<M:32/signed>> = <<N:32>>,
+    {M, Bin1}.
+
+-spec decode_varint64(binary()) -> {integer(), binary()}.
+decode_varint64(Bin0) ->
+    {N, Bin1} = decode_varint(Bin0, 0, 10, 0),
+    <<M:64/signed>> = <<N:64>>,
+    {M, Bin1}.
+
+-spec decode_varint(binary(), non_neg_integer(), non_neg_integer(), non_neg_integer()) ->
+                           {non_neg_integer(), binary()}.
+decode_varint(<<0:1, N:7, Bin/binary>>, I, _, M) ->
+    {(N bsl (I * 7)) + M, Bin};
+decode_varint(<<1:1, N:7, Bin/binary>>, I, Max, M) when I =< Max ->
+    decode_varint(Bin, I + 1, Max, (N bsl (I * 7)) + M).
diff --git a/test/thrift_protocol_compact_tests.erl b/test/thrift_protocol_compact_tests.erl
new file mode 100644
index 0000000..4824ef4
--- /dev/null
+++ b/test/thrift_protocol_compact_tests.erl
@@ -0,0 +1,77 @@
+-module(thrift_protocol_compact_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+-include("thrift_protocol.hrl").
+
+decode_test() ->
+    Input = bytes(),
+    {Message, <<>>} = thrift_protocol_compact:decode_message(Input),
+    ?assertEqual(message(), Message).
+
+encode_test() ->
+    Bytes = thrift_protocol_compact:encode_message(message()),
+    {Message, <<>>} = thrift_protocol_compact:decode_message(list_to_binary(Bytes)),
+    ?assertEqual(message(), Message),
+    ?assertEqual(lists:sort(binary_to_list(bytes())),
+                 lists:sort(binary_to_list(list_to_binary(Bytes)))).
+
+-spec bytes() -> binary().
+bytes() ->
+    <<130,129,1,9,101,109,105,116,66,97,116,99,104,28,28,24,11,102,
+      111,111,95,115,101,114,118,105,99,101,25,60,24,14,106,97,101,
+      103,101,114,46,118,101,114,115,105,111,110,21,0,24,8,71,111,
+      45,50,46,57,46,48,0,24,8,104,111,115,116,110,97,109,101,21,0,
+      24,3,117,98,117,0,24,2,105,112,21,0,24,9,49,48,46,48,46,50,
+      46,49,53,0,0,25,28,22,128,203,251,150,247,243,173,5,22,0,22,
+      170,12,22,0,24,4,109,97,105,110,37,2,22,128,203,251,150,247,
+      243,173,5,22,128,137,15,0,0,0>>.
+
+-spec message() -> thrift_protocol:message().
+message() ->
+    Process =
+        #thrift_protocol_struct{
+           fields =
+               #{1 => <<"foo_service">>,
+                 2 => #thrift_protocol_list{
+                         element_type = struct,
+                         elements =
+                             [
+                              #thrift_protocol_struct{
+                                 fields = #{1 => <<"jaeger.version">>,
+                                            2 => {i32,0},
+                                            3 => <<"Go-2.9.0">>}},
+                              #thrift_protocol_struct{
+                                 fields = #{1 => <<"hostname">>,
+                                            2 => {i32,0},
+                                            3 => <<"ubu">>}},
+                              #thrift_protocol_struct{
+                                 fields = #{1 => <<"ip">>,
+                                            2 => {i32,0},
+                                            3 => <<"10.0.2.15">>}}
+                             ]
+                        }
+                }
+          },
+    Spans =
+        #thrift_protocol_list{
+           element_type = struct,
+           elements =
+               [#thrift_protocol_struct{
+                   fields =
+                       #{1 => {i64,1508322611000000},
+                         2 => {i64,0},
+                         3 => {i64,789},
+                         4 => {i64,0},
+                         5 => <<"main">>,
+                         7 => {i32,1},
+                         8 => {i64,1508322611000000},
+                         9 => {i64,123456}}}]
+          },
+    Batch =
+        #thrift_protocol_struct{fields = #{1 => Process, 2 => Spans}},
+    #thrift_protocol_message{
+       method_name = <<"emitBatch">>,
+       message_type = oneway,
+       sequence_id = 1,
+       body = #thrift_protocol_struct{fields = #{1 => Batch}}
+      }.