From: David Reiss Date: Mon, 30 Aug 2010 22:05:34 +0000 (+0000) Subject: erlang: Refactor the binary protocol X-Git-Tag: 0.5.0~122 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=63f6126e978e2a5e23c6abc91a9805ff8611f45a;p=common%2Fthrift.git erlang: Refactor the binary protocol At this point, everything passes dialyzer except for the processor, and the client works. git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@990983 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/lib/erl/include/thrift_protocol_impl.hrl b/lib/erl/include/thrift_protocol_impl.hrl index ae0f0f7f..de6bb7be 100644 --- a/lib/erl/include/thrift_protocol_impl.hrl +++ b/lib/erl/include/thrift_protocol_impl.hrl @@ -22,16 +22,16 @@ -ifndef(THRIFT_PROTOCOL_IMPL_INCLUDED). -define(THRIFT_PROTOCOL_IMPL_INCLUDED, true). --spec flush_transport(state()) -> ok. --spec close_transport(state()) -> ok. +-spec flush_transport(state()) -> {state(), ok | {error, _Reason}}. +-spec close_transport(state()) -> {state(), ok | {error, _Reason}}. --spec write(state(), term()) -> ok | {error, _Reason}. +-spec write(state(), term()) -> {state(), ok | {error, _Reason}}. %% NOTE: Keep this in sync with thrift_protocol:read and read_specific. -spec read - (state(), tprot_empty_tag()) -> ok | {error, _Reason}; - (state(), tprot_header_tag()) -> tprot_header_val() | {error, _Reason}; - (state(), tprot_data_tag()) -> {ok, term()} | {error, _Reason}. + (state(), tprot_empty_tag()) -> {state(), ok | {error, _Reason}}; + (state(), tprot_header_tag()) -> {state(), tprot_header_val() | {error, _Reason}}; + (state(), tprot_data_tag()) -> {state(), {ok, term()} | {error, _Reason}}. -endif. diff --git a/lib/erl/src/thrift_binary_protocol.erl b/lib/erl/src/thrift_binary_protocol.erl index 00300bad..fcb072bd 100644 --- a/lib/erl/src/thrift_binary_protocol.erl +++ b/lib/erl/src/thrift_binary_protocol.erl @@ -60,79 +60,81 @@ parse_options([{strict_write, Bool} | Rest], State) when is_boolean(Bool) -> parse_options(Rest, State#binary_protocol{strict_write=Bool}). -flush_transport(#binary_protocol{transport = Transport}) -> - thrift_transport:flush(Transport). +flush_transport(This = #binary_protocol{transport = Transport}) -> + Result = thrift_transport:flush(Transport), + {This, Result}. -close_transport(#binary_protocol{transport = Transport}) -> - thrift_transport:close(Transport). +close_transport(This = #binary_protocol{transport = Transport}) -> + Result = thrift_transport:close(Transport), + {This, Result}. %%% %%% instance methods %%% -write(This, #protocol_message_begin{ +write(This0, #protocol_message_begin{ name = Name, type = Type, seqid = Seqid}) -> - case This#binary_protocol.strict_write of + case This0#binary_protocol.strict_write of true -> - write(This, {i32, ?VERSION_1 bor Type}), - write(This, {string, Name}), - write(This, {i32, Seqid}); + {This1, ok} = write(This0, {i32, ?VERSION_1 bor Type}), + {This2, ok} = write(This1, {string, Name}), + {This3, ok} = write(This2, {i32, Seqid}), + {This3, ok}; false -> - write(This, {string, Name}), - write(This, {byte, Type}), - write(This, {i32, Seqid}) - end, - ok; + {This1, ok} = write(This0, {string, Name}), + {This2, ok} = write(This1, {byte, Type}), + {This3, ok} = write(This2, {i32, Seqid}), + {This3, ok} + end; -write(This, message_end) -> ok; +write(This, message_end) -> {This, ok}; -write(This, #protocol_field_begin{ +write(This0, #protocol_field_begin{ name = _Name, type = Type, id = Id}) -> - write(This, {byte, Type}), - write(This, {i16, Id}), - ok; + {This1, ok} = write(This0, {byte, Type}), + {This2, ok} = write(This1, {i16, Id}), + {This2, ok}; write(This, field_stop) -> - write(This, {byte, ?tType_STOP}), - ok; + write(This, {byte, ?tType_STOP}); -write(This, field_end) -> ok; +write(This, field_end) -> {This, ok}; -write(This, #protocol_map_begin{ +write(This0, #protocol_map_begin{ ktype = Ktype, vtype = Vtype, size = Size}) -> - write(This, {byte, Ktype}), - write(This, {byte, Vtype}), - write(This, {i32, Size}), - ok; + {This1, ok} = write(This0, {byte, Ktype}), + {This2, ok} = write(This1, {byte, Vtype}), + {This3, ok} = write(This2, {i32, Size}), + {This3, ok}; -write(This, map_end) -> ok; +write(This, map_end) -> {This, ok}; -write(This, #protocol_list_begin{ +write(This0, #protocol_list_begin{ etype = Etype, size = Size}) -> - write(This, {byte, Etype}), - write(This, {i32, Size}), - ok; + {This1, ok} = write(This0, {byte, Etype}), + {This2, ok} = write(This1, {i32, Size}), + {This2, ok}; -write(This, list_end) -> ok; +write(This, list_end) -> {This, ok}; -write(This, #protocol_set_begin{ +write(This0, #protocol_set_begin{ etype = Etype, size = Size}) -> - write(This, {byte, Etype}), - write(This, {i32, Size}), - ok; + {This1, ok} = write(This0, {byte, Etype}), + {This2, ok} = write(This1, {i32, Size}), + {This2, ok}; -write(This, set_end) -> ok; +write(This, set_end) -> {This, ok}; -write(This, #protocol_struct_begin{}) -> ok; -write(This, struct_end) -> ok; +write(This, #protocol_struct_begin{}) -> {This, ok}; +write(This, struct_end) -> {This, ok}; write(This, {bool, true}) -> write(This, {byte, 1}); write(This, {bool, false}) -> write(This, {byte, 0}); @@ -152,153 +154,166 @@ write(This, {i64, I64}) -> write(This, {double, Double}) -> write(This, <>); -write(This, {string, Str}) when is_list(Str) -> - write(This, {i32, length(Str)}), - write(This, list_to_binary(Str)); +write(This0, {string, Str}) when is_list(Str) -> + {This1, ok} = write(This0, {i32, length(Str)}), + {This2, ok} = write(This1, list_to_binary(Str)), + {This2, ok}; -write(This, {string, Bin}) when is_binary(Bin) -> - write(This, {i32, size(Bin)}), - write(This, Bin); +write(This0, {string, Bin}) when is_binary(Bin) -> + {This1, ok} = write(This0, {i32, size(Bin)}), + {This2, ok} = write(This1, Bin), + {This2, ok}; %% Data :: iolist() -write(This, Data) -> - thrift_transport:write(This#binary_protocol.transport, Data). +write(This = #binary_protocol{transport = Trans}, Data) -> + Result = thrift_transport:write(Trans, Data), + {This, Result}. %% -read(This, message_begin) -> - case read(This, ui32) of +read(This0, message_begin) -> + {This1, Initial} = read(This0, ui32), + case Initial of {ok, Sz} when Sz band ?VERSION_MASK =:= ?VERSION_1 -> %% we're at version 1 - {ok, Name} = read(This, string), - Type = Sz band ?TYPE_MASK, - {ok, SeqId} = read(This, i32), - #protocol_message_begin{name = binary_to_list(Name), - type = Type, - seqid = SeqId}; + {This2, {ok, Name}} = read(This1, string), + {This3, {ok, SeqId}} = read(This2, i32), + Type = Sz band ?TYPE_MASK, + {This3, #protocol_message_begin{name = binary_to_list(Name), + type = Type, + seqid = SeqId}}; {ok, Sz} when Sz < 0 -> %% there's a version number but it's unexpected - {error, {bad_binary_protocol_version, Sz}}; + {This1, {error, {bad_binary_protocol_version, Sz}}}; - {ok, Sz} when This#binary_protocol.strict_read =:= true -> + {ok, Sz} when This1#binary_protocol.strict_read =:= true -> %% strict_read is true and there's no version header; that's an error - {error, no_binary_protocol_version}; + {This1, {error, no_binary_protocol_version}}; - {ok, Sz} when This#binary_protocol.strict_read =:= false -> + {ok, Sz} when This1#binary_protocol.strict_read =:= false -> %% strict_read is false, so just read the old way - {ok, Name} = read_data(This, Sz), - {ok, Type} = read(This, byte), - {ok, SeqId} = read(This, i32), - #protocol_message_begin{name = binary_to_list(Name), - type = Type, - seqid = SeqId}; - - Err = {error, closed} -> Err; - Err = {error, timeout}-> Err; - Err = {error, ebadf} -> Err + {This2, {ok, Name}} = read_data(This1, Sz), + {This3, {ok, Type}} = read(This2, byte), + {This4, {ok, SeqId}} = read(This3, i32), + {This4, #protocol_message_begin{name = binary_to_list(Name), + type = Type, + seqid = SeqId}}; + + Else -> + {This1, Else} end; -read(This, message_end) -> ok; +read(This, message_end) -> {This, ok}; -read(This, struct_begin) -> ok; -read(This, struct_end) -> ok; +read(This, struct_begin) -> {This, ok}; +read(This, struct_end) -> {This, ok}; -read(This, field_begin) -> - case read(This, byte) of +read(This0, field_begin) -> + {This1, Result} = read(This0, byte), + case Result of {ok, Type = ?tType_STOP} -> - #protocol_field_begin{type = Type}; + {This1, #protocol_field_begin{type = Type}}; {ok, Type} -> - {ok, Id} = read(This, i16), - #protocol_field_begin{type = Type, - id = Id} + {This2, {ok, Id}} = read(This1, i16), + {This2, #protocol_field_begin{type = Type, + id = Id}} end; -read(This, field_end) -> ok; - -read(This, map_begin) -> - {ok, Ktype} = read(This, byte), - {ok, Vtype} = read(This, byte), - {ok, Size} = read(This, i32), - #protocol_map_begin{ktype = Ktype, - vtype = Vtype, - size = Size}; -read(This, map_end) -> ok; - -read(This, list_begin) -> - {ok, Etype} = read(This, byte), - {ok, Size} = read(This, i32), - #protocol_list_begin{etype = Etype, - size = Size}; -read(This, list_end) -> ok; - -read(This, set_begin) -> - {ok, Etype} = read(This, byte), - {ok, Size} = read(This, i32), - #protocol_set_begin{etype = Etype, - size = Size}; -read(This, set_end) -> ok; - -read(This, field_stop) -> - {ok, ?tType_STOP} = read(This, byte), - ok; +read(This, field_end) -> {This, ok}; + +read(This0, map_begin) -> + {This1, {ok, Ktype}} = read(This0, byte), + {This2, {ok, Vtype}} = read(This1, byte), + {This3, {ok, Size}} = read(This2, i32), + {This3, #protocol_map_begin{ktype = Ktype, + vtype = Vtype, + size = Size}}; +read(This, map_end) -> {This, ok}; + +read(This0, list_begin) -> + {This1, {ok, Etype}} = read(This0, byte), + {This2, {ok, Size}} = read(This1, i32), + {This2, #protocol_list_begin{etype = Etype, + size = Size}}; +read(This, list_end) -> {This, ok}; + +read(This0, set_begin) -> + {This1, {ok, Etype}} = read(This0, byte), + {This2, {ok, Size}} = read(This1, i32), + {This2, #protocol_set_begin{etype = Etype, + size = Size}}; +read(This, set_end) -> {This, ok}; + +read(This0, field_stop) -> + {This1, {ok, ?tType_STOP}} = read(This0, byte), + {This1, ok}; %% -read(This, bool) -> - case read(This, byte) of - {ok, Byte} -> {ok, Byte /= 0}; - Else -> Else +read(This0, bool) -> + {This1, Result} = read(This0, byte), + case Result of + {ok, Byte} -> {This1, {ok, Byte /= 0}}; + Else -> {This1, Else} end; -read(This, byte) -> - case read_data(This, 1) of - {ok, <>} -> {ok, Val}; - Else -> Else +read(This0, byte) -> + {This1, Bytes} = read_data(This0, 1), + case Bytes of + {ok, <>} -> {This1, {ok, Val}}; + Else -> {This1, Else} end; -read(This, i16) -> - case read_data(This, 2) of - {ok, <>} -> {ok, Val}; - Else -> Else +read(This0, i16) -> + {This1, Bytes} = read_data(This0, 2), + case Bytes of + {ok, <>} -> {This1, {ok, Val}}; + Else -> {This1, Else} end; -read(This, i32) -> - case read_data(This, 4) of - {ok, <>} -> {ok, Val}; - Else -> Else +read(This0, i32) -> + {This1, Bytes} = read_data(This0, 4), + case Bytes of + {ok, <>} -> {This1, {ok, Val}}; + Else -> {This1, Else} end; %% unsigned ints aren't used by thrift itself, but it's used for the parsing %% of the packet version header. Without this special function BEAM works fine %% but hipe thinks it received a bad version header. -read(This, ui32) -> - case read_data(This, 4) of - {ok, <>} -> {ok, Val}; - Else -> Else +read(This0, ui32) -> + {This1, Bytes} = read_data(This0, 4), + case Bytes of + {ok, <>} -> {This1, {ok, Val}}; + Else -> {This1, Else} end; -read(This, i64) -> - case read_data(This, 8) of - {ok, <>} -> {ok, Val}; - Else -> Else +read(This0, i64) -> + {This1, Bytes} = read_data(This0, 8), + case Bytes of + {ok, <>} -> {This1, {ok, Val}}; + Else -> {This1, Else} end; -read(This, double) -> - case read_data(This, 8) of - {ok, <>} -> {ok, Val}; - Else -> Else +read(This0, double) -> + {This1, Bytes} = read_data(This0, 8), + case Bytes of + {ok, <>} -> {This1, {ok, Val}}; + Else -> {This1, Else} end; % returns a binary directly, call binary_to_list if necessary -read(This, string) -> - {ok, Sz} = read(This, i32), - {ok, Bin} = read_data(This, Sz). - --spec read_data(#binary_protocol{}, non_neg_integer()) -> {ok, binary()} | {error, _Reason}. -read_data(This, 0) -> {ok, <<>>}; -read_data(This, Len) when is_integer(Len), Len >= 0 -> - thrift_transport:read(This#binary_protocol.transport, Len). +read(This0, string) -> + {This1, {ok, Sz}} = read(This0, i32), + read_data(This1, Sz). + +-spec read_data(#binary_protocol{}, non_neg_integer()) -> + {#binary_protocol{}, {ok, binary()} | {error, _Reason}}. +read_data(This, 0) -> {This, {ok, <<>>}}; +read_data(This = #binary_protocol{transport = Trans}, Len) when is_integer(Len) andalso Len > 0 -> + Result = thrift_transport:read(Trans, Len), + {This, Result}. %%%% FACTORY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%