{"id":13435077,"url":"https://github.com/tomas-abrahamsson/gpb","last_synced_at":"2026-02-27T13:10:56.642Z","repository":{"id":43186122,"uuid":"2049737","full_name":"tomas-abrahamsson/gpb","owner":"tomas-abrahamsson","description":"A Google Protobuf implementation for Erlang","archived":false,"fork":false,"pushed_at":"2026-02-06T22:56:55.000Z","size":4618,"stargazers_count":575,"open_issues_count":5,"forks_count":154,"subscribers_count":28,"default_branch":"master","last_synced_at":"2026-02-07T09:45:12.663Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tomas-abrahamsson.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog","contributing":null,"funding":null,"license":"COPYING.LIB","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2011-07-14T20:51:33.000Z","updated_at":"2026-02-06T22:56:59.000Z","dependencies_parsed_at":"2023-01-24T06:00:15.601Z","dependency_job_id":"7c459d28-4c3b-4c61-9448-2daa7afe7bcc","html_url":"https://github.com/tomas-abrahamsson/gpb","commit_stats":{"total_commits":1359,"total_committers":39,"mean_commits":34.84615384615385,"dds":"0.19867549668874174","last_synced_commit":"5557e3117235b7df70a302c4f18267ec95777803"},"previous_names":[],"tags_count":184,"template":false,"template_full_name":null,"purl":"pkg:github/tomas-abrahamsson/gpb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomas-abrahamsson%2Fgpb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomas-abrahamsson%2Fgpb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomas-abrahamsson%2Fgpb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomas-abrahamsson%2Fgpb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tomas-abrahamsson","download_url":"https://codeload.github.com/tomas-abrahamsson/gpb/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomas-abrahamsson%2Fgpb/sbom","scorecard":{"id":891959,"data":{"date":"2025-08-11","repo":{"name":"github.com/tomas-abrahamsson/gpb","commit":"4fae6fba4b52782762aaa0f81ebc186f2c833c3d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":1,"reason":"Found 3/27 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/main.yml:1","Warn: no topLevel permission defined: .github/workflows/release.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":3,"reason":"3 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/tomas-abrahamsson/gpb/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/tomas-abrahamsson/gpb/release.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/tomas-abrahamsson/gpb/release.yml/master?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: COPYING.LIB:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact 4.21.4 not signed: https://api.github.com/repos/tomas-abrahamsson/gpb/releases/239675067","Warn: release artifact 4.21.3 not signed: https://api.github.com/repos/tomas-abrahamsson/gpb/releases/194505359","Warn: release artifact 4.21.2 not signed: https://api.github.com/repos/tomas-abrahamsson/gpb/releases/192577697","Warn: release artifact 4.21.1 not signed: https://api.github.com/repos/tomas-abrahamsson/gpb/releases/142655935","Warn: release artifact 4.21.0 not signed: https://api.github.com/repos/tomas-abrahamsson/gpb/releases/136100345","Warn: release artifact 4.21.4 does not have provenance: https://api.github.com/repos/tomas-abrahamsson/gpb/releases/239675067","Warn: release artifact 4.21.3 does not have provenance: https://api.github.com/repos/tomas-abrahamsson/gpb/releases/194505359","Warn: release artifact 4.21.2 does not have provenance: https://api.github.com/repos/tomas-abrahamsson/gpb/releases/192577697","Warn: release artifact 4.21.1 does not have provenance: https://api.github.com/repos/tomas-abrahamsson/gpb/releases/142655935","Warn: release artifact 4.21.0 does not have provenance: https://api.github.com/repos/tomas-abrahamsson/gpb/releases/136100345"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-24T12:12:34.232Z","repository_id":43186122,"created_at":"2025-08-24T12:12:34.232Z","updated_at":"2025-08-24T12:12:34.232Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29896315,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-27T12:09:13.686Z","status":"ssl_error","status_checked_at":"2026-02-27T12:09:13.282Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T03:00:32.093Z","updated_at":"2026-02-27T13:10:56.618Z","avatar_url":"https://github.com/tomas-abrahamsson.png","language":"Erlang","funding_links":[],"categories":["Erlang","协议"],"sub_categories":[],"readme":"The gpb is a compiler for\n[Google protocol buffer](https://protobuf.dev/)\ndefinitions files for Erlang.\n\nShortcuts: [API documentation](https://hexdocs.pm/gpb/) ~ [gpb on hex.pm](https://hex.pm/packages/gpb/)\n\n[![Build Status](https://github.com/tomas-abrahamsson/gpb/workflows/build/badge.svg?branch=master)](https://github.com/tomas-abrahamsson/gpb/actions?query=workflow%3A%22build%22)\n\nBasic example of using gpb\n--------------------------\n\nLet's say we have a protobuf file, `x.proto`\n```protobuf\nmessage Person {\n  required string name = 1;\n  required int32 id = 2;\n  optional string email = 3;\n}\n```\nWe can generate code for this definition in a number of different\nways. Here we use the command line tool. For info on integration with\nrebar, see further down.\n```\n# .../gpb/bin/protoc-erl -I. x.proto\n```\nNow we've got `x.erl` and `x.hrl`. First we compile it and then we can\ntry it out in the Erlang shell:\n```erlang\n# erlc -I.../gpb/include x.erl\n# erl\nErlang/OTP 19 [erts-8.0.3] [source] [64-bit] [smp:12:12] [async-threads:10] [kernel-poll:false]\n\nEshell V8.0.3  (abort with ^G)\n1\u003e rr(\"x.hrl\").\n['Person']\n2\u003e x:encode_msg(#'Person'{name=\"abc def\", id=345, email=\"a@example.com\"}).\n\u003c\u003c10,7,97,98,99,32,100,101,102,16,217,2,26,13,97,64,101,\n  120,97,109,112,108,101,46,99,111,109\u003e\u003e\n3\u003e Bin = v(-1).\n\u003c\u003c10,7,97,98,99,32,100,101,102,16,217,2,26,13,97,64,101,\n  120,97,109,112,108,101,46,99,111,109\u003e\u003e\n4\u003e x:decode_msg(Bin, 'Person').\n#'Person'{name = \"abc def\",id = 345,email = \"a@example.com\"}\n```\n\nIn the Erlang shell, the `rr(\"x.hrl\")` reads record definitions, and\nthe `v(-1)` references a value one step earlier in the history.\n\nMapping of protocol buffer datatypes to Erlang\n----------------------------------------------\n\n\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\u003cth\u003eProtobuf type\u003c/th\u003e\u003cth\u003eErlang type\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\n\u003ctbody\u003e\n\u003c!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = --\u003e\n\u003ctr\u003e\u003ctd\u003edouble, float\u003c/td\u003e\n    \u003ctd\u003efloat() | infinity | '-infinity' | nan\u003cbr/\u003e\n        When encoding, integers, too, are accepted\u003c/td\u003e\u003c/tr\u003e\n\u003c!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - --\u003e\n\u003ctr\u003e\u003ctd\u003e   int32,    int64\u003cbr/\u003e\n          uint32,   uint64\u003cbr/\u003e\n          sint32,   sint64\u003cbr/\u003e\n         fixed32,  fixed64\u003cbr/\u003e\n        sfixed32, sfixed64\u003c/td\u003e\n    \u003ctd\u003einteger()\u003c/td\u003e\u003c/tr\u003e\n\u003c!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - --\u003e\n\u003ctr\u003e\u003ctd\u003ebool\u003c/td\u003e\n    \u003ctd\u003etrue | false\u003cbr/\u003e\n        When encoding, the integers 1 and 0, too, are accepted\u003c/td\u003e\u003c/tr\u003e\n\u003c!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - --\u003e\n\u003ctr\u003e\u003ctd\u003eenum\u003c/td\u003e\n    \u003ctd\u003eatom()\u003cbr/\u003e\n        unknown enums decode to integer()\u003c/td\u003e\u003c/tr\u003e\n\u003c!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - --\u003e\n\u003ctr\u003e\u003ctd\u003emessage\u003c/td\u003e\n    \u003ctd\u003erecord (thus tuple())\u003cbr/\u003e\n        or map() if the maps (-maps) option is specified\u003c/td\u003e\u003c/tr\u003e\n\u003c!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - --\u003e\n\u003ctr\u003e\u003ctd\u003estring\u003c/td\u003e\n    \u003ctd\u003eunicode string, thus list of integers\u003cbr/\u003e\n        or binary() if the strings_as_binaries (-strbin) option is\n        specified\u003cbr/\u003e\n        When encoding, iolists, too, are accepted\u003c/td\u003e\u003c/tr\u003e\n\u003c!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - --\u003e\n\u003ctr\u003e\u003ctd\u003ebytes\u003c/td\u003e\n    \u003ctd\u003ebinary()\u003cbr/\u003e\n        When encoding, iolists, too, are accepted\u003c/td\u003e\u003c/tr\u003e\n\u003c!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - --\u003e\n\u003ctr\u003e\u003ctd\u003eoneof\u003c/td\u003e\n    \u003ctd\u003e\u003ctt\u003e{ChosenFieldName, Value}\u003c/tt\u003e\u003cbr/\u003e\n        or \u003ctt\u003eChosenFieldName =\u003e Value\u003c/tt\u003e if the {maps_oneof,flat}\n        (-maps_oneof flat) option is specified\u003c/td\u003e\u003c/tr\u003e\n\u003c!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - --\u003e\n\u003ctr\u003e\u003ctd\u003emap\u003c_,_\u003e\u003c/td\u003e\n    \u003ctd\u003eAn unordered list of 2-tuples, \u003ctt\u003e[{Key,Value}]\u003c/tt\u003e\u003cbr/\u003e\n        or  a map(), if the maps (-maps) option is specified\u003c/td\u003e\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\n\nRepeated fields are represented as lists.\n\nOptional fields are represented as either the value or `undefined` if\nnot set. However, for maps, if the option `maps_unset_optional` is set\nto `omitted`, then unset optional values are omitted from the map,\ninstead of being set to `undefined` when encoding messages. When\ndecoding messages, even with `maps_unset_optional` set to `omitted`,\nthe default value will be set in the decoded map.\n\nExamples of Erlang format for protocol buffer messages\n------------------------------------------------------\n\n#### Repeated and required fields\n\n```protobuf\n   message m1 {\n     repeated uint32 i   = 1;\n     required bool   b   = 2;\n     required eee    e   = 3;\n     required submsg sub = 4;\n   }\n   message submsg {\n     required string s = 1;\n     required bytes  b = 2;\n   }\n   enum eee {\n     INACTIVE = 0;\n     ACTIVE   = 1;\n   }\n```\n##### Corresponding Erlang\n```erlang\n   #m1{i   = [17, 4711],\n       b   = true,\n       e   = 'ACTIVE',\n       sub = #submsg{s = \"abc\",\n                     b = \u003c\u003c0,1,2,3,255\u003e\u003e}}\n\n   %% If compiled to with the option maps:\n   #{i   =\u003e [17, 4711],\n     b   =\u003e true,\n     e   =\u003e 'ACTIVE',\n     sub =\u003e #{s =\u003e \"abc\",\n              b =\u003e \u003c\u003c0,1,2,3,255\u003e\u003e}}\n```\n\n#### Optional fields\n```protobuf\n   message m2 {\n     optional uint32 i1 = 1;\n     optional uint32 i2 = 2;\n   }\n```\n##### Corresponding Erlang\n```erlang\n   #m2{i1 = 17}    % i2 is implicitly set to undefined\n\n   %% With the maps option\n   #{i1 =\u003e 17}\n\n   %% With the maps option and the maps_unset_optional set to present_undefined:\n   #{i1 =\u003e 17,\n     i2 =\u003e undefined}\n\n```\n\n#### Oneof fields\nThis construct first appeared in Google protobuf version 2.6.0.\n```protobuf\n   message m3 {\n     oneof u {\n       int32  a = 1;\n       string b = 2;\n     }\n   }\n```\n##### Corresponding Erlang\nA oneof field is automatically always optional.\n```erlang\n   #m3{u = {a, 17}}\n   #m3{u = {b, \"hello\"}}\n   #m3{}                 % u is implicitly set to undefined\n\n   %% With the maps option\n   #{u =\u003e {a, 17}}\n   #{u =\u003e {b, \"hello\"}}\n   #{}                   % If maps_unset_optional = omitted (default)\n   #{u =\u003e undefined}     % With maps_unset_optional set to present_undefined\n\n   %% With the {maps_oneof,flat} option (requires maps_unset_optional = omitted)\n   #{a =\u003e 17}\n   #{b =\u003e \"hello\"}\n   #{}\n\n```\n\n#### Map fields\nNot to be confused with Erlang maps.\nThis construct first appeared in Google protobuf version 3.0.0 (for\nboth the `proto2` and the `proto3` syntax)\n```protobuf\n   message m4 {\n     map\u003cuint32,string\u003e f = 1;\n   }\n```\n##### Corresponding Erlang\nFor records, the order of items is undefined when decoding.\n```erlang\n   #m4{f = []}\n   #m4{f = [{1, \"a\"}, {2, \"b\"}, {13, \"hello\"}]}\n\n   %% With the maps option\n   #{f =\u003e #{}}\n   #{f =\u003e #{1 =\u003e \"a\", 2 =\u003e \"b\", 13 =\u003e \"hello\"}}\n```\n\n\nUnset optionals and the `default` option\n----------------------------------------\n\n#### For proto2 syntax\n\nThis describes how decoding works for optional fields that are\nnot present in the binary-to-decode.\n\nThe documentation for Google protobuf says these decode to the default\nvalue if specified, or else to the field's type-specific default. The\ncode generated by Google's protobuf compiler also contains\n`has_\u003cfield\u003e()` methods so one can examine whether a field was\nactually present or not.\n\nHowever, in Erlang, the natural way to set and read fields is to just\nuse the syntax for records (or maps), and this leaves no good way to\nat the same time both convey whether a field was present or not and to\nread the defaults.\n\nSo the approach in `gpb` is that you have to choose: either or.\nNormally, it is possible to see whether an optional field is\npresent or not, eg by checking if the value is `undefined`. But there\nare options to the compiler to instead decode to defaults, in which\ncase you lose the ability to see whether a field is present or not.\nThe options are `defaults_for_omitted_optionals` and\n`type_defaults_for_omitted_optionals`, for decoding to `default=\u003cx\u003e`\nvalues, or to type-specific defaults respectively.\n\nIt works this way:\n\n```protobuf\nmessage o1 {\n  optional uint32 a = 1 [default=33];\n  optional uint32 b = 2; // the type-specific default is 0\n}\n```\n\nGiven binary data `\u003c\u003c\u003e\u003e`, that is, neither field `a` nor `b` is present,\nthen the call `decode_msg(Input, o1)` results in:\n\n```erlang\n#o1{a=undefined, b=undefined} % None of the options\n\n#o1{a=33, b=undefined}        % with option defaults_for_omitted_optionals\n\n#o1{a=33, b=0}                % with both defaults_for_omitted_optionals\n                              %       and type_defaults_for_omitted_optionals\n\n#o1{a=0, b=0}                 % with only type_defaults_for_omitted_optionals\n```\nThe last of the alternatives is perhaps not very useful, but still\npossible, and implemented for completeness.\n\n[Google's Reference](https://protobuf.dev/programming-guides/proto/#optional)\n\n#### For proto3 syntax\n\nFor proto3, there is neither `required` nor `default=\u003cx\u003e`\nfor fields. Instead, unless marked with `optional`, all scalar fields,\nstrings and bytes are implicitly optional. On decoding, if such a field\nis missing in the binary to decode, they always decode to the type-specific\ndefault value.\nOn encoding, such fields are only included in the resulting encoded\nbinary if they have a value different from the type-specific default\nvalue. Even though all fields are implicitly optional, one could also\nsay that on a conceptual level, all such fields always have a value.\nAt decoding, it is not possible to determine whether at encoding,\na value was present---with a type-specific value---or not.\n\nFields marked as `optional` are essentially represented the same way\nas in proto2 syntax; in a record the field has the value `undefined`\nif it is not set, and in maps the field is not present if it is not set.\n\nA recommendation I've seen for if you need detection of \"missing\" data,\nis to define `has_\u003cfield\u003e` boolean fields and set them appropriately.\nAnother alternative could be to use the well-known wrapper messages.\n\nFields that are sub-messages and oneof fields, do not have any\ntype-specific default. A sub-message field that was not set encodes\ndifferently from a sub-message field set to the sub-message, and it\ndecodes differently. This holds even when the sub-message has no\nfields. It works a bit similarly for oneof fields. Either none of the\nalternative oneof fields is set, or one of them is. The encoded format\nis different, and on decoding it is possible to tell a difference.\n\nFeatures of gpb\n---------------\n\n*  Parses protocol buffer definition files and can generate:\n   - record definitions, one record for each message\n   - erlang code for encoding/decoding the messages to/from binaries\n\n*  Features of the protocol buffer definition files:\n   gpb supports:\n   - message definitions (also messages in messages)\n   - scalar types\n   - importing other proto files\n   - nested types\n   - message extensions\n   - the `packed` and `default` options for fields\n   - the `allow_alias` enum option (treated as if it is always set true)\n   - generating metadata information\n   - package namespacing (optional)\n   - `oneof` (introduced in protobuf 2.6.0)\n   - `map\u003c_,_\u003e` (introduced in protobuf 3.0.0)\n   - proto3 support:\n     - syntax and general semantics\n     - import of well-known types\n     - Callback functions can be specified for automatically translating\n       google.protobuf.Any messages\n   - groups\n   - JSON mapping is supported, see the json (-json) option(s)\n\n   gpb reads but ignores:\n   - options other than `packed` or `default`\n   - custom options\n\n   gpb does not support:\n   - aggregate custom options introduced in protobuf 2.4.0\n   - rpc\n   - JSON limitations:\n     - does not handle the special JSON mapping of\n       the google.protobuf.Any wellknown\n\n*  Characteristics of gpb:\n   - Skipping over unknown message fields or groups, when decoding,\n     is supported\n   - Merging of messages, also recursive merging, is supported\n   - Gpb can optionally generate code for verification of values during\n     encoding this makes it easy to catch e.g integers out of range,\n     or values of the wrong type.\n   - Gpb can optionally or conditionally copy the contents of `bytes`\n     fields, in order to let the runtime system free the larger message\n     binary.\n   - Gpb can optionally make use of the `package` attribute by prepending\n     the name of the package to every contained message type (if defined),\n     which is useful to avoid name clashes of message types across packages.\n     See the [`use_packages` option](https://hexdocs.pm/gpb/gpb_compile.html#option-use_packages)\n     or the [`-pkgs` command line option](https://hexdocs.pm/gpb/gpb_compile.html#cmdline-option-pkgs).\n   - The generated encode/decoder has no run-time dependency to gpb,\n     but there is normally a compile-time dependency for the generated\n     code: to the `#field{}` record in gpb.hrl for the `get_msg_defs`\n     function, but it is possible to avoid this dependency by using\n     the also the `defs_as_proplists` or `-pldefs` option.\n   - Gpb can generate code both to files and to binaries.\n   - Proto input files are expected to be UTF-8, but the file reader\n     will fall back to decode the files as latin1 in UTF-8 decode errors,\n     for backwards compatibility and behaviour that most closely\n     emulates what Google protobuf does.\n\n*  Introspection\n\n   gpb generates some functions for examining messages, enums and services:\n   - `get_msg_defs()` (or `get_proto_defs()` if `introspect_get_proto_defs`\n      is set), `get_msg_names()`, `get_enum_names()`\n   - `find_msg_def(MsgName)` and `fetch_msg_def(MsgName)`\n   - `find_enum_def(MsgName)` and `fetch_enum_def(MsgName)`\n   - `enum_symbol_by_value(EnumName, Value)`,\n   - `enum_symbol_by_value_\u003cEnumName\u003e(Value)`,\n     `enum_value_by_symbol(EnumName, Enum)` and\n     `enum_value_by_symbol_\u003cEnumName\u003e(Enum)`\n   - `get_service_names()`, `get_service_def(ServiceName)`, `get_rpc_names(ServiceName)`\n   - `find_rpc_def(ServiceName, RpcName)`, `fetch_rpc_def(ServiceName, RpcName)`\n\n   There are also some functions for translating between fully qualified\n   names and internal names. These take any renaming options into\n   consideration. They may be useful for instance with grpc reflection.\n\n   - `fqbin_to_service_name(\u003c\u003c\"Package.ServiceName\"\u003e\u003e)`\n     and `service_name_to_fqbin('ServiceName')`\n   - `fqbins_to_service_and_rpc_name(\u003c\u003c\"Package.ServiceName\"\u003e\u003e, \u003c\u003c\"RpcName\"\u003e\u003e)`\n     and `service_and_rpc_name_to_fqbins('ServiceName', 'RpcName')`\n   - `fqbin_to_msg_name(\u003c\u003c\"Package.MsgName\"\u003e\u003e)` and\n     `msg_name_to_fqbin('MsgName')`\n   - `fqbin_to_enum_name(\u003c\u003c\"Package.EnumName\"\u003e\u003e)` and\n     `enum_name_to_fqbin('EnumName')`\n\n   There are also some functions for querying what proto a type belongs\n   to. Each type belongs to some `\"name\"` which is a string, usually the\n   file name, sans extension, for example `\"name\"` if the proto file was\n   `\"name.proto\"`.\n\n   - `get_all_proto_names() -\u003e [\"name1\", ...]`\n   - `get_msg_containment(\"name\") -\u003e ['MsgName1', ...]`\n   - `get_pkg_containment(\"name\") -\u003e 'Package'`\n   - `get_service_containment(\"name\") -\u003e ['Service1', ...]`\n   - `get_rpc_containment(\"name\") -\u003e [{'Service1', 'RpcName1}, ...]`\n   - `get_proto_by_msg_name_as_fqbin(\u003c\u003c\"Package.MsgName\"\u003e\u003e) -\u003e \"name\"`\n   - `get_proto_by_enum_name_as_fqbin(\u003c\u003c\"Package.EnumName\"\u003e\u003e) -\u003e \"name\"`\n   - `get_protos_by_pkg_name_as_fqbin(\u003c\u003c\"Package\"\u003e\u003e) -\u003e [\"name1\", ...]`\n\n   There are also some version information functions:\n\n   - `gpb:version_as_string()`, `gpb:version_as_list()`\n     and `gpb:version_source()`\n   - `GeneratedCode:version_as_string()`, `GeneratedCode:version_as_list()` and\n   - `GeneratedCode:version_source()`\n   - `?gpb_version`  (in gpb_version.hrl)\n   - `?'GeneratedCode_gpb_version'`  (in GeneratedCode.hrl)\n\n   The gpb can also generate a self-description of the proto file.\n   The self-description is a description of the proto file, encoded to\n   a binary using the descriptor.proto that comes with the Google\n   protocol buffers library. Note that such an encoded self-descriptions\n   won't be byte-by-byte identical to what the Google protocol buffers\n   compiler will generate for the same proto, but should be roughly\n   equivalent.\n\n*  Erroneously encoded protobuf messages and fields will generally\n   cause the decoder to crash.  Examples of such erroneous encodings are:\n   - varints with too many bits\n   - strings, bytes, sub messages or packed repeated fields,\n     where the encoded length is longer than the remaining binary\n\n*  Maps\n\n   Gpb can generate encoders/decoders for maps.\n\n   The option `maps_unset_optional` can be used to specify behavior\n   for non-present optional fields: whether they are omitted from\n   maps, or whether they are present, but have the value `undefined`\n   like for records.\n\n*  Reporting of errors in .proto files\n\n   Gpb is not very good at error reporting, especially referencing\n   errors, such as references to messages that are not defined.\n   You might want to first verify with `protoc` that the .proto files\n   are valid before feeding them to gpb.\n\nInteraction with rebar\n----------------------\n\nFor info on how to use gpb with rebar3, see\nhttps://rebar3.org/docs/configuration/plugins/#protocol-buffers\n\nCompatibility with rebar2\n------------------------\n\nIn rebar there is support for gpb since version 2.6.0. See the\nproto compiler section of rebar.sample.config file at\nhttps://github.com/rebar/rebar/blob/master/rebar.config.sample\n\nFor older versions of rebar---prior to 2.6.0---the text below outlines\nhow to proceed:\n\nPlace the .proto files for instance in a `proto/` subdirectory.\nAny subdirectory, other than src/, is fine, since rebar will try to\nuse another protobuf compiler for any .proto it finds in the src/\nsubdirectory.  Here are some some lines for the `rebar.config` file:\n\n    %% -*- erlang -*-\n    {pre_hooks,\n     [{compile, \"mkdir -p include\"}, %% ensure the include dir exists\n      {compile,\n       \"/path/to/gpb/bin/protoc-erl -I`pwd`/proto\"\n       \"-o-erl src -o-hrl include `pwd`/proto/*.proto\"\n      }]}.\n\n    {post_hooks,\n     [{clean,\n       \"bash -c 'for f in proto/*.proto; \"\n       \"do \"\n       \"  rm -f src/$(basename $f .proto).erl; \"\n       \"  rm -f include/$(basename $f .proto).hrl; \"\n       \"done'\"}\n     ]}.\n\n    {erl_opts, [{i, \"/path/to/gpb/include\"}]}.\n\n\nVersion numbering\n-----------------\n\nThe gpb version number is fetched from the git latest git tag\nmatching N.M where N and M are integers.  This version is\ninserted into the gpb.app file as well as into the\ninclude/gpb_version.hrl.  The version is the result of the command\n\n    git describe --always --tags --match '[0-9]*.[0-9]*'\n\nThus, to create a new version of gpb, the single source from where\nthis version is fetched, is the git tag.   (If you are importing\ngpb into another version control system than git, or using another\nbuild tool than rebar, you might have to adapt rebar.config and\nsrc/gpb.app.src accordingly. See also the section below about\n[building outside of a git work tree](README.md#building-outside-of-a-git-work-tree) for info on\nexporting gpb from git.)\n\nThe version number from the `git describe` command above will look like\n* `\u003cx\u003e.\u003cy\u003e.\u003cz\u003e` (on master on Github)\n* `\u003cx\u003e.\u003cy\u003e.\u003cz\u003e-\u003cn\u003e-g\u003csha\u003e` (on branches or between releases)\n\nThe version number on the master branch of the gpb on Github is\nintended to always be only integers with dots, in order to be\ncompatible with reltool.  In other words, each push to Github's master\nbranch is considered a release, and the version number is bumped.\nTo ensure  this, there is a `pre-push` git hook and two scripts,\n`install-git-hooks` and `tag-next-minor-vsn`, in the helpers\nsubdirectory. The ChangeLog file will not necessarily reflect all\nminor version bumps, only important updates.\n\nPlaces to update when making a new version:\n* Write about the changes in the ChangeLog file,\n  if it is a non-minor version bump.\n* Tag it in git\n\n\nBuilding outside of a git work tree\n-----------------------------------\n\nThe gpb build process expects a (non-shallow) git work tree, with tags,\nto get the version numbering right, as described in the\n[Version numbering section](#version-numbering), but it is also possible\nto build outside of git. To do that, you have two options:\n* set the version manually by creating a file, `gpb.vsn`,\n  with the version on the first line\n* or create a versioned archive, using the `helpers/mk-versioned-archive` script,\n  then unpack the archive and build inside it.\n\nIf you create the versioned archive in a git work tree, the version\nwill be set automatically, otherwise you will need to specify it\nmanually. Run `mk-versioned-archive --help` for info on what options\nto use.\n\nWhen downloading from Github, the *gpb-_\u003cx.y.z\u003e_.tar.gz* archives\nhave been created using the mk-versioned-archive script, so it is\npossible to just unpack and build directly.\n\nIf you use Github's automatic _Source code_ zip or tar.gz archives,\nyou will need to either create a `gpb.vsn` file as described above,\nor re-create a versioned archive using the `mk-versioned-archive`\nscript and the `--override-version=\u003cx\u003e` option (or possibly the\nor the `--override-version-from-cwd-path` option if the directory name\ncontains a proper version.)\n\n\nRelated projects\n----------------\n* [rebar3_gpb_plugin](https://github.com/lrascao/rebar3_gpb_plugin) for\n  using gpb with rebar3\n* [exprotobuf](https://github.com/bitwalker/exprotobuf) for using gpb from\n  [Elixir](http://elixir-lang.org)\n* [enif_protobuf](https://github.com/jinganix/enif_protobuf) for a NIF\n  encoder/decoder\n* [grpcbox](https://github.com/tsloughter/grpcbox), for creating\n  grpc services (client and server)\n* [grpc](https://github.com/Bluehouse-Technology/grpc) and\n  [grpc_client](https://github.com/Bluehouse-Technology/grpc_client)\n  for a grpc server and client\n\n\nContributing\n------------\n\nContributions are welcome, preferably as pull requests or git patches\nor git fetch requests.  Here are some guide lines:\n\n* Use only spaces for indentation, no tabs. Indentation is 4 spaces.\n* The code must fit 80 columns\n* Verify that the code and documentation compiles and that tests are ok:\u003cbr/\u003e\n  `rebar clean; rebar eunit \u0026\u0026 rebar doc`\u003cbr/\u003e\n  (if you are still on rebar2, you will need to run rebar compile before eunit)\n* If you add a feature, test cases are most welcome,\n  so that the feature won't get lost in any future refactorization\n* Use a git branch for your feature. This way, the git history will\n  look better in case there is need to refetch.\n* By submitting patches to this project, you agree to allow them to be\n  redistributed under the project's license according to the normal\n  forms and usages of the open-source community.\n\n\nVersion history\n---------------\n\nSee the\n[ChangeLog](https://github.com/tomas-abrahamsson/gpb/blob/master/ChangeLog)\nfor details.\n\n##### Major change in version 4.0.0: #####\n\nThe default value for the `maps_unset_optional` option has changed\nto `omitted`, from `present_undefined` This concerns only code generated\nwith the maps (-maps) options. Projects that already set this option\nexplicitly are not impacted. Projects that relied on the default to be\n`present_undefined` will need to set the option explicitly in order to\nupgrade to 4.0.0.\n\nFor type specs, the default has changed to generate them when possible. The\noption `{type_specs,false}` (-no_type) can be used to avoid generating type\nspecs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomas-abrahamsson%2Fgpb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomas-abrahamsson%2Fgpb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomas-abrahamsson%2Fgpb/lists"}