Read and write of structs, lists, maps, and sets
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@666375 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/alterl/src/thrift_protocol.erl b/lib/alterl/src/thrift_protocol.erl
index 66e19b3..75c2d4b 100644
--- a/lib/alterl/src/thrift_protocol.erl
+++ b/lib/alterl/src/thrift_protocol.erl
@@ -27,10 +27,6 @@
data = Data}}.
-write(#protocol{module = Module,
- data = ModuleData}, Data) ->
- Module:write(ModuleData, Data).
-
typeid_to_atom(?tType_STOP) -> field_stop;
typeid_to_atom(?tType_VOID) -> void;
typeid_to_atom(?tType_BOOL) -> bool;
@@ -45,10 +41,92 @@
typeid_to_atom(?tType_SET) -> set;
typeid_to_atom(?tType_LIST) -> list.
+
+term_to_typeid(void) -> ?tType_VOID;
+term_to_typeid(bool) -> ?tType_BOOL;
+term_to_typeid(byte) -> ?tType_BYTE;
+term_to_typeid(double) -> ?tType_DOUBLE;
+term_to_typeid(i16) -> ?tType_I16;
+term_to_typeid(i32) -> ?tType_I32;
+term_to_typeid(i64) -> ?tType_I64;
+term_to_typeid(string) -> ?tType_STRING;
+term_to_typeid({struct, _}) -> ?tType_STRUCT;
+term_to_typeid({map, _, _}) -> ?tType_MAP;
+term_to_typeid({set, _}) -> ?tType_SET;
+term_to_typeid({list, _}) -> ?tType_LIST.
+
+
+%% Structure is like:
+%% [{Fid, Type}, ...]
+read(IProto, {struct, Structure}) when is_list(Structure) ->
+ SWithIndices = [{Fid, {Type, Index}} ||
+ {{Fid, Type}, Index} <-
+ lists:zip(Structure, lists:seq(1, length(Structure)))],
+ % Fid -> {Type, Index}
+ SDict = dict:from_list(SWithIndices),
+
+
+ ok = read(IProto, struct_begin),
+ RDict = read_struct_loop(IProto, SDict, dict:new()),
+
+ List = [case dict:find(Index, RDict) of
+ {ok, Val} -> Val;
+ error -> undefined
+ end || Index <- lists:seq(1, length(Structure))],
+ {ok, list_to_tuple(List)};
+
+read(IProto, {list, Type}) ->
+ #protocol_list_begin{etype = EType, size = Size} =
+ read(IProto, list_begin),
+ List = [Result || {ok, Result} <-
+ [read(IProto, Type) || _X <- lists:seq(1, Size)]],
+ ok = read(IProto, list_end),
+ {ok, List};
+
+read(IProto, {map, KeyType, ValType}) ->
+ #protocol_map_begin{size = Size} =
+ read(IProto, map_begin),
+
+ List = [{Key, Val} || {{ok, Key}, {ok, Val}} <-
+ [{read(IProto, KeyType),
+ read(IProto, ValType)} || _X <- lists:seq(1, Size)]],
+ ok = read(IProto, map_end),
+ {ok, dict:from_list(List)};
+
+read(IProto, {set, Type}) ->
+ #protocol_set_begin{etype = _EType,
+ size = Size} =
+ read(IProto, set_begin),
+ List = [Result || {ok, Result} <-
+ [read(IProto, Type) || _X <- lists:seq(1, Size)]],
+ ok = read(IProto, set_end),
+ {ok, sets:from_list(List)};
+
read(#protocol{module = Module,
data = ModuleData}, ProtocolType) ->
Module:read(ModuleData, ProtocolType).
+read_struct_loop(IProto, SDict, RDict) ->
+ #protocol_field_begin{type = FType, id = Fid, name = Name} =
+ thrift_protocol:read(IProto, field_begin),
+ case {FType, Fid} of
+ {?tType_STOP, _} ->
+ RDict;
+ _Else ->
+ case dict:find(Fid, SDict) of
+ {ok, {Type, Index}} ->
+ {ok, Val} = read(IProto, Type),
+ thrift_protocol:read(IProto, field_end),
+ NewRDict = dict:store(Index, Val, RDict),
+ read_struct_loop(IProto, SDict, NewRDict);
+ _Else2 ->
+ error_logger:info_msg("Skipping fid ~p~n", [Fid]),
+ FTypeAtom = thrift_protocol:typeid_to_atom(FType),
+ thrift_protocol:skip(IProto, FTypeAtom),
+ read(IProto, field_end),
+ read_struct_loop(IProto, SDict, RDict)
+ end
+ end.
skip(Proto, struct) ->
@@ -118,3 +196,98 @@
Map#protocol_list_begin{size = Size - 1});
0 -> ok
end.
+
+
+%%--------------------------------------------------------------------
+%% Function: write(OProto, {Type, Data}) -> ok
+%%
+%% Type = {struct, StructDef} |
+%% {list, Type} |
+%% {map, KeyType, ValType} |
+%% {set, Type} |
+%% BaseType
+%%
+%% Data =
+%% tuple() -- for struct
+%% | list() -- for list
+%% | dictionary() -- for map
+%% | set() -- for set
+%% | term() -- for base types
+%%
+%% Description:
+%%--------------------------------------------------------------------
+write(Proto, {{struct, StructDef}, Data})
+ when is_list(StructDef), is_tuple(Data), length(StructDef) == size(Data) ->
+ ok = write(Proto, #protocol_struct_begin{}),
+ ok = struct_write_loop(Proto, StructDef, tuple_to_list(Data)),
+ ok = write(Proto, struct_end),
+ ok;
+
+write(Proto, {{list, Type}, Data})
+ when is_list(Data) ->
+ ok = write(Proto,
+ #protocol_list_begin{
+ etype = term_to_typeid(Type),
+ size = length(Data)
+ }),
+ lists:foreach(fun(Elem) ->
+ ok = write(Proto, {Type, Elem})
+ end,
+ Data),
+ ok = write(Proto, list_end),
+ ok;
+
+write(Proto, {{map, KeyType, ValType}, Data}) ->
+ DataList = dict:to_list(Data),
+ ok = write(Proto,
+ #protocol_map_begin{
+ ktype = term_to_typeid(KeyType),
+ vtype = term_to_typeid(ValType),
+ size = length(DataList)
+ }),
+ lists:foreach(fun({KeyData, ValData}) ->
+ ok = write(Proto, {KeyType, KeyData}),
+ ok = write(Proto, {ValType, ValData})
+ end,
+ DataList),
+ ok = write(Proto, map_end),
+ ok;
+
+write(Proto, {{set, Type}, Data}) ->
+ true = sets:is_set(Data),
+ DataList = sets:to_list(Data),
+ ok = write(Proto,
+ #protocol_set_begin{
+ etype = term_to_typeid(Type),
+ size = length(DataList)
+ }),
+ lists:foreach(fun(Elem) ->
+ ok = write(Proto, {Type, Elem})
+ end,
+ DataList),
+ ok = write(Proto, set_end),
+ ok;
+
+write(#protocol{module = Module,
+ data = ModuleData}, Data) ->
+ Module:write(ModuleData, Data).
+
+
+struct_write_loop(Proto, [{Fid, Type} | RestStructDef], [Data | RestData]) ->
+ case Data of
+ undefined ->
+ % null fields are skipped in response
+ skip;
+ _ ->
+ ok = write(Proto,
+ #protocol_field_begin{
+ type = term_to_typeid(Type),
+ id = Fid
+ }),
+ ok = write(Proto, {Type, Data}),
+ ok = write(Proto, field_end)
+ end,
+ struct_write_loop(Proto, RestStructDef, RestData);
+struct_write_loop(Proto, [], []) ->
+ ok = write(Proto, field_stop),
+ ok.