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:13 UTC

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

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.