anchor.diff:  mk_field_encode_fn_name(_MsgName, #field{type=Type}) ->
       mk_fn(e_type_, Type).
   
  -format_special_field_encoders(Defs) ->
  -    [[format_field_encoder(MsgName, FieldDef, Defs)
  +format_special_field_encoders(Defs, AnRes) ->
  +    [[format_field_encoder(MsgName, FieldDef, AnRes)
         || #field{occurrence=Occ, type=Type}=FieldDef <- MsgDef,
            Occ == repeated orelse is_msg_type(Type)]
        || {{msg,MsgName}, MsgDef} <- Defs].
  
positive.code:      end].
  
  possibly_format_mfield_encoder(MsgName, #field{type={msg,SubMsg}}=FieldDef,
                                 Defs) ->
      FnName = mk_field_encode_fn_name(MsgName, FieldDef),
      case is_msgsize_known_at_compiletime(SubMsg, Defs) of
          no ->
              [f("~p(Msg, Bin) ->~n", [FnName]),
               f("    SubBin = ~p(Msg, <<>>),~n", [mk_fn(e_msg_, SubMsg)]),
  
negative.code:                 end,
                  InitAcc,
                  Defs).
  
  find_msgsizes_known_at_compile_time(Defs) ->
      T = ets:new(gpb_msg_sizes, [set, public]),
      [find_msgsize(MsgName, Defs, T) || {{msg,MsgName},_Fields} <- Defs],
      Result = dict:from_list(ets:tab2list(T)),
      ets:delete(T),
      Result.
  
  find_msgsize(MsgName, Defs, T) ->
      case ets:lookup(T, MsgName) of
          [] ->
              {{msg,MsgName}, Fields} = lists:keyfind({msg,MsgName}, 1, Defs),
              Result = find_msgsize_2(Fields, 0, Defs, T),
              ets:insert(T, {MsgName, Result}),
              Result;
          [{MsgName, Result}] ->
              Result
      end.
  
  find_msgsize_2([#field{occurrence=repeated} | _Rest], _AccSize, _Defs, _T) ->
      undefined;
  find_msgsize_2([#field{occurrence=optional} | _Rest], _AccSize, _Defs, _T) ->
      undefined;
  find_msgsize_2([#field{type=Type, fnum=FNum} | Rest], AccSize, Defs, T) ->
      FKey = gpb:encode_varint((FNum bsl 3) bor gpb:encode_wire_type(Type)),
      FKeySize = byte_size(FKey),
      case Type of
          sint32   -> undefined;
          sint64   -> undefined;
          int32    -> undefined;
          int64    -> undefined;
          uint32   -> undefined;
          uint64   -> undefined;
          bool     -> find_msgsize_2(Rest, AccSize+FKeySize+1, Defs, T);
          {enum,EnumName} ->
              case all_enum_values_encode_to_same_size(EnumName, Defs) of
                  {yes, ESize} ->
                      find_msgsize_2(Rest, AccSize+FKeySize+ESize, Defs, T);
                  no ->
                      undefined
              end;
          fixed64  -> find_msgsize_2(Rest, AccSize+FKeySize+8, Defs, T);
          sfixed64 -> find_msgsize_2(Rest, AccSize+FKeySize+8, Defs, T);
          double   -> find_msgsize_2(Rest, AccSize+FKeySize+8, Defs, T);
          string   -> undefined;
          bytes    -> undefined;
          {msg,MsgName} ->
              case find_msgsize(MsgName, Defs, T) of
                  MsgSize when is_integer(MsgSize) ->
                      find_msgsize_2(Rest, AccSize+FKeySize+MsgSize, Defs, T);
                  undefined ->
                      undefined
              end;
          fixed32  -> find_msgsize_2(Rest, AccSize+FKeySize+4, Defs, T);
          sfixed32 -> find_msgsize_2(Rest, AccSize+FKeySize+4, Defs, T);
          float    -> find_msgsize_2(Rest, AccSize+FKeySize+4, Defs, T)
      end;
  find_msgsize_2([], AccSize, _Defs, _T) ->
      AccSize.
  
  
  all_enum_values_encode_to_same_size(EnumName, Defs) ->
      {{enum,EnumName}, EnumDef} = lists:keyfind({enum,EnumName}, 1, Defs),
      EnumSizes = [begin
                       <<N:32/unsigned-native>> = <<Value:32/signed-native>>,
                       byte_size(gpb:encode_varint(N))
                   end
                   || {_EnumSym, Value} <- EnumDef],
      case lists:usort(EnumSizes) of
          [Size] -> {yes, Size};
          _      -> no
      end.
  
  %% -- generating code ----------------------------------------------
  
  