/echubby/deps/protobuffs/ebin/enum_pb.erl

http://erlang-lab.googlecode.com/ · Erlang · 148 lines · 127 code · 21 blank · 0 comment · 0 complexity · b02d4b429425dd9904eeb46fe635c263 MD5 · raw file

  1. -file("src/enum_pb.erl", 1).
  2. -module(enum_pb).
  3. -export([encode_enummsg/1, decode_enummsg/1]).
  4. -export([encode/1, decode/2, iolist/2]).
  5. -record(enummsg, {value}).
  6. encode(Record) -> encode(element(1, Record), Record).
  7. encode_enummsg(Record)
  8. when is_record(Record, enummsg) ->
  9. encode(enummsg, Record).
  10. encode(enummsg, Record) ->
  11. iolist_to_binary(iolist(enummsg, Record)).
  12. iolist(enummsg, Record) ->
  13. [pack(1, optional,
  14. with_default(Record#enummsg.value, none),
  15. enummsg_values, [])].
  16. with_default(undefined, none) -> undefined;
  17. with_default(undefined, Default) -> Default;
  18. with_default(Val, _) -> Val.
  19. pack(_, optional, undefined, _, _) -> [];
  20. pack(_, repeated, undefined, _, _) -> [];
  21. pack(_, repeated_packed, undefined, _, _) -> [];
  22. pack(_, repeated_packed, [], _, _) -> [];
  23. pack(FNum, required, undefined, Type, _) ->
  24. exit({error,
  25. {required_field_is_undefined, FNum, Type}});
  26. pack(_, repeated, [], _, Acc) -> lists:reverse(Acc);
  27. pack(FNum, repeated, [Head | Tail], Type, Acc) ->
  28. pack(FNum, repeated, Tail, Type,
  29. [pack(FNum, optional, Head, Type, []) | Acc]);
  30. pack(FNum, repeated_packed, Data, Type, _) ->
  31. protobuffs:encode_packed(FNum, Data, Type);
  32. pack(FNum, _, Data, _, _) when is_tuple(Data) ->
  33. [RecName | _] = tuple_to_list(Data),
  34. protobuffs:encode(FNum, encode(RecName, Data), bytes);
  35. pack(FNum, _, Data, Type, _)
  36. when Type =:= bool;
  37. Type =:= int32;
  38. Type =:= uint32;
  39. Type =:= int64;
  40. Type =:= uint64;
  41. Type =:= sint32;
  42. Type =:= sint64;
  43. Type =:= fixed32;
  44. Type =:= sfixed32;
  45. Type =:= fixed64;
  46. Type =:= sfixed64;
  47. Type =:= string;
  48. Type =:= bytes;
  49. Type =:= float;
  50. Type =:= double ->
  51. protobuffs:encode(FNum, Data, Type);
  52. pack(FNum, _, Data, Type, _) when is_atom(Data) ->
  53. protobuffs:encode(FNum, enum_to_int(Type, Data), enum).
  54. enum_to_int(enummsg_values, value2) -> 2;
  55. enum_to_int(enummsg_values, value1) -> 1.
  56. int_to_enum(enummsg_values, 2) -> value2;
  57. int_to_enum(enummsg_values, 1) -> value1;
  58. int_to_enum(_, Val) -> Val.
  59. decode_enummsg(Bytes) when is_binary(Bytes) ->
  60. decode(enummsg, Bytes).
  61. decode(enummsg_values, 1) -> value1;
  62. decode(enummsg, Bytes) when is_binary(Bytes) ->
  63. Types = [{1, value, enummsg_values, []}],
  64. Decoded = decode(Bytes, Types, []),
  65. to_record(enummsg, Decoded).
  66. decode(<<>>, _, Acc) -> Acc;
  67. decode(Bytes, Types, Acc) ->
  68. {ok, FNum} = protobuffs:next_field_num(Bytes),
  69. case lists:keysearch(FNum, 1, Types) of
  70. {value, {FNum, Name, Type, Opts}} ->
  71. {Value1, Rest1} = case lists:member(is_record, Opts) of
  72. true ->
  73. {{FNum, V}, R} = protobuffs:decode(Bytes,
  74. bytes),
  75. RecVal =
  76. decode(list_to_atom(string:to_lower(atom_to_list(Type))),
  77. V),
  78. {RecVal, R};
  79. false ->
  80. case lists:member(repeated_packed, Opts) of
  81. true ->
  82. {{FNum, V}, R} =
  83. protobuffs:decode_packed(Bytes,
  84. Type),
  85. {V, R};
  86. false ->
  87. {{FNum, V}, R} =
  88. protobuffs:decode(Bytes, Type),
  89. {unpack_value(V, Type), R}
  90. end
  91. end,
  92. case lists:member(repeated, Opts) of
  93. true ->
  94. case lists:keytake(FNum, 1, Acc) of
  95. {value, {FNum, Name, List}, Acc1} ->
  96. decode(Rest1, Types,
  97. [{FNum, Name,
  98. lists:reverse([int_to_enum(Type, Value1)
  99. | lists:reverse(List)])}
  100. | Acc1]);
  101. false ->
  102. decode(Rest1, Types,
  103. [{FNum, Name, [int_to_enum(Type, Value1)]} | Acc])
  104. end;
  105. false ->
  106. decode(Rest1, Types,
  107. [{FNum, Name, int_to_enum(Type, Value1)} | Acc])
  108. end;
  109. false -> exit({error, {unexpected_field_index, FNum}})
  110. end.
  111. unpack_value(Binary, string) when is_binary(Binary) ->
  112. binary_to_list(Binary);
  113. unpack_value(Value, _) -> Value.
  114. to_record(enummsg, DecodedTuples) ->
  115. lists:foldl(fun ({_FNum, Name, Val}, Record) ->
  116. set_record_field(record_info(fields, enummsg), Record,
  117. Name, Val)
  118. end,
  119. #enummsg{}, DecodedTuples).
  120. set_record_field(Fields, Record, Field, Value) ->
  121. Index = list_index(Field, Fields),
  122. erlang:setelement(Index + 1, Record, Value).
  123. list_index(Target, List) -> list_index(Target, List, 1).
  124. list_index(Target, [Target | _], Index) -> Index;
  125. list_index(Target, [_ | Tail], Index) ->
  126. list_index(Target, Tail, Index + 1);
  127. list_index(_, [], _) -> 0.