anchor.diff:                 ""
          end,
          "\n",
  -       format_export_types(get_type_specs_by_opts(Opts),
  -                           get_records_or_maps_by_opts(Opts), Defs),
  +       format_export_types(Defs, Opts),
          "\n",
          [[?f("~s~n", [format_load_nif(Mod, Opts)]),
            "\n"]
  
positive.code: % --- exported types -----------------------------------------------------
  format_enum_typespec(Enum, Enumeration) ->
    ?f("-type '~s'() :: ~s.", [Enum,
      string:join(["'"++atom_to_list(EName)++"'" || {EName, _} <- Enumeration], " | ")]).
  
  format_record_typespec(records, Msg, _Fields, _Defs) ->
    ?f("-type '~s'() :: #'~s'{}.", [Msg, Msg]);
  format_record_typespec(maps, Msg, Fields, Defs) ->
    ?f("-type '~s'() :: ~n"
       "      #{~s~n"
       "       }.",
        [Msg, outdent_first(format_hfields(7 + 1, Fields,
                                           [{maps, true}, {type_specs, true}], Defs))]).
  
  format_export_types(false, _, _Defs) -> "";
  format_export_types(true, MapsOrRecords, Defs) ->
    iolist_to_binary(
      ["%% enumerate types\n",
       string:join([format_enum_typespec(Enum, Enumeration)
                      || {{enum, Enum}, Enumeration} <- Defs],
                  "\n"),
      "\n",
       ?f("-export_type([~s]).",
          [string:join(["'"++atom_to_list(Enum)++"'/0"
                      || {{enum, Enum}, _} <- Defs], ", ")]),
      "\n\n",
      "%% message types\n",
      string:join([format_record_typespec(MapsOrRecords, Msg, Fields, Defs)
                      || {{msg, Msg}, Fields} <- Defs],
                  "\n"),
      "\n",
       ?f("-export_type([~s]).",
          [string:join(["'"++atom_to_list(Msg)++"'/0"
                      || {{msg, Msg}, _} <- Defs], ", ")]),
       "\n"]).
  
  %% -- hrl -----------------------------------------------------
  
  
negative.code:     Default = false,
      proplists:get_value(type_specs, Opts, Default).
  
  find_last_nonopt_field_index(Fields) ->
      lists:foldl(fun({I, F}, Acc) ->
                          case get_field_occurrence(F) of
                              required -> I;
                              repeated -> I;
                              optional -> Acc
                          end
                  end,
                  0,
                  index_seq(Fields)).
  
  type_to_typestr(#?gpb_field{type=Type, occurrence=Occurrence}, Defs, Opts) ->
      OrUndefined = case get_mapping_and_unset_by_opts(Opts) of
                        records                   -> " | undefined";
                        {maps, present_undefined} -> " | undefined";
                        {maps, omitted}           -> ""
                    end,
      case Occurrence of
          required -> type_to_typestr_2(Type, Defs, Opts);
          repeated -> "[" ++ type_to_typestr_2(Type, Defs, Opts) ++ "]";
          optional -> type_to_typestr_2(Type, Defs, Opts) ++ OrUndefined
      end;
  type_to_typestr(#gpb_oneof{fields=OFields}, Defs, Opts) ->
      OrUndefined = case get_mapping_and_unset_by_opts(Opts) of
                        records                   -> ["undefined"];
                        {maps, present_undefined} -> ["undefined"];
                        {maps, omitted}           -> []
                    end,
      string:join(
        [?f("{~s, ~s}", [Name, type_to_typestr_2(Type, Defs, Opts)])
         || #?gpb_field{name=Name, type=Type} <- OFields]
        ++ OrUndefined,
        " | ").
  
  type_to_typestr_2(sint32, _Defs, _Opts)   -> "integer()";
  