Current section
Files
Jump to
Current section
Files
src/generate_proto_info.erl
-module(generate_proto_info).
-export([
generate/3,
test/0
]).
%% create proto_info.erl file
generate(AppInfo, _State, MetaList) ->
AppDir = rebar_app_info:dir(AppInfo),
Opts = rebar_app_info:opts(AppInfo),
{ok, ProtoOpts} = dict:find(proto_opts, Opts),
ProtoInfoFile = proplists:get_value(o_proto_info, ProtoOpts, "proto_info.erl"),
OutProtoInfo = filename:join([AppDir, ProtoInfoFile]),
CustomInfoFile = proplists:get_value(custom_info, ProtoOpts, undefined),
generate_proto_info(MetaList, OutProtoInfo, CustomInfoFile),
ok.
generate_proto_info(MetaList, OutProtoInfo, CustomInfoFile) ->
ModuleName = erlang:list_to_atom(filename:rootname(filename:basename(OutProtoInfo))),
Module = generate_module(ModuleName, MetaList, CustomInfoFile),
Formatted = erl_prettypr:format(Module),
ok = file:write_file(OutProtoInfo, Formatted),
ok.
generate_module(ModName, MetaList, CustomInfoFile) ->
Mod = erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(ModName)]),
DefaultExportList = [ erl_syntax:arity_qualifier(erl_syntax:atom(Fun), erl_syntax:integer(1))
|| Fun <- [get_msg_name, get_msg_code, get_msg_pbmodule] ],
DefaultClauses = lists:append([Fun(MetaList) || Fun <- [fun generate_get_msg_name/1,
fun generate_get_msg_code/1,
fun generate_get_msg_pbmodule/1]]),
[CustomExportList, CustomClaues] = generate_custom_info(CustomInfoFile, MetaList),
Export = erl_syntax:attribute(erl_syntax:atom(export),
[erl_syntax:list(DefaultExportList++CustomExportList)]),
Clauses = DefaultClauses++CustomClaues,
erl_syntax:form_list([Mod, Export| Clauses]).
%% get_msg_name(MsgCode) -> MsgName.
generate_get_msg_name(MetaList) ->
ClausesMapsList = [ #{args => [MsgCode], return => MsgName}
|| #{msg_name := MsgName, msg_code := MsgCode} <- MetaList],
general_create_function(#{fun_name => get_msg_name,
clauses => ClausesMapsList}).
%% get_msg_code(MsgName) -> MsgCode.
generate_get_msg_code(MetaList) ->
ClausesMapsList = [ #{args => [MsgName], return => MsgCode}
|| #{msg_name := MsgName, msg_code := MsgCode} <- MetaList],
general_create_function(#{fun_name => get_msg_code,
clauses => ClausesMapsList}).
%% get_msg_pbmodule(MsgCode) -> PbModule.
generate_get_msg_pbmodule(MetaList) ->
ClausesMapsList = [ #{args => [MsgCode], return => PbModule}
|| #{msg_code := MsgCode, pb_module := PbModule} <- MetaList],
general_create_function(#{fun_name => get_msg_pbmodule,
clauses => ClausesMapsList}).
%% generate custom function
generate_custom_info(undefined, _) ->
[];
generate_custom_info(CustomInfoFile, MetaList) ->
rebar_api:debug("load module file: ~p~n", [{filename:rootname(CustomInfoFile, ".erl")}]),
{ok, Mod, Bin} = compile:file(filename:rootname(CustomInfoFile, ".erl"), [binary, {i, "include/"}]),
code:load_binary(Mod, [], Bin),
generate_custom_info_1(MetaList, Mod:fun_list(), [], []).
generate_custom_info_1(_MetaList, [], AccExportList, AccFunList) ->
[AccExportList, AccFunList];
generate_custom_info_1(MetaList, [HFun|TFun], AccExportList, AccFunList) ->
#{fun_name := FunName} = ClausesMapsList = HFun(MetaList),
Export = erl_syntax:arity_qualifier(erl_syntax:atom(FunName), erl_syntax:integer(1)),
Clauses = general_create_function(ClausesMapsList),
generate_custom_info_1(MetaList, TFun, AccExportList++[Export], AccFunList++Clauses).
%% MFA, A always a list
general_create_function(#{fun_name:=FunName, clauses:=ClausesMapsList}) ->
Name = erl_syntax:atom(FunName),
Clauses = [ erl_syntax:clause(general_create_function_variable(Args), none, [general_create_function_variable(Return)])
|| #{args := Args,
return := Return} <- ClausesMapsList ],
AlwaysMatch = erl_syntax:clause([erl_syntax:underscore()], none, [erl_syntax:atom(undefined)]),
[ erl_syntax:function(Name, Clauses ++ [AlwaysMatch]) ].
%% conver variable
general_create_function_variable(Var) when is_atom(Var) ->
erl_syntax:atom(Var);
general_create_function_variable(Var) when is_integer(Var) ->
erl_syntax:integer(Var);
general_create_function_variable(Var) when is_list(Var) ->
[general_create_function_variable(VarX) || VarX <- Var];
general_create_function_variable(Var) when is_tuple(Var) ->
List = tuple_to_list(Var),
List1 = general_create_function_variable(List),
list_to_tuple(List1).
test() ->
List = [#{msg_name => list_to_atom("msg" ++ integer_to_list(X)),
msg_code => 1000+X,
pb_module => list_to_atom("pb_msg" ++ integer_to_list(X))} || X <- lists:seq(1,8000)],
{Micros, Res} = timer:tc(fun generate_proto_info/3, [List, "proto.erl", undefined]),
io:format("haoxian ~p~n", [{Micros, Res}]).