Skip to content

Commit

Permalink
Merge branches 'plus-minus-zero', 'enum-macros', 'pre-encoded-submsgs…
Browse files Browse the repository at this point in the history
…' and 'no-gen-encoders-decoders'

New options:

- enum_macros
- {rename, {What, uppercase}}
- {rename, {enum_macros, How}}
- allow_preencoded_submsgs
- {gen_encoders,bool()}
- {gen_decoders,bool()}

Bugfix the rename lowercase option to work also	from the cmdline.

Work with Erlang 26.1 which now warns for exact comparisons with 0.0.
One has to compare with +0.0 instead (if that is what one wants).
  • Loading branch information
tomas-abrahamsson committed Oct 1, 2023
5 parents 45d7f9e + 0b2aac6 + 25293de + 2ee8064 + 894561f commit b717f05
Show file tree
Hide file tree
Showing 13 changed files with 584 additions and 101 deletions.
4 changes: 2 additions & 2 deletions src/gpb.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1631,13 +1631,13 @@ proto3_type_default(Type, MsgDefs) ->
bool -> false;
fixed64 -> 0;
sfixed64 -> 0;
double -> 0.0;
double -> 0.0; % only +0.0 is the type-default
string -> "";
bytes -> <<>>;
{msg,_} -> undefined;
fixed32 -> 0;
sfixed32 -> 0;
float -> 0.0;
float -> 0.0; % only +0.0 is the type-default
{map,_KT,_VT} -> [];
{enum, _EnumName}=Key ->
{Key, EnumDef} = lists:keyfind(Key, 1, MsgDefs),
Expand Down
295 changes: 237 additions & 58 deletions src/gpb_compile.erl

Large diffs are not rendered by default.

33 changes: 31 additions & 2 deletions src/gpb_gen_encoders.erl
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ format_msg_encoder(MsgName, MsgDef, Defs, AnRes, Opts, IncludeStarter) ->
replace_tree('M', MsgVar)])
end
end,
AllowPreencodedSubmsgs = proplists:get_bool(allow_preencoded_submsgs, Opts),
[[[[[gpb_codegen:format_fn(
gpb_lib:mk_fn(encode_msg_, MsgName),
fun(Msg) ->
Expand All @@ -317,10 +318,19 @@ format_msg_encoder(MsgName, MsgDef, Defs, AnRes, Opts, IncludeStarter) ->
"\n"] || IncludeStarter],
gpb_codegen:format_fn(
FnName,
fun('<msg-matching>', Bin, TrUserData) ->
fun('Preencoded', _Bin, _TrUserData) when is_binary('Preencoded') ->
'Preencoded';
('<msg-matching>', Bin, TrUserData) ->
'<encode-param-exprs>'
end,
[replace_tree('<msg-matching>', FieldMatching),
[repeat_clauses(
'Preencoded',
if AllowPreencodedSubmsgs ->
[[replace_tree('Preencoded', gpb_lib:var("Preencoded", []))]];
not AllowPreencodedSubmsgs ->
[] % don't include this clause at all
end),
replace_tree('<msg-matching>', FieldMatching),
splice_trees('<encode-param-exprs>', EncodeExprs)])].

field_encode_expr(MsgName, MsgVar, #?gpb_field{name=FName}=Field,
Expand Down Expand Up @@ -418,6 +428,25 @@ field_encode_expr(MsgName, MsgVar, #?gpb_field{name=FName}=Field,
end
end,
Transforms);
Type == float;
Type == double ->
%% Need to compare with +0.0 since Erl 26.1 to avoid
%% compilation warnings. Only +0.0 is the type default.
?expr(
begin
'TrF' = 'Tr'('<F>', 'TrUserData'),
if 'TrF' =:= '+0.0';
'TrF' =:= 0 ->
'<Bin>';
true ->
'<enc>'('TrF',
<<'<Bin>'/binary, '<Key>'>>,
'TrUserData')
end
end,
[replace_tree('+0.0', erl_syntax:text("+0.0"))
| Transforms]);

IsEnum ->
TypeDefault = gpb:proto3_type_default(Type, Defs),
?expr(
Expand Down
3 changes: 2 additions & 1 deletion src/gpb_gen_json_decoders.erl
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,8 @@ mk_check_null_decode_value_update_field_expr(
end,
?expr(if 'JValueExpr' =:= null;
'JValueExpr' =:= 0;
'JValueExpr' =:= 0.0;
'JValueExpr' =:= +0.0;
'JValueExpr' =:= -0.0;
is_jstring('JValueExpr') ->
'<update-field-expr>';
is_number('JValueExpr') ->
Expand Down
18 changes: 18 additions & 0 deletions src/gpb_gen_json_encoders.erl
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,24 @@ field_to_json_expr(MsgName, MsgVar, #?gpb_field{name=FName}=Field,
end,
[replace_tree('<enc>', FEncoderExpr(TrFVar)) |
Transforms]);
Type == float;
Type == double ->
%% Need to compare with +0.0 since Erl 26.1 to avoid
%% compilation warnings. Only +0.0 is the type default.
?expr(
begin
'TrF' = 'Tr'('F', 'TrUserData'),
if 'TrF' =:= '+0.0';
'TrF' =:= 0 ->
'Json';
true ->
tj_add_field(jfieldname, '<enc>',
'Json')
end
end,
[replace_tree('+0.0', erl_syntax:text("+0.0")),
replace_tree('<enc>', FEncoderExpr(TrFVar)) |
Transforms]);
IsEnum ->
TypeDefault = gpb:proto3_type_default(Type, Defs),
?expr(
Expand Down
17 changes: 12 additions & 5 deletions src/gpb_gen_types.erl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
map_type_fields :: '2tuples' | maps,
module :: module(),
nif :: boolean(),
verify_decode_required_present :: boolean()}).
verify_decode_required_present :: boolean(),
allow_preencoded_submsgs :: boolean()}).

-record(type_text,
{text :: string(),
Expand Down Expand Up @@ -208,14 +209,16 @@ t_env(Opts) ->
Mod = proplists:get_value(module, Opts),
Nif = proplists:get_bool(nif, Opts),
DecVfy = proplists:get_bool(verify_decode_required_present, Opts),
AllowPreencodedSubmsgs = proplists:get_bool(allow_preencoded_submsgs, Opts),
#t_env{type_specs = TypeSpecs,
can_do_map_presence = TypespecsCanIndicateMapItemPresence,
mapping_and_unset = MappingAndUnset,
map_key_type = KeyType,
map_type_fields = MapTypeFieldsRepr,
module = Mod,
nif = Nif,
verify_decode_required_present = DecVfy}.
verify_decode_required_present = DecVfy,
allow_preencoded_submsgs = AllowPreencodedSubmsgs}.

calc_keytype_override([], _TEnv) ->
no_override;
Expand Down Expand Up @@ -766,13 +769,17 @@ float_spec() ->
msg_to_typestr(M, AnRes, TEnv) ->
MsgType = rename_msg_type(M, AnRes),
#t_env{mapping_and_unset=MappingAndUnset,
module = Mod} = TEnv,
module = Mod,
allow_preencoded_submsgs=AllowPreencodedSubmsgs} = TEnv,
OrBinary = if AllowPreencodedSubmsgs -> " | binary()";
true -> ""
end,
case MappingAndUnset of
records ->
%% Prefix with module since records live in an hrl file
?f("~p:~p()", [Mod, MsgType]);
?f("~p:~p()~s", [Mod, MsgType, OrBinary]);
#maps{} ->
?f("~p()", [MsgType])
?f("~p()~s", [MsgType, OrBinary])
end.

enum_typestr(E, Defs, #t_env{nif=Nif}) ->
Expand Down
47 changes: 40 additions & 7 deletions src/gpb_gen_verifiers.erl
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,41 @@ format_verifiers(Defs, AnRes, Opts) ->
].

format_msg_verifiers(Defs, AnRes, Opts) ->
[format_msg_verifier(MsgName, MsgDef, AnRes, Opts)
|| {_Type, MsgName, MsgDef} <- gpb_lib:msgs_or_groups(Defs)].
[[case Type == msg andalso can_occur_as_submsg(MsgName, AnRes) of
true -> format_submsg_verifier_wrapper(MsgName, Opts);
false -> []
end,
format_msg_verifier(MsgName, MsgDef, AnRes, Opts)]
|| {Type, MsgName, MsgDef} <- gpb_lib:msgs_or_groups(Defs)].

can_occur_as_submsg(MsgName, #anres{used_types=UsedTypes}) ->
gpb_lib:smember({msg, MsgName}, UsedTypes).

format_submsg_verifier_wrapper(MsgName, Opts) ->
FnNameSub = gpb_lib:mk_fn(v_submsg_, MsgName),
FnName = gpb_lib:mk_fn(v_msg_, MsgName),
case proplists:get_bool(allow_preencoded_submsgs, Opts) of
true ->
[gpb_lib:nowarn_unused_function(FnNameSub, 3),
gpb_lib:nowarn_dialyzer_attr(FnNameSub, 3,Opts),
gpb_codegen:format_fn(
FnNameSub,
fun(Preencoded, _Path, _TrUserData) when is_binary(Preencoded) ->
ok;
(Msg, Path, TrUserData) ->
'FnName'(Msg, Path, TrUserData)
end,
[replace_term('FnName', FnName)])];
false ->
[gpb_lib:nowarn_unused_function(FnNameSub, 3),
gpb_lib:nowarn_dialyzer_attr(FnNameSub, 3,Opts),
gpb_codegen:format_fn(
FnNameSub,
fun(Msg, Path, TrUserData) ->
'FnName'(Msg, Path, TrUserData)
end,
[replace_term('FnName', FnName)])]
end.

format_msg_verifier(MsgName, MsgDef0, AnRes, Opts) ->
MsgDef1 = drop_field_for_unknown_if_present(MsgDef0),
Expand Down Expand Up @@ -254,7 +287,7 @@ field_verifier(MsgName,
FVar, MsgVar, TrUserDataVar, AnRes, Opts) ->
FVerifierFn =
case Type of
{msg,FMsgName} -> gpb_lib:mk_fn(v_msg_, FMsgName);
{msg,FMsgName} -> gpb_lib:mk_fn(v_submsg_, FMsgName);
{group,GName} -> gpb_lib:mk_fn(v_msg_, GName);
{enum,EnumName} -> gpb_lib:mk_fn(v_enum_, EnumName);
{map,KT,VT} -> gpb_lib:mk_fn(v_, gpb_lib:map_type_to_msg_name(
Expand Down Expand Up @@ -524,7 +557,7 @@ field_oneof_present_undefined_verifier(MsgName, FName, OFields,
FVerifierFn =
case Type of
{msg,FMsgName} ->
gpb_lib:mk_fn(v_msg_, FMsgName);
gpb_lib:mk_fn(v_submsg_, FMsgName);
{enum,EnumName} ->
gpb_lib:mk_fn(v_enum_, EnumName);
Type ->
Expand Down Expand Up @@ -581,7 +614,7 @@ field_oneof_omitted_tuples_verifier(MsgName, FName, OFields,
[begin
FVerifierFn =
case Type of
{msg,FMsgName} -> gpb_lib:mk_fn(v_msg_, FMsgName);
{msg,FMsgName} -> gpb_lib:mk_fn(v_submsg_, FMsgName);
{enum,EnumName} -> gpb_lib:mk_fn(v_enum_, EnumName);
Type -> gpb_lib:mk_fn(v_type_, Type)
end,
Expand Down Expand Up @@ -645,7 +678,7 @@ field_oneof_omitted_flat_verifier(MsgName, FName, OFields,
[begin
FVerifierFn =
case Type of
{msg,FMsgName} -> gpb_lib:mk_fn(v_msg_, FMsgName);
{msg,FMsgName} -> gpb_lib:mk_fn(v_submsg_, FMsgName);
{enum,EnumName} -> gpb_lib:mk_fn(v_enum_, EnumName);
Type -> gpb_lib:mk_fn(v_type_, Type)
end,
Expand Down Expand Up @@ -818,7 +851,7 @@ format_map_verifier(KeyType, ValueType, MapsOrTuples, AnRes, Opts) ->
FnName = gpb_lib:mk_fn(v_, MsgName),
KeyVerifierFn = gpb_lib:mk_fn(v_type_, KeyType),
ValueVerifierFn1 = case ValueType of
{msg,FMsgName} -> gpb_lib:mk_fn(v_msg_, FMsgName);
{msg,FMsgName} -> gpb_lib:mk_fn(v_submsg_,FMsgName);
{enum,EnumName} -> gpb_lib:mk_fn(v_enum_, EnumName);
Type -> gpb_lib:mk_fn(v_type_, Type)
end,
Expand Down
12 changes: 12 additions & 0 deletions src/gpb_lib.erl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
-export([get_defs_as_maps_or_records/1]).
-export([get_epb_functions_by_opts/1]).
-export([get_bypass_wrappers_by_opts/1]).
-export([get_enum_macros_by_opts/1]).
-export([is_target_major_version_at_least/2]).
-export([target_has_lists_join/1]).
-export([target_has_variable_key_map_update/1]).
Expand All @@ -110,6 +111,8 @@
-export([get_gen_mergers/1]).
-export([get_gen_introspect/1]).
-export([get_gen_verifiers/1]).
-export([get_gen_encoders/1]).
-export([get_gen_decoders/1]).

-export([var_f_n/1]).
-export([var_b_n/1]).
Expand Down Expand Up @@ -703,6 +706,9 @@ get_epb_functions_by_opts(Opts) ->
get_bypass_wrappers_by_opts(Opts) ->
proplists:get_bool(bypass_wrappers, Opts).

get_enum_macros_by_opts(Opts) ->
proplists:get_bool(gen_enum_macros, Opts).

is_target_major_version_at_least(VsnMin, Opts) ->
case proplists:get_value(target_erlang_version, Opts, current) of
current ->
Expand Down Expand Up @@ -880,6 +886,12 @@ get_gen_introspect(Opts) ->
get_gen_verifiers(Opts) ->
proplists:get_value(gen_verifiers, Opts, true).

get_gen_encoders(Opts) ->
proplists:get_value(gen_encoders, Opts, true).

get_gen_decoders(Opts) ->
proplists:get_value(gen_decoders, Opts, true).

%% Syntax tree stuff ----

var_f_n(N) -> var_n("F", N).
Expand Down
16 changes: 15 additions & 1 deletion src/gpb_names.erl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

-export([file_name_to_module_name/2]).
-export([rename_module/2]).
-export([rename_enum_macro/2]).
-export([rename_defs/2]).
-export([compute_renamings/2]).
-export([apply_renamings/2]).
Expand Down Expand Up @@ -102,6 +103,13 @@ possibly_suffix_mod(BaseNameNoExt, Opts) ->
lists:concat([BaseNameNoExt, Suffix])
end.

%% @doc Given an enum macro name, rename it according to opts, for example
%% by prefixing it.
-spec rename_enum_macro(atom(), gpb_compile:opts()) -> atom().
rename_enum_macro(EnumMacro, Opts) when is_atom(EnumMacro) ->
RenameOps = [How || {rename, {enum_macro, How}} <- Opts],
lists:foldl(fun do_prim_op/2, EnumMacro, RenameOps).

%% @doc Rename definitions according to options, for example
%% lowercasing message names.
%%
Expand Down Expand Up @@ -273,7 +281,11 @@ l_msg_and_service_and_rpc_opts(Value) ->
%% -- Renaming opts -> renaming functions ------------------

mk_rename_operations(Opts) ->
[{What, mk_rename_op(What, How)} || {rename, {What, How}} <- Opts].
[{What, mk_rename_op(What, How)} || {rename, {What, How}} <- Opts,
is_def_related_rename(What)].

is_def_related_rename(enum_macro) -> false;
is_def_related_rename(_) -> true.

mk_rename_op(pkg_name, How) -> mk_pkg_rename_op(How);
mk_rename_op(msg_fqname, How) -> mk_msg_rename_op(How);
Expand Down Expand Up @@ -319,6 +331,8 @@ do_prim_op({suffix, Suffix}, Name) ->
list_to_atom(lists:concat([Name, Suffix]));
do_prim_op(lowercase, Name) ->
list_to_atom(gpb_lib:lowercase(atom_to_list(Name)));
do_prim_op(uppercase, Name) ->
list_to_atom(gpb_lib:uppercase(atom_to_list(Name)));
do_prim_op(snake_case, Name) ->
list_to_atom(gpb_lib:snake_case(atom_to_list(Name)));
do_prim_op(dots_to_underscores, Name) ->
Expand Down
Loading

0 comments on commit b717f05

Please sign in to comment.