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.