├── .dir-locals.el ├── .edts ├── .github └── workflows │ ├── main.yml │ └── release.yml ├── .gitignore ├── .tidyrc ├── COPYING.LIB ├── ChangeLog ├── Makefile ├── README.md ├── README.nif-cc ├── benchmarks ├── Makefile ├── README.txt ├── d-msgs │ ├── d-all-concatenated.dat │ ├── d-msg-n01.dat │ ├── d-msg-n02.dat │ ├── d-msg-n03.dat │ ├── d-msg-n04.dat │ ├── d-msg-n05.dat │ ├── d-msg-n06.dat │ ├── d-msg-n07.dat │ ├── d-msg-n08.dat │ ├── d-msg-n09.dat │ ├── d-msg-n10.dat │ ├── d-msg-n11.dat │ ├── d-msg-n12.dat │ ├── d-msg-n13.dat │ ├── d-msg-n14.dat │ ├── d-msg-n15.dat │ ├── d-msg-n16.dat │ ├── d-msg-n17.dat │ ├── d-msg-n18.dat │ ├── d-msg-n19.dat │ ├── d-msg-n20.dat │ ├── d-msg-n21.dat │ ├── d-msg-n22.dat │ ├── d-msg-n23.dat │ ├── d-msg-n24.dat │ ├── d-msg-n25.dat │ ├── d-msg-n26.dat │ ├── d-msg-n27.dat │ ├── d-msg-n28.dat │ ├── d-msg-n29.dat │ ├── d-msg-n30.dat │ ├── d-msg-n31.dat │ ├── d-msg-n32.dat │ ├── d-msg-n33.dat │ ├── d-msg-n34.dat │ ├── d-msg-n35.dat │ ├── d-msg-n36.dat │ ├── d-msg-n37.dat │ ├── d-msg-n38.dat │ ├── d-msg-n39.dat │ ├── d-msg-n40.dat │ ├── d-msg-n41.dat │ ├── d-msg-n42.dat │ ├── d-msg-n43.dat │ ├── d-msg-n44.dat │ ├── d-msg-n45.dat │ ├── d-msg-n46.dat │ ├── d-msg-n47.dat │ ├── d-msg-n48.dat │ ├── d-msg-n49.dat │ ├── d-msg-n50.dat │ ├── d-msg-n51.dat │ ├── d-msg-n52.dat │ ├── d-msg-n53.dat │ ├── d-msg-n54.dat │ ├── d-msg-n55.dat │ ├── d-msg-n56.dat │ ├── d-msg-n57.dat │ ├── d-msg-n58.dat │ ├── d-msg-n59.dat │ ├── d-msg-n60.dat │ ├── d-msg-n61.dat │ ├── d-msg-n62.dat │ ├── d-msg-n63.dat │ ├── d-msg-n64.dat │ ├── d-msg-n65.dat │ ├── d-msg-n66.dat │ ├── d-msg-n67.dat │ ├── d-msg-n68.dat │ ├── d-msg-n69.dat │ ├── d-msg-n70.dat │ ├── d-msg-n71.dat │ ├── d-msg-n72.dat │ ├── d-msg-n73.dat │ ├── d-msg-n74.dat │ ├── d-msg-n75.dat │ ├── d-msg-n76.dat │ └── d-msg-n77.dat ├── d.proto ├── google_message1.dat ├── google_message2.dat ├── msg.proto └── proto-bench ├── bin └── protoc-erl ├── build ├── compile_descriptor ├── find-vsn └── mk_version_hrl ├── descr_src ├── gpb_compile_descr.erl ├── gpb_compile_descr_tests.erl ├── gpb_parse_descr.erl └── gpb_parse_descr_tests.erl ├── doc └── dev-guide │ ├── decoding.md │ ├── encoding.md │ ├── intro.md │ ├── json.md │ ├── proto-defs-versions.md │ └── translations.md ├── helpers ├── export-from-git ├── extract-top-changelog-entry ├── git-hooks │ └── pre-push ├── import-protobuf-protos ├── install-git-hooks ├── mk-versioned-archive ├── package-for-hex.pm ├── send-pr-to-rebar3-gpb-plugin ├── tag-next-minor-vsn └── upload-hexdoc ├── include ├── gpb.hrl └── gpb_version.hrl.in ├── priv └── proto3 │ └── google │ └── protobuf │ ├── LICENSE │ ├── any.proto │ ├── api.proto │ ├── descriptor.proto │ ├── duration.proto │ ├── empty.proto │ ├── field_mask.proto │ ├── source_context.proto │ ├── struct.proto │ ├── timestamp.proto │ ├── type.proto │ └── wrappers.proto ├── rebar.config.script ├── src ├── gpb.app.src ├── gpb.erl ├── gpb_analyzer.erl ├── gpb_codegen.erl ├── gpb_codegen.hrl ├── gpb_codemorpher.erl ├── gpb_compile.erl ├── gpb_compile.hrl ├── gpb_decoders_lib.erl ├── gpb_decoders_lib.hrl ├── gpb_defs.erl ├── gpb_gen_decoders.erl ├── gpb_gen_encoders.erl ├── gpb_gen_introspect.erl ├── gpb_gen_json_decoders.erl ├── gpb_gen_json_encoders.erl ├── gpb_gen_mergers.erl ├── gpb_gen_nif.erl ├── gpb_gen_translators.erl ├── gpb_gen_types.erl ├── gpb_gen_verifiers.erl ├── gpb_lib.erl ├── gpb_names.erl ├── gpb_parse.erl └── gpb_scan.erl └── test ├── gpb_codegen_tests.erl ├── gpb_codemorpher_tests.erl ├── gpb_compile_maps_tests.erl ├── gpb_compile_tests.erl ├── gpb_defs_tests.erl ├── gpb_json_tests.erl ├── gpb_lib_tests.erl ├── gpb_names_tests.erl ├── gpb_nif_test_helpers.hrl ├── gpb_scan_tests.erl └── gpb_tests.erl /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ;; Project-wide Emacs settings 2 | ( 3 | ;; For all modes (types of files) 4 | (nil . ( 5 | ;; use spaces to indent, not tabs 6 | (indent-tabs-mode . nil) 7 | ;; but if there are any tabs, the tab with is 8 chars anyway 8 | (tab-width . 8) 9 | ;; Lines no longer than this 10 | (fill-column . 80))) 11 | 12 | ;; However, for Makefiles, tabs are important 13 | (makefile-mode . ((indent-tabs-mode . t))) 14 | 15 | ;; For Erlang files 16 | (erlang-mode . ( 17 | ;; Use this spaces of indentation per level 18 | (erlang-indent-level . 4)))) 19 | -------------------------------------------------------------------------------- /.edts: -------------------------------------------------------------------------------- 1 | :name "gpb" 2 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | jobs: 6 | build: 7 | 8 | name: Build and test gpb 9 | runs-on: ubuntu-latest 10 | 11 | strategy: 12 | matrix: 13 | otpvsn: [23, 24, 25, 26, 27] 14 | fail-fast: false 15 | 16 | container: 17 | image: erlang:${{ matrix.otpvsn }} 18 | 19 | env: 20 | VERBOSE: 1 21 | GPB_ALLOW_NON_CONFORMING_VSN_FORMAT: 1 22 | steps: 23 | - uses: actions/checkout@v3 24 | - name: Erlang ${{ matrix.otpvsn }} 25 | # TODO: test with protobuf (in the container) 26 | run: | 27 | set -xv 28 | echo $GITHUB_SHA > gpb.vsn 29 | erl +B -noinput -eval 'io:put_chars(erlang:system_info(system_version)),halt(0).' 30 | make all test doc dialyze 31 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | # Sequence of patterns matched against refs/tags 4 | tags: 5 | - '[0-9]*.[0-9]*' 6 | 7 | name: Create a release 8 | 9 | jobs: 10 | build: 11 | name: Upload Release Asset 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v3 16 | - name: Create a .tar.gz 17 | run: | 18 | set -xv 19 | t=${{ github.event.ref }} 20 | vsn=${t##*/} 21 | echo "vsn=$vsn" >> $GITHUB_ENV 22 | ./helpers/mk-versioned-archive --override-version=$vsn 23 | ./helpers/extract-top-changelog-entry > release-descr.txt 24 | - name: Create Release 25 | id: create_release 26 | uses: softprops/action-gh-release@v1 27 | env: 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | with: 30 | tag_name: ${{ env.vsn }} 31 | name: Release ${{ env.vsn }} 32 | draft: false 33 | prerelease: false 34 | body_path: release-descr.txt 35 | files: gpb-${{ env.vsn }}.tar.gz 36 | fail_on_unmatched_files: true 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | /ebin/*.beam 3 | /test/*.beam 4 | /erl_crash.dump 5 | /doc/* 6 | !/doc/dev-guide 7 | # The gpb_version.hrl is generated, see pre_hooks in rebar.config 8 | /include/gpb_version.hrl 9 | # The .app file is automatically generated by rebar 10 | /ebin/*.app 11 | # Rebar compiles tests and more to .eunit/ 12 | /.eunit 13 | # Rebar build-plt saves it to .rebar/ 14 | /.rebar 15 | # Dest dir for benchmarking artifacts 16 | /benchmarks/tmp/ 17 | # Code for generation of description: generated files 18 | /descr_src/gpb_compile_descr.beam 19 | /descr_src/gpb_compile_descr_tests.beam 20 | /descr_src/gpb_parse_descr.beam 21 | /descr_src/gpb_parse_descr_tests.beam 22 | /descr_src/gpb_descriptor.erl 23 | /descr_src/gpb_descriptor.hrl 24 | # Plt generated by Makefile 25 | /.gpb-*.plt 26 | 27 | # etags 28 | /TAGS 29 | -------------------------------------------------------------------------------- /.tidyrc: -------------------------------------------------------------------------------- 1 | gnu-emacs: yes 2 | -------------------------------------------------------------------------------- /README.nif-cc: -------------------------------------------------------------------------------- 1 | The `nif' option will cause the compiler to generate nif C++ code 2 | that can be linked with the Google protobuf C++ library. 3 | 4 | The purpose for this is speed: the Google protobuf C++ is faster than 5 | the interpreted Erlang code. Gpb will try to avoid locking up an 6 | Erlang scheduler for doing the encoding and decoding work, if 7 | supported by the Erlang VM, which currently means at least 17.3 8 | configured with --enable-dirty-schedulers. If gpb cannot run on a 9 | dirty scheduler, it will lock up an Erlang scheduler for as long as it 10 | takes for the Google protobuf library to complete the encoding or 11 | decoding of a message. This is normally a small amount of time, but 12 | can be a longer time for huge messages. 13 | 14 | The generated nif code can be compiled with Erlang R14B or later. The 15 | `gpb_compile' will only generate C++ code, it will _not_ compile the 16 | generated C++ code for you. Below is an example of how to generate and 17 | compile the C++ nif code under Linux. Details may differ from system 18 | to system. 19 | 20 | # Use protoc to generate C++ code, and compile it. 21 | # This will generate x.pb.cc and x.pb.h from x.proto. 22 | protoc --cpp_out=$PWD x.proto 23 | g++ -g -fPIC -O3 -I/path/to/protobuf-include -o x.pb.o -c x.pb.cc 24 | # Generate Erlang code and C++ nif glue code, and compile it. 25 | # This will generate x.erl, x.hrl and x.nif.cc from x.proto. 26 | erl -boot start_clean -pa /path/to/gpb/ebin -noshell -noinput +B \ 27 | -I$PWD -nif -s gpb_compile c x.proto 28 | erlc -Wall x.erl 29 | g++ -g -fPIC -Wall -O3 -I/path/to/protobuf -o x.nif.o -c x.nif.cc 30 | # Link all the C++ code together to a shared library. 31 | g++ -g -fPIC -shared -O3 -Wall -o x.nif.so x.nif.o x.pb.o \ 32 | -L/path/to/protobuf-libs -lprotobuf \ 33 | -Wl,-rpath=/path/to/protobuf-libs 34 | # Now, if you load x.beam into an Erlang VM, it will 35 | # automatically load x.nif.so which contains the nif glue C++ 36 | code as well as the protobuf code. 37 | 38 | NB: Caveats: Reloading or upgrading code compiled with the `nif' 39 | option, might have unexpected behaviour. The Google protobuf 40 | library maintains a database of .proto descriptors and will 41 | complain -- and halt the entire Erlang VM -- if you try to load nif 42 | code in two different modules that defines a message with the same 43 | name. I have also seen cases where protobuf descriptors from old 44 | versions of the nif code appears to be used even if new code has 45 | been loaded. The descriptor database appears to be kept as long as 46 | the Google C++ protobuf library is loaded, and it is not possible 47 | to control unloading of a sharerd library in Erlang, at least as of 48 | R15B01. Even if the code has been purged and deleted, the shared 49 | object for the nif, and thus also for the Google protobuf library's 50 | database, may still be kept in memory. 51 | 52 | The `load_nif' option lets you specify the code to use to load the nif. 53 | The value to the `load_nif' must be a text that defines the function 54 | `load_nif/0', that in the end calls `erlang:load_nif/2'. 55 | Two special substrings are recognized and substituted in the text: 56 | 57 | `{{nifbase}}' 58 | The basename of the nif file to be loaded (a string). 59 | Example: `"MyModule.nif"' if we are compiling `MyModule.proto'. 60 | This is intended to be (part of) the first argument in 61 | the call to `erlang:load_nif/2'. 62 | 63 | `{{loadinfo}}' 64 | This is a term that is intended to be the second argument in 65 | the call to `erlang:load_nif/2'. 66 | 67 | The default for the `load_nif' is as follows: If the module's 68 | directory, as returned by`code:which/1', is on the form 69 | `/path/to/ebin/Mod.beam', then the nif object code is loaded from 70 | `/path/to/priv/Mod.nif'. Otherwise: if `code:which/1' returns 71 | `/some/path/Mod.beam', then the nif is loaded from 72 | `/some/path/Mod.nif'. 73 | -------------------------------------------------------------------------------- /benchmarks/Makefile: -------------------------------------------------------------------------------- 1 | erl ?= erl 2 | erlc ?= erlc 3 | escript ?= escript 4 | 5 | ifdef HIPE 6 | HIPE_ERLC_OPTS := +'native' +'{hipe,[o3]}' 7 | else 8 | HIPE_ERLC_OPTS := 9 | endif 10 | 11 | PROTOBUF_CFLAGS ?= $(shell pkg-config --cflags protobuf) 12 | PROTOBUF_LDFLAGS ?= $(shell pkg-config --libs protobuf) 13 | PROTOC ?= $(shell which protoc) 14 | ifdef PROTOHOME 15 | PROTOBUF_CFLAGS := "-I$(PROTOHOME)/src" 16 | PROTOBUF_LIBS := $(PROTOHOME)/src/.libs 17 | PROTOBUF_LDFLAGS := "-Wl,-rpath=$(PROTOBUF_LIBS)" "-L$(PROTOBUF_LIBS)" -lprotobuf -pthread -lpthread 18 | PROTOC := "$(PROTOHOME)/src/protoc" 19 | else 20 | PROTOBUF_CFLAGS ?= "-I/usr/local/src/protobuf/src" 21 | PROTOBUF_LIBS ?= /usr/local/src/protobuf/src/.libs 22 | PROTOBUF_LDFLAGS ?= "-Wl,-rpath=$(PROTOBUF_LIBS)" "-L$(PROTOBUF_LIBS)" -lprotobuf -pthread -lpthread 23 | endif 24 | 25 | 26 | all: benchmarks-erl-code 27 | 28 | benchmarks-erl-code: tmp/msg_r.beam tmp/d_r.beam \ 29 | tmp/msg_mo.beam tmp/d_mo.beam \ 30 | tmp/msg_mp.beam tmp/d_mp.beam 31 | 32 | benchmarks-gr-code: tmp/msg_r.beam 33 | 34 | benchmarks-maps-mo-code: tmp/msg_mo.beam 35 | 36 | benchmarks-nif-code: tmp/msg.beam tmp/msg.nif.so \ 37 | tmp/d.beam tmp/d.nif.so 38 | 39 | show-hw-sw-info = \ 40 | echo CPU info; \ 41 | egrep '^model name' /proc/cpuinfo | head -1; \ 42 | egrep '^cache' /proc/cpuinfo | head -1; \ 43 | printf 'cores/threads : %s\n' `egrep -c '^processor' /proc/cpuinfo`; \ 44 | egrep '^bogomips' /proc/cpuinfo | head -1; \ 45 | echo; \ 46 | $(erl) +V 47 | 48 | # Args: 49 | # $1 - module suffix 50 | # $2 - any options 51 | # $3 - proto file name 52 | gpb-compile = \ 53 | $(erl) -boot start_clean -pa ../ebin -noshell -noinput +B \ 54 | -v never -c false -I`pwd` -o tmp \ 55 | -modsuffix $1 \ 56 | $(2) \ 57 | -s gpb_compile c $(3) 58 | 59 | tmp/%_r.erl: %.proto 60 | [ -d tmp ] || mkdir tmp 61 | $(call gpb-compile,_r,,$<) 62 | 63 | tmp/%_mo.erl: %.proto 64 | [ -d tmp ] || mkdir tmp 65 | $(call gpb-compile,_mo,-maps -maps_unset_optional omitted,$<) 66 | 67 | tmp/%_mp.erl: %.proto 68 | [ -d tmp ] || mkdir tmp 69 | $(call gpb-compile,_mp,-maps -maps_unset_optional present_undefined,$<) 70 | 71 | %.beam: %.erl 72 | cd tmp; $(erlc) -Wall $(HIPE_ERLC_OPTS) -I../../include +debug_info \ 73 | $(patsubst tmp/%,%,$<) 74 | 75 | tmp/%.nif.so: %.proto 76 | $(PROTOC) --cpp_out=tmp/ $*.proto 77 | $(CXX) -g -fPIC -O3 $(PROTOBUF_CFLAGS) $(CXXFLAGS) \ 78 | -o tmp/$*.pb.o -c tmp/$*.pb.cc 79 | $(CXX) -g -fPIC -Wall -O3 $(PROTOBUF_CFLAGS) $(CXXFLAGS) \ 80 | -o tmp/$*.nif.o -c tmp/$*.nif.cc 81 | $(CXX) -g -fPIC -shared -O3 -Wall $(PROTOBUF_CFLAGS) $(CXXFLAGS) \ 82 | -o $@ tmp/$*.nif.o tmp/$*.pb.o $(PROTOBUF_LDFLAGS) 83 | 84 | tmp/%.erl: %.proto 85 | [ -d tmp ] || mkdir tmp 86 | $(call gpb-compile,"",-nif,$<) 87 | 88 | clean: 89 | $(RM) -r tmp 90 | 91 | # Run only the "standard" Google benchmark messages with records 92 | benchmarks: benchmarks-gr-code 93 | @$(call show-hw-sw-info) 94 | @echo 95 | ./proto-bench \ 96 | msg_r Message1 google_message1.dat \ 97 | msg_r Message2 google_message2.dat 98 | 99 | # Run only (one of) the maps benchmarks 100 | maps-benchmarks: benchmarks-maps-mo-code 101 | @$(call show-hw-sw-info) 102 | @echo 103 | ./proto-bench \ 104 | msg_mo Message1 google_message1.dat \ 105 | msg_mo Message2 google_message2.dat 106 | 107 | # "Standard" Google benchmark messages 108 | erl-benchmarks: benchmarks-erl-code 109 | @$(call show-hw-sw-info) 110 | @echo 111 | ./proto-bench \ 112 | --echo "-- Records --" \ 113 | msg_r Message1 google_message1.dat \ 114 | msg_r Message2 google_message2.dat \ 115 | --echo "--" \ 116 | --echo "-- Maps (unset optionals: omitted) --" \ 117 | msg_mo Message1 google_message1.dat \ 118 | msg_mo Message2 google_message2.dat \ 119 | --echo "--" \ 120 | --echo "-- Maps (unset optionals: present, undefined) --" \ 121 | msg_mp Message1 google_message1.dat \ 122 | msg_mp Message2 google_message2.dat 123 | 124 | # Some "d" messages 125 | d-benchmarks: benchmarks-code 126 | @$(call show-hw-sw-info) 127 | @echo 128 | ./proto-bench \ 129 | --echo "-- Records --" \ 130 | d_r dm1 --multi d-msgs/d-msg-n*.dat --end-multi \ 131 | d_r dm1 d-msgs/d-all-concatenated.dat \ 132 | --echo "--" \ 133 | --echo "-- Maps (unset optionals: omitted) --" \ 134 | d_mo dm1 --multi d-msgs/d-msg-n*.dat --end-multi \ 135 | d_mo dm1 d-msgs/d-all-concatenated.dat \ 136 | --echo "--" \ 137 | --echo "-- Maps (unset optionals: present, undefined) --" \ 138 | d_mp dm1 --multi d-msgs/d-msg-n*.dat --end-multi \ 139 | d_mp dm1 d-msgs/d-all-concatenated.dat 140 | 141 | # Some "d" messages 142 | nif-benchmarks: benchmarks-nif-code 143 | @$(call show-hw-sw-info) 144 | @echo 145 | ./proto-bench \ 146 | msg Message1 google_message1.dat \ 147 | msg Message2 google_message2.dat \ 148 | d dm1 --multi d-msgs/d-msg-n*.dat --end-multi \ 149 | d dm1 d-msgs/d-all-concatenated.dat \ 150 | -------------------------------------------------------------------------------- /benchmarks/README.txt: -------------------------------------------------------------------------------- 1 | About the benchmarks 2 | -------------------- 3 | 4 | The benchmark setup is very similar to the benchmarks found in the 5 | protobuf's subversion repository. 6 | 7 | Deviations from the benchmarks in protobuf's subversion repository: 8 | 9 | * The google_size.proto and the google_speed.proto have been 10 | fused into msg.proto since gpb doesn't know how to optimize 11 | neither for speed nor for code size. 12 | * The "repeated group" construction has been changed into a 13 | repeated (sub) message, since groups were not supported by gpb originally. 14 | The google_message2.dat file has been updated accordingly. 15 | * Addition of the d.proto and messages in d-msgs/ This contains 16 | randomly generated messages according to d.proto. 17 | The d-msgs/d-all-concatenated.dat will cause a lot of message 18 | merging to happen upon deserialization. 19 | 20 | Running a benchmark 21 | ------------------- 22 | 23 | 1. Build the gpb itself (in the top-directory of gpb) 24 | $ rebar compile 25 | 26 | 2. Build the benchmarking code (in this benchmarks directory) 27 | $ make 28 | 29 | 3. Run the benchmarks: 30 | $ make benchmarks 31 | 32 | This will call the proto-bench escript. Arguments are given in 33 | triples - the first is the module name; the second is the message 34 | name, the third is the filename. For example: 35 | $ ./proto-bench \ msg Message1 google_message1.dat \ 36 | msg Message2 google_message2.dat 37 | 38 | There are currently some alternative benchmarks one can run: 39 | 40 | - make maps-benchmarks 41 | 42 | This runs the same benchmarks (the google messages) with code 43 | compiled for maps with maps_unset_optional = omitted 44 | 45 | - make erl-benchamrks 46 | 47 | Benchmark the google messages using records (suffix = _r), and 48 | twice with maps; once with maps_unset_optional = omitted 49 | (suffix = _mo) once with maps_unset_optional = present_undefined 50 | (suffix = _mp) thus, the target "benchmarks" and "maps-benchmarks" 51 | run subsets of this target. 52 | 53 | - make nif-benchmarks 54 | 55 | Benchmark the google messages using the nif bindings to Google's 56 | libprotobuf 57 | 58 | To run the benchmarks with HiPE-compiled code, set the HIPE 59 | variable, for example like this: 60 | 61 | make HIPE=1 erl-benchmarks 62 | 63 | Please note that things here might change as development shifts, 64 | for instance target names and variables, these names are super stable. 65 | 66 | 4. Wait! Each test runs for around 30--35 seconds, and there are 2 tests 67 | per msg/data combination. The above command will take about 68 | 4.5 -- 5 minutes to run. 69 | -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-all-concatenated.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-all-concatenated.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n01.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n01.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n02.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n02.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n03.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n03.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n04.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n04.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n05.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n05.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n06.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n06.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n07.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n07.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n08.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n08.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n09.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n09.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n10.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n10.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n11.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n11.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n12.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n12.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n13.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n13.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n14.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n14.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n15.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n15.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n16.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n16.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n17.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n17.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n18.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n18.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n19.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n19.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n20.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n20.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n21.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n21.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n22.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n22.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n23.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n23.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n24.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n24.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n25.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n25.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n26.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n26.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n27.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n27.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n28.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n28.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n29.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n29.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n30.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n30.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n31.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n31.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n32.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n32.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n33.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n33.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n34.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n34.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n35.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n35.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n36.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n36.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n37.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n37.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n38.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n38.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n39.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n39.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n40.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n40.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n41.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n41.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n42.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n42.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n43.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n43.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n44.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n44.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n45.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n45.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n46.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n46.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n47.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n47.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n48.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n48.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n49.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n49.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n50.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n50.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n51.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n51.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n52.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n52.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n53.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n53.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n54.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n54.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n55.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n55.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n56.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n56.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n57.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n57.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n58.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n58.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n59.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n59.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n60.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n60.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n61.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n61.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n62.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n62.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n63.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n63.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n64.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n64.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n65.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n65.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n66.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n66.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n67.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n67.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n68.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n68.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n69.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n69.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n70.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n70.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n71.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n71.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n72.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n72.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n73.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n73.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n74.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n74.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n75.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n75.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n76.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n76.dat -------------------------------------------------------------------------------- /benchmarks/d-msgs/d-msg-n77.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/d-msgs/d-msg-n77.dat -------------------------------------------------------------------------------- /benchmarks/d.proto: -------------------------------------------------------------------------------- 1 | // many deeply nested messages 2 | 3 | enum de01 { 4 | DE01_E01 = 200; 5 | DE01_E02 = 201; 6 | DE01_E03 = 202; 7 | DE01_E04 = 203; 8 | DE01_E05 = 204; 9 | DE01_E06 = 205; 10 | DE01_E07 = 206; 11 | DE01_E08 = 207; 12 | DE01_E10 = 208; 13 | DE01_E11 = 209; 14 | DE01_E12 = 210; 15 | DE01_E13 = 211; 16 | DE01_E14 = 212; 17 | DE01_E15 = 213; 18 | DE01_E16 = 214; 19 | DE01_E17 = 215; 20 | DE01_E18 = 216; 21 | DE01_E19 = 217; 22 | DE01_E20 = 218; 23 | DE01_E21 = 219; 24 | } 25 | message dm02 { 26 | required fixed32 dm02f01 = 1; 27 | required uint32 dm02f02 = 2; 28 | required string dm02f03 = 3; 29 | } 30 | message dm03 { 31 | required fixed32 dm03f01 = 1; 32 | required uint32 dm03f02 = 2; 33 | optional uint32 dm03f03 = 3 [default = 0]; 34 | optional uint32 dm03f04 = 4 [default = 0]; 35 | required string dm03f05 = 5; 36 | } 37 | message dm04 { 38 | required string dm04f01 = 1; 39 | required uint32 dm04f02 = 10; 40 | required fixed32 dm04f03 = 2; 41 | required uint32 dm04f04 = 3; 42 | optional uint32 dm04f05 = 4 [default = 0]; 43 | optional uint32 dm04f06 = 5 [default = 0]; 44 | required string dm04f07 = 6; 45 | required string dm04f08 = 7; 46 | required string dm04f09 = 8; 47 | required string dm04f10 = 9; 48 | } 49 | message dm05 { 50 | } 51 | message dm06 { 52 | } 53 | message dm07 { 54 | optional fixed64 dm07f01 = 1; 55 | repeated uint32 dm07f02 = 2; 56 | } 57 | message dm08 { 58 | optional fixed64 dm08f01 = 1; 59 | repeated uint32 dm08f02 = 2; 60 | } 61 | message dm09 { 62 | optional string dm09f01 = 1; 63 | optional bool dm09f02 = 2; 64 | } 65 | message dm10 { 66 | optional string dm10f01 = 1; 67 | required uint32 dm10f02 = 2; 68 | optional uint32 dm10f03 = 3; 69 | } 70 | enum de02 { 71 | DE02_E01 = 1; 72 | DE02_E02 = 2; 73 | } 74 | message dm11 { 75 | optional string dm11f01 = 1; 76 | optional de02 dm11f02 = 2; 77 | } 78 | message dm12 { 79 | required string dm12f01 = 1; 80 | required uint32 dm12f02 = 2; 81 | optional bool dm12f03 = 3; 82 | } 83 | message dm13 { 84 | required uint32 dm13f01 = 1; 85 | optional uint32 dm13f02 = 2; 86 | } 87 | message dm14 { 88 | required uint32 dm14f01 = 1; 89 | required de02 dm14f02 = 2; 90 | } 91 | message dm15 { 92 | required uint32 dm15f01 = 1; 93 | } 94 | message dm16 { 95 | required uint32 dm16f01 = 1; 96 | } 97 | enum de03 { 98 | DE03_E01 = 1; 99 | DE03_E02 = 2; 100 | } 101 | message dm17 { 102 | required uint32 dm17f01 = 1; 103 | required de03 dm17f02 = 2; 104 | } 105 | message dm18 { 106 | required uint32 dm18f01 = 1; 107 | required uint32 dm18f02 = 2; 108 | required int32 dm18f03 = 3; 109 | optional bool dm18f04 = 4 [default = false]; 110 | optional uint32 dm18f05 = 5 [default = 100]; 111 | optional uint32 dm18f06 = 6 [default = 100]; 112 | } 113 | message dm19 { 114 | required uint32 dm19f01 = 1; 115 | } 116 | message dm20 { 117 | required uint32 dm20f01 = 1; 118 | } 119 | message dm21 { 120 | required uint32 dm21f01 = 1; 121 | } 122 | message dm22 { 123 | required uint32 dm22f01 = 1; 124 | } 125 | enum de04 { 126 | DE04_E01 = 100; 127 | DE04_E02 = 101; 128 | DE04_E03 = 102; 129 | DE04_E04 = 103; 130 | DE04_E05 = 104; 131 | } 132 | message dm23 { 133 | optional uint32 dm23f01 = 1; 134 | optional fixed32 dm23f02 = 2; 135 | optional bytes dm23f03 = 3; 136 | } 137 | message dm24 { 138 | optional string dm24f01 = 1; 139 | optional string dm24f02 = 2; 140 | optional string dm24f03 = 3; 141 | optional string dm24f04 = 4; 142 | optional string dm24f05 = 6; 143 | } 144 | message dm25 { 145 | optional string dm25f01 = 1; 146 | optional string dm25f02 = 2; 147 | optional string dm25f03 = 3; 148 | } 149 | message dm26 { 150 | optional string dm26f01 = 1; 151 | optional string dm26f02 = 2; 152 | optional string dm26f03 = 3; 153 | optional uint32 dm26f04 = 4; 154 | } 155 | message dm27 { 156 | optional string dm27f01 = 1; 157 | optional uint32 dm27f02 = 2; 158 | } 159 | message dm28 { 160 | optional dm23 dm28f01 = 1; 161 | optional dm24 dm28f02 = 2; 162 | optional dm25 dm28f03 = 3; 163 | } 164 | message dm29 { 165 | optional dm23 dm29f01 = 1; 166 | optional dm26 dm29f02 = 2; 167 | } 168 | message dm30 { 169 | } 170 | message dm31 { 171 | repeated dm26 dm31f01 = 1; 172 | } 173 | message dm32 { 174 | optional string dm32f01 = 1; 175 | optional uint32 dm32f02 = 2; 176 | repeated dm27 dm32f03 = 3; 177 | } 178 | enum de05 { 179 | DE05_E01 = 300; 180 | DE05_E02 = 301; 181 | DE05_E03 = 302; 182 | DE05_E04 = 303; 183 | DE05_E05 = 304; 184 | DE05_E06 = 305; 185 | DE05_E07 = 306; 186 | DE05_E08 = 307; 187 | DE05_E09 = 308; 188 | DE05_E10 = 309; 189 | DE05_E11 = 310; 190 | } 191 | enum de06 { 192 | DE06_E01 = 1; 193 | DE06_E02 = 2; 194 | DE06_E03 = 3; 195 | } 196 | enum de07 { 197 | DE07_E01 = 1; 198 | DE07_E02 = 2; 199 | } 200 | message dm33 { 201 | } 202 | message dm34 { 203 | } 204 | message dm35 { 205 | optional uint32 dm35f01 = 1; 206 | optional uint32 dm35f02 = 2; 207 | optional uint32 dm35f03 = 3; 208 | optional uint32 dm35f04 = 4; 209 | optional uint32 dm35f05 = 5; 210 | optional uint32 dm35f06 = 6; 211 | } 212 | message dm36 { 213 | required de06 dm36f01 = 1; 214 | optional de07 dm36f02 = 6 [default = DE07_E02]; 215 | required int32 dm36f03 = 2; 216 | required int32 dm36f04 = 7; 217 | optional dm33 dm36f05 = 3; 218 | optional dm34 dm36f06 = 4; 219 | optional dm35 dm36f07 = 5; 220 | } 221 | message dm37 { 222 | repeated dm36 dm37f01 = 1; 223 | } 224 | message dm38 { 225 | repeated int32 dm38f01 = 1; 226 | } 227 | message dm39 { 228 | repeated int32 dm39f01 = 1; 229 | } 230 | message dm40 { 231 | repeated int32 dm40f01 = 1; 232 | } 233 | message dm41 { 234 | optional uint32 dm41f01 = 1; 235 | } 236 | message dm42 { 237 | optional uint32 dm42f01 = 1; 238 | } 239 | message dm43 { 240 | } 241 | message dm44 { 242 | required uint32 dm44f01 = 1; 243 | } 244 | message dm45 { 245 | } 246 | message dm46 { 247 | required uint32 dm46f01 = 1; 248 | required uint32 dm46f02 = 2; 249 | } 250 | message dm47 { 251 | } 252 | enum de08 { 253 | DE08_E01 = 400; 254 | DE08_E02 = 401; 255 | DE08_E03 = 402; 256 | DE08_E04 = 403; 257 | DE08_E05 = 404; 258 | DE08_E06 = 405; 259 | DE08_E07 = 406; 260 | DE08_E08 = 407; 261 | DE08_E09 = 408; 262 | DE08_E10 = 409; 263 | DE08_E11 = 410; 264 | DE08_E12 = 411; 265 | DE08_E13 = 412; 266 | } 267 | message dm48 { 268 | } 269 | message dm49 { 270 | required uint32 dm49f01 = 2; 271 | required uint32 dm49f02 = 3; 272 | } 273 | message dm50 { 274 | required uint32 dm50f01 = 1; 275 | optional uint32 dm50f02 = 2; 276 | required bool dm50f03 = 3; 277 | } 278 | message dm51 { 279 | optional bool dm51f01 = 1 [default = false]; 280 | optional dm50 dm51f02 = 2; 281 | } 282 | message dm52 { 283 | optional uint32 dm52f01 = 1; 284 | optional sint32 dm52f02 = 2; 285 | optional int32 dm52f03 = 3; 286 | optional uint32 dm52f04 = 4; 287 | optional int32 dm52f05 = 5; 288 | optional int32 dm52f06 = 6; 289 | optional int32 dm52f07 = 7; 290 | optional int32 dm52f08 = 8; 291 | optional int32 dm52f09 = 9; 292 | optional int32 dm52f10 = 10; 293 | optional sint32 dm52f11 = 11; 294 | optional int32 dm52f12 = 12; 295 | optional uint32 dm52f13 = 13; 296 | optional int32 dm52f14 = 14; 297 | optional uint32 dm52f15 = 15; 298 | optional int32 dm52f16 = 16; 299 | optional int32 dm52f17 = 17; 300 | optional int32 dm52f18 = 18; 301 | optional int32 dm52f19 = 19; 302 | optional bytes dm52f20 = 20; 303 | optional uint32 dm52f21 = 21; 304 | optional uint32 dm52f22 = 22; 305 | optional dm51 dm52f23 = 23; 306 | } 307 | message dm53 { 308 | } 309 | message dm54 { 310 | } 311 | message dm55 { 312 | } 313 | enum de09 { 314 | DE09_E01 = 1; 315 | DE09_E02 = 2; 316 | DE09_E03 = 3; 317 | } 318 | message dm56 { 319 | required int32 dm56f01 = 1; 320 | optional int32 dm56f02 = 2; 321 | optional sint32 dm56f03 = 3; 322 | optional int32 dm56f04 = 4; 323 | optional int32 dm56f05 = 5; 324 | } 325 | message dm57 { 326 | required de09 dm57f01 = 1; 327 | optional dm56 dm57f02 = 2; 328 | } 329 | message dm58 { 330 | repeated dm57 dm58f01 = 1; 331 | } 332 | message dm59 { 333 | repeated int32 dm59f01 = 1; 334 | } 335 | enum de10 { 336 | DE10_E01 = 1; 337 | DE10_E02 = 2; 338 | } 339 | message dm60 { 340 | required de10 dm60f01 = 1; 341 | } 342 | message dm61 { 343 | } 344 | message dm62 { 345 | } 346 | message dm63 { 347 | required uint32 dm63f01 = 1; 348 | optional uint32 dm63f02 = 2 [default = 100]; 349 | optional uint32 dm63f03 = 3; 350 | optional uint32 dm63f04 = 4 [default = 211]; 351 | optional int32 dm63f05 = 5; 352 | optional int32 dm63f06 = 6; 353 | optional bool dm63f07 = 7 [default = true]; 354 | } 355 | message dm64 { 356 | } 357 | enum de11 { 358 | DE11_E01 = 500; 359 | DE11_E02 = 501; 360 | DE11_E03 = 502; 361 | } 362 | enum de12 { 363 | DE12_E01 = -2; 364 | DE12_E02 = 0; 365 | DE12_E03 = 2; 366 | } 367 | enum de13 { 368 | DE13_E01 = 1; 369 | DE13_E02 = 3; 370 | DE13_E03 = 5; 371 | } 372 | enum de14 { 373 | DE14_E01 = -2; 374 | DE14_E02 = 0; 375 | DE14_E03 = 1; 376 | DE14_E04 = 2; 377 | } 378 | enum de15 { 379 | DE15_E01 = -2; 380 | DE15_E02 = 0; 381 | DE15_E03 = 2; 382 | } 383 | enum de16 { 384 | DE16_E01 = -2; 385 | DE16_E02 = 0; 386 | DE16_E03 = 2; 387 | } 388 | enum de17 { 389 | DE17_E01 = 0; 390 | DE17_E02 = 1; 391 | } 392 | message dm65 { 393 | } 394 | message dm66 { 395 | optional uint32 dm66f01 = 1; 396 | optional uint32 dm66f02 = 2; 397 | optional uint32 dm66f03 = 3; 398 | optional uint32 dm66f04 = 4; 399 | optional int32 dm66f05 = 5; 400 | optional int32 dm66f06 = 6; 401 | optional int32 dm66f07 = 7; 402 | optional de12 dm66f08 = 8; 403 | optional de13 dm66f09 = 9; 404 | optional de14 dm66f10 = 10; 405 | optional de15 dm66f11 = 11; 406 | optional de16 dm66f12 = 12; 407 | optional int32 dm66f13 = 16; 408 | optional int32 dm66f14 = 13; 409 | optional int32 dm66f15 = 14; 410 | optional bool dm66f16 = 18; 411 | optional de17 dm66f17 = 15; 412 | optional int32 dm66f18 = 17; 413 | } 414 | message dm67 { 415 | } 416 | enum de18 { 417 | DE18_E01 = 600; 418 | DE18_E02 = 601; 419 | DE18_E03 = 602; 420 | DE18_E04 = 603; 421 | DE18_E05 = 604; 422 | DE18_E06 = 605; 423 | DE18_E07 = 606; 424 | DE18_E08 = 607; 425 | } 426 | message dm68 { 427 | optional string dm68f01 = 1; 428 | optional uint32 dm68f02 = 2; 429 | optional fixed32 dm68f03 = 3; 430 | optional uint32 dm68f04 = 4; 431 | optional uint32 dm68f05 = 5; 432 | optional uint32 dm68f06 = 6; 433 | } 434 | message dm69 { 435 | } 436 | message dm70 { 437 | optional fixed32 dm70f01 = 1; 438 | } 439 | message dm71 { 440 | } 441 | message dm72 { 442 | } 443 | message dm73 { 444 | required fixed32 dm73f01 = 1; 445 | } 446 | message dm74 { 447 | required fixed32 dm74f01 = 1; 448 | } 449 | message dm75 { 450 | required fixed32 dm75f01 = 1; 451 | } 452 | enum de19 { 453 | DE19_E01 = 700; 454 | DE19_E02 = 701; 455 | } 456 | message dm76 { 457 | } 458 | message dm77 { 459 | } 460 | enum de20 { 461 | DE20_E01 = 800; 462 | DE20_E02 = 801; 463 | } 464 | message dm78 { 465 | } 466 | message dm79 { 467 | required bool dm79f01 = 1; 468 | repeated uint32 dm79f02 = 2; 469 | repeated uint32 dm79f03 = 3; 470 | repeated uint32 dm79f04 = 4; 471 | repeated int32 dm79f05 = 5; 472 | } 473 | message dm1 { 474 | required uint32 dm01f01 = 1; 475 | optional dm28 dm01f02 = 100; 476 | optional dm29 dm01f03 = 101; 477 | optional dm30 dm01f04 = 102; 478 | optional dm31 dm01f05 = 103; 479 | optional dm32 dm01f06 = 104; 480 | optional dm02 dm01f07 = 200; 481 | optional dm03 dm01f08 = 201; 482 | optional dm04 dm01f09 = 202; 483 | optional dm05 dm01f10 = 203; 484 | optional dm06 dm01f11 = 204; 485 | optional dm07 dm01f12 = 205; 486 | optional dm08 dm01f13 = 206; 487 | optional dm09 dm01f14 = 207; 488 | optional dm10 dm01f15 = 208; 489 | optional dm11 dm01f16 = 209; 490 | optional dm12 dm01f17 = 210; 491 | optional dm13 dm01f18 = 211; 492 | optional dm14 dm01f19 = 212; 493 | optional dm15 dm01f20 = 213; 494 | optional dm16 dm01f21 = 214; 495 | optional dm17 dm01f22 = 215; 496 | optional dm18 dm01f23 = 216; 497 | optional dm20 dm01f24 = 217; 498 | optional dm21 dm01f25 = 218; 499 | optional dm19 dm01f26 = 219; 500 | optional dm37 dm01f27 = 300; 501 | optional dm38 dm01f28 = 301; 502 | optional dm39 dm01f29 = 302; 503 | optional dm40 dm01f30 = 303; 504 | optional dm41 dm01f31 = 304; 505 | optional dm42 dm01f32 = 305; 506 | optional dm43 dm01f33 = 306; 507 | optional dm44 dm01f34 = 307; 508 | optional dm45 dm01f35 = 308; 509 | optional dm46 dm01f36 = 309; 510 | optional dm47 dm01f37 = 310; 511 | optional dm48 dm01f38 = 400; 512 | optional dm49 dm01f39 = 401; 513 | optional dm52 dm01f40 = 402; 514 | optional dm53 dm01f41 = 403; 515 | optional dm54 dm01f42 = 404; 516 | optional dm55 dm01f43 = 405; 517 | optional dm58 dm01f44 = 406; 518 | optional dm59 dm01f45 = 407; 519 | optional dm60 dm01f46 = 408; 520 | optional dm61 dm01f47 = 409; 521 | optional dm63 dm01f48 = 410; 522 | optional dm64 dm01f49 = 411; 523 | optional dm62 dm01f50 = 412; 524 | optional dm65 dm01f51 = 500; 525 | optional dm66 dm01f52 = 501; 526 | optional dm67 dm01f53 = 502; 527 | optional dm68 dm01f54 = 600; 528 | optional dm69 dm01f55 = 601; 529 | optional dm70 dm01f56 = 602; 530 | optional dm71 dm01f57 = 603; 531 | optional dm72 dm01f58 = 604; 532 | optional dm73 dm01f59 = 605; 533 | optional dm74 dm01f60 = 606; 534 | optional dm75 dm01f61 = 607; 535 | optional dm76 dm01f62 = 700; 536 | optional dm77 dm01f63 = 701; 537 | optional dm78 dm01f64 = 800; 538 | optional dm79 dm01f65 = 801; 539 | } 540 | 541 | 542 | -------------------------------------------------------------------------------- /benchmarks/google_message1.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/google_message1.dat -------------------------------------------------------------------------------- /benchmarks/google_message2.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-abrahamsson/gpb/d3920bb120d6ff04ac1c94bf3f744a1800bc18ea/benchmarks/google_message2.dat -------------------------------------------------------------------------------- /benchmarks/msg.proto: -------------------------------------------------------------------------------- 1 | message Message1 { 2 | required string field1 = 1; 3 | optional string field9 = 9; 4 | optional string field18 = 18; 5 | optional bool field80 = 80 [default=false]; 6 | optional bool field81 = 81 [default=true]; 7 | required int32 field2 = 2; 8 | required int32 field3 = 3; 9 | optional int32 field280 = 280; 10 | optional int32 field6 = 6 [default=0]; 11 | optional int64 field22 = 22; 12 | optional string field4 = 4; 13 | repeated fixed64 field5 = 5; 14 | optional bool field59 = 59 [default=false]; 15 | optional string field7 = 7; 16 | optional int32 field16 = 16; 17 | optional int32 field130 = 130 [default=0]; 18 | optional bool field12 = 12 [default=true]; 19 | optional bool field17 = 17 [default=true]; 20 | optional bool field13 = 13 [default=true]; 21 | optional bool field14 = 14 [default=true]; 22 | optional int32 field104 = 104 [default=0]; 23 | optional int32 field100 = 100 [default=0]; 24 | optional int32 field101 = 101 [default=0]; 25 | optional string field102 = 102; 26 | optional string field103 = 103; 27 | optional int32 field29 = 29 [default=0]; 28 | optional bool field30 = 30 [default=false]; 29 | optional int32 field60 = 60 [default=-1]; 30 | optional int32 field271 = 271 [default=-1]; 31 | optional int32 field272 = 272 [default=-1]; 32 | optional int32 field150 = 150; 33 | optional int32 field23 = 23 [default=0]; 34 | optional bool field24 = 24 [default=false]; 35 | optional int32 field25 = 25 [default=0]; 36 | optional Message1SubMessage field15 = 15; 37 | optional bool field78 = 78; 38 | optional int32 field67 = 67 [default=0]; 39 | optional int32 field68 = 68; 40 | optional int32 field128 = 128 [default=0]; 41 | optional string field129 = 129 [default="xxxxxxxxxxxxxxxxxxxxx"]; 42 | optional int32 field131 = 131 [default=0]; 43 | } 44 | 45 | message Message1SubMessage { 46 | optional int32 field1 = 1 [default=0]; 47 | optional int32 field2 = 2 [default=0]; 48 | optional int32 field3 = 3 [default=0]; 49 | optional string field15 = 15; 50 | optional bool field12 = 12 [default=true]; 51 | optional int64 field13 = 13; 52 | optional int64 field14 = 14; 53 | optional int32 field16 = 16; 54 | optional int32 field19 = 19 [default=2]; 55 | optional bool field20 = 20 [default=true]; 56 | optional bool field28 = 28 [default=true]; 57 | optional fixed64 field21 = 21; 58 | optional int32 field22 = 22; 59 | optional bool field23 = 23 [ default=false ]; 60 | optional bool field206 = 206 [default=false]; 61 | optional fixed32 field203 = 203; 62 | optional int32 field204 = 204; 63 | optional string field205 = 205; 64 | optional uint64 field207 = 207; 65 | optional uint64 field300 = 300; 66 | } 67 | 68 | message Message2 { 69 | optional string field1 = 1; 70 | optional int64 field3 = 3; 71 | optional int64 field4 = 4; 72 | optional int64 field30 = 30; 73 | optional bool field75 = 75 [default=false]; 74 | optional string field6 = 6; 75 | optional bytes field2 = 2; 76 | optional int32 field21 = 21 [default=0]; 77 | optional int32 field71 = 71; 78 | optional float field25 = 25; 79 | optional int32 field109 = 109 [default=0]; 80 | optional int32 field210 = 210 [default=0]; 81 | optional int32 field211 = 211 [default=0]; 82 | optional int32 field212 = 212 [default=0]; 83 | optional int32 field213 = 213 [default=0]; 84 | optional int32 field216 = 216 [default=0]; 85 | optional int32 field217 = 217 [default=0]; 86 | optional int32 field218 = 218 [default=0]; 87 | optional int32 field220 = 220 [default=0]; 88 | optional int32 field221 = 221 [default=0]; 89 | optional float field222 = 222 [default=0.0]; 90 | optional int32 field63 = 63; 91 | repeated Message2Group1 Group1 = 10; 92 | repeated string field128 = 128; 93 | optional int64 field131 = 131; 94 | repeated string field127 = 127; 95 | optional int32 field129 = 129; 96 | repeated int64 field130 = 130; 97 | optional bool field205 = 205 [default=false]; 98 | optional bool field206 = 206 [default=false]; 99 | } 100 | 101 | message Message2Group1 { 102 | required float field11 = 11; 103 | optional float field26 = 26; 104 | optional string field12 = 12; 105 | optional string field13 = 13; 106 | repeated string field14 = 14; 107 | required uint64 field15 = 15; 108 | optional int32 field5 = 5; 109 | optional string field27 = 27; 110 | optional int32 field28 = 28; 111 | optional string field29 = 29; 112 | optional string field16 = 16; 113 | repeated string field22 = 22; 114 | repeated int32 field73 = 73; 115 | optional int32 field20 = 20 [default=0]; 116 | optional string field24 = 24; 117 | optional Message2GroupedMessage field31 = 31; 118 | } 119 | 120 | message Message2GroupedMessage { 121 | optional float field1 = 1; 122 | optional float field2 = 2; 123 | optional float field3 = 3 [default=0.0]; 124 | optional bool field4 = 4; 125 | optional bool field5 = 5; 126 | optional bool field6 = 6 [default=true]; 127 | optional bool field7 = 7 [default=false]; 128 | optional float field8 = 8; 129 | optional bool field9 = 9; 130 | optional float field10 = 10; 131 | optional int64 field11 = 11; 132 | } 133 | -------------------------------------------------------------------------------- /benchmarks/proto-bench: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env escript 2 | %% This line tells emacs to use -*- erlang -*- mode -*- coding: iso-8859-1 -*- 3 | %%! -pa ../ebin/ -pa tmp/ -sname protoexerciser 4 | 5 | %%% Copyright (C) 2011 Tomas Abrahamsson 6 | %%% 7 | %%% Author: Tomas Abrahamsson 8 | %%% 9 | %%% This library is free software; you can redistribute it and/or 10 | %%% modify it under the terms of the GNU Lesser General Public 11 | %%% License as published by the Free Software Foundation; either 12 | %%% version 2.1 of the License, or (at your option) any later version. 13 | %%% 14 | %%% This library is distributed in the hope that it will be useful, 15 | %%% but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | %%% Lesser General Public License for more details. 18 | %%% 19 | %%% You should have received a copy of the GNU Lesser General Public 20 | %%% License along with this library; if not, write to the Free Software 21 | %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 22 | %%% MA 02110-1301 USA 23 | 24 | -mode(compile). 25 | %-compile(export_all). 26 | -export([main/1]). 27 | 28 | main(Args) -> 29 | run_tests(Args). 30 | 31 | run_tests(["--echo", Str | Rest]) -> 32 | io:format("~s~n", [Str]), 33 | run_tests(Rest); 34 | run_tests([MsgModuleStr, MsgNameStr | MsgFileAndRest]) -> 35 | MsgModule = list_to_atom(MsgModuleStr), 36 | MsgName = list_to_atom(MsgNameStr), 37 | {MsgFiles, Rest} = pickup_msg_file_or_files(MsgFileAndRest), 38 | MsgBins = [begin {{ok, B},_} = {file:read_file(MsgFile),MsgFile}, 39 | B 40 | end || MsgFile <- MsgFiles], 41 | DataSize = iolist_size(MsgBins), 42 | EMsgName = case encode_needs_msgname(MsgModule) of 43 | true -> MsgName; 44 | false -> undefined 45 | end, 46 | Decoder = fun() -> decode_bins(MsgBins, MsgModule, MsgName) end, 47 | Msgs = [MsgModule:decode_msg(Bin, MsgName) || Bin <- MsgBins], 48 | Encoder = fun() -> encode_msgs(Msgs, MsgModule, EMsgName) end, 49 | maybe_warn_skewed_results(), 50 | io:format("Benchmarking ~s ~s with file ~s~n", 51 | [MsgModule, MsgName, string:join(MsgFiles, ",")]), 52 | run_test("Serialize to binary", DataSize, Encoder), 53 | run_test("Deserialize from binary", DataSize, Decoder), 54 | io:format("~n"), 55 | run_tests(Rest); 56 | run_tests([]) -> 57 | ok. 58 | 59 | encode_needs_msgname(MsgModule) -> 60 | Exports = MsgModule:module_info(exports), 61 | case lists:keyfind(encode_msg, 1, Exports) of 62 | {encode_msg, 1} -> false; %% records 63 | {encode_msg, 2} -> true %% maps 64 | end. 65 | 66 | pickup_msg_file_or_files(["--multi" | MsgFilesAndRest]) -> 67 | EndMarker = "--end-multi", 68 | {MsgFiles, [EndMarker | Rest]} = 69 | lists:splitwith(fun(S) -> S /= EndMarker end, MsgFilesAndRest), 70 | {MsgFiles, Rest}; 71 | pickup_msg_file_or_files([MsgFile | Rest]) -> 72 | {[MsgFile], Rest}. 73 | 74 | 75 | decode_bins([MsgBin | Rest], MsgModule, MsgName) -> 76 | MsgModule:decode_msg(MsgBin, MsgName), 77 | decode_bins(Rest, MsgModule, MsgName); 78 | decode_bins([], _, _) -> 79 | ok. 80 | 81 | encode_msgs([Msg | Rest], MsgModule, undefined) -> 82 | MsgModule:encode_msg(Msg), %% MsgName not needed for records 83 | encode_msgs(Rest, MsgModule, undefined); 84 | encode_msgs([Msg | Rest], MsgModule, MsgName) -> 85 | MsgModule:encode_msg(Msg, MsgName), %% MsgName needed for maps 86 | encode_msgs(Rest, MsgModule, MsgName); 87 | encode_msgs([], _, _) -> 88 | ok. 89 | 90 | 91 | maybe_warn_skewed_results() -> 92 | ok. 93 | %%maybe_warn_skewed_results() -> 94 | %% try list_to_integer(erlang:system_info(otp_release)) of 95 | %% N when N >= 22 -> 96 | %% io:format( 97 | %% "\n" 98 | %% "NB: The results are currently skewed on Erlang 22 and later.\n" 99 | %% " Optimizations in Erlang 22 and the way the benchmarks\n" 100 | %% " are implemented cause more GC than normal.\n" 101 | %% " The benchmarking code is not yet adapted. It will show\n" 102 | %% " pessimistic values.\n" 103 | %% " See https://github.com/erlang/otp/commit/7d941c529d#commitcomment-31091771\n" 104 | %% " for more info.\n" 105 | %% "\n"); 106 | %% _ -> 107 | %% ok 108 | %% catch _:_ -> 109 | %% ok 110 | %% end. 111 | 112 | 113 | 114 | run_test(Description, DataSize, Action) -> 115 | P = spawn_opt( 116 | fun() -> 117 | run_test_aux(Description, DataSize, Action) 118 | end, 119 | [{min_heap_size, 10000000}, 120 | {min_bin_vheap_size, 10000000}]), 121 | M = monitor(process, P), 122 | receive 123 | {'DOWN',M,process,P,normal} -> 124 | ok; 125 | {'DOWN',M,process,P,Other} -> 126 | error({aux_died,Other}) 127 | end. 128 | 129 | run_test_aux(Description, DataSize, Action) -> 130 | MinSampleTime = 2, %% seconds 131 | TargetTime = 30, %% seconds 132 | {Elapsed, NumIterations} = iterate_until_elapsed(MinSampleTime, Action), 133 | TargetNumIterations = round((TargetTime / Elapsed) * NumIterations), 134 | Elapsed2 = time_action(TargetNumIterations, Action), 135 | io:format("~s: ~w iterations in ~.3fs; ~.2fMB/s~n", 136 | [Description, TargetNumIterations, Elapsed2, 137 | (TargetNumIterations * DataSize) / (Elapsed2 * 1024 * 1024)]), 138 | ok. 139 | 140 | iterate_until_elapsed(MaxDuration, Action) -> 141 | iterate_until_elapsed_2(1, MaxDuration, Action). 142 | 143 | iterate_until_elapsed_2(NumIterations, MaxDuration, Action) -> 144 | case time_action(NumIterations, Action) of 145 | Elapsed when Elapsed < MaxDuration -> 146 | iterate_until_elapsed_2(NumIterations * 2, MaxDuration, Action); 147 | Elapsed when Elapsed >= MaxDuration -> 148 | {Elapsed, NumIterations} 149 | end. 150 | 151 | time_action(NumIterations, Action) -> 152 | garbage_collect(), 153 | T0 = erlang:monotonic_time(), 154 | iterate_action(NumIterations, Action), 155 | T1 = erlang:monotonic_time(), 156 | to_seconds(T1 - T0, native). 157 | 158 | to_seconds(Time, InUnit) -> 159 | erlang:convert_time_unit(Time, InUnit, microsecond) / 1000000. 160 | 161 | iterate_action(N, Action) when N > 0 -> 162 | Action(), 163 | iterate_action(N-1, Action); 164 | iterate_action(0, _Action) -> 165 | ok. 166 | -------------------------------------------------------------------------------- /bin/protoc-erl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env escript 2 | %% -*- erlang -*- 3 | %%! -noinput +B 4 | 5 | main(Argv) -> 6 | setup_code_path(), 7 | case gpb_compile:parse_opts_and_args(Argv) of 8 | {ok, {Opts, Files}} -> 9 | Opts1 = Opts ++ [{show_usage_fn, fun() -> show_usage() end}], 10 | gpb_compile:c(Opts1, Files); %% will halt 11 | {error, Reason} -> 12 | io:format("Error: ~s.~n", [Reason]), 13 | show_usage(), 14 | halt(1) 15 | end. 16 | 17 | setup_code_path() -> 18 | ScriptName = escript:script_name(), 19 | %% check symbolic link 20 | RawFile = find_raw_file(ScriptName), 21 | 22 | BinDir = filename:dirname(RawFile), 23 | EBinDir = filename:join([BinDir, "..", "ebin"]), 24 | %% add the gpb ebin path to we can have access to gpb_compile 25 | case code:add_pathz(EBinDir) of 26 | true -> 27 | try gpb_compile:module_info() 28 | catch error:undef -> 29 | io:format( 30 | "Found dir ~p, but no usable gpb_compile.beam,~n" 31 | "please verify that gpb has been built properly.~n", 32 | [EBinDir]), 33 | halt(1) 34 | end, 35 | ok; 36 | {error, bad_directory} -> 37 | io:format( 38 | "Cannot find dir ~p~n" 39 | "please verify that gpb has been built properly.~n", 40 | [EBinDir]), 41 | halt(1) 42 | end. 43 | 44 | find_raw_file(Name) -> 45 | find_raw_file(Name, file:read_link(Name)). 46 | 47 | find_raw_file(Name, {error, _}) -> 48 | Name; 49 | 50 | find_raw_file(Name, {ok, Name1}) -> 51 | %% for relative symbolic link 52 | %% if Name1 is absolute, then AbsoluteName is Name1 53 | DirName = filename:dirname(Name), 54 | AbsoluteName = filename:join(DirName, Name1), 55 | find_raw_file(AbsoluteName, file:read_link(AbsoluteName)). 56 | 57 | show_usage() -> 58 | io:format("Usage: ~s [options] X.proto [...]~n", 59 | [filename:basename(escript:script_name())]), 60 | gpb_compile:show_args(). 61 | -------------------------------------------------------------------------------- /build/compile_descriptor: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env escript 2 | %% -*- erlang -*- 3 | -include_lib("kernel/include/file.hrl"). 4 | 5 | 6 | is_up_to_date(Target, Deps) -> 7 | case file:read_file_info(Target) of 8 | {ok, #file_info{mtime = TargetMTime}} -> 9 | lists:all(fun(Dep) -> 10 | case file:read_file_info(Dep) of 11 | {ok, #file_info{mtime = MTime}} -> 12 | MTime =< TargetMTime; 13 | _ -> 14 | false 15 | end 16 | end, Deps); 17 | _ -> 18 | false 19 | end. 20 | 21 | make_target(Target, Deps, CmdFun) -> 22 | case is_up_to_date(Target, Deps) of 23 | true -> 24 | ok; 25 | _ -> 26 | io:format("Compiling ~s...~n", [filename:basename(hd(Deps))]), 27 | CmdFun() 28 | end. 29 | 30 | make(Makescript) -> 31 | lists:foreach( 32 | fun({Target, Deps, CmdFun}) -> make_target(Target, Deps, CmdFun) end, 33 | Makescript). 34 | 35 | gpb_compile_file_cmd(Proto, Opts) -> 36 | fun() -> 37 | check_ok_or_halt(gpb_compile:file(Proto, Opts)) 38 | end. 39 | 40 | compile_file_cmd(Erl, Opts) -> 41 | fun() -> 42 | check_ok_or_halt(compile:file(Erl, Opts)) 43 | end. 44 | 45 | check_ok_or_halt(Res) -> 46 | if Res =:= ok -> ok; 47 | element(1, Res) =:= ok -> ok; 48 | true -> halt(1) 49 | end. 50 | 51 | deps_dir() -> 52 | case os:getenv("REBAR_DEPS_DIR") of 53 | false -> 54 | %% Elixir 1.12+ 55 | os:getenv("REBAR_BARE_COMPILER_OUTPUT_DIR"); 56 | DepsDir -> 57 | DepsDir 58 | end. 59 | 60 | checkouts_out_dir() -> 61 | os:getenv("REBAR_CHECKOUTS_OUT_DIR"). 62 | 63 | gpb_exists_via_env(DirEnvValue) -> 64 | if DirEnvValue == false -> 65 | false; 66 | is_list(DirEnvValue) -> 67 | filelib:is_dir(filename:join(DirEnvValue, "gpb")) 68 | end. 69 | 70 | main(_) -> 71 | REBAR_CHECKOUTS_OUT_DIR = checkouts_out_dir(), 72 | REBAR_DEPS_DIR = deps_dir(), 73 | GpbExistsInCheckoutsOutDir = gpb_exists_via_env(REBAR_CHECKOUTS_OUT_DIR), 74 | GpbExistsInDepsDir = gpb_exists_via_env(REBAR_DEPS_DIR), 75 | 76 | {EbinPath, TestPath} = 77 | if GpbExistsInCheckoutsOutDir -> 78 | %% With _checkouts and rebar3 3.14 or later 79 | {filename:join([REBAR_CHECKOUTS_OUT_DIR, "gpb", "ebin"]), 80 | filename:join([REBAR_CHECKOUTS_OUT_DIR, "gpb", "test"])}; 81 | GpbExistsInDepsDir -> 82 | {filename:join([REBAR_DEPS_DIR, "gpb", "ebin"]), 83 | filename:join([REBAR_DEPS_DIR, "gpb", "test"])}; 84 | true -> 85 | %% rebar2 (or make) 86 | {"./ebin", "./test"} 87 | end, 88 | 89 | filelib:ensure_dir(filename:join(EbinPath, ".dummy")), 90 | 91 | GpbcOpts = [{i, "priv/proto3/google/protobuf"}, 92 | {o, "descr_src"}, {module_name_prefix, "gpb_"}, 93 | report], 94 | ErlcOpts = [{i, "descr_src"}, {i,"include"}, 95 | {outdir, EbinPath}, debug_info, 96 | report], 97 | 98 | code:add_patha(EbinPath), 99 | 100 | MakeScript = 101 | [{"descr_src/gpb_descriptor.erl", 102 | ["priv/proto3/google/protobuf/descriptor.proto"], 103 | gpb_compile_file_cmd("descriptor.proto", GpbcOpts)}, 104 | 105 | {filename:join(EbinPath, "gpb_descriptor.beam"), 106 | ["descr_src/gpb_descriptor.erl"], 107 | compile_file_cmd("descr_src/gpb_descriptor.erl", ErlcOpts)}, 108 | 109 | {filename:join(EbinPath, "gpb_compile_descr.beam"), 110 | ["descr_src/gpb_compile_descr.erl", 111 | "descr_src/gpb_descriptor.hrl"], 112 | compile_file_cmd("descr_src/gpb_compile_descr.erl", ErlcOpts)}, 113 | 114 | {filename:join(EbinPath, "gpb_parse_descr.beam"), 115 | ["descr_src/gpb_parse_descr.erl", 116 | "descr_src/gpb_descriptor.hrl"], 117 | compile_file_cmd("descr_src/gpb_parse_descr.erl", ErlcOpts)}], 118 | 119 | make(MakeScript), 120 | case filelib:is_dir(TestPath) of 121 | true -> 122 | %% eg: "rebar3 eunit" or "rebar2 eunit" 123 | %% but not "rebar3 compile" 124 | %% and not when compiling gpb as a dependency, since 125 | %% the test directory does not exist in the hex package. 126 | 127 | ErlcTestOpts = [{i, "descr_src"}, {i, "include"}, 128 | {outdir, TestPath}, debug_info], 129 | 130 | TestMakeScript = 131 | [{filename:join(TestPath, "gpb_compile_descr_tests.beam"), 132 | ["descr_src/gpb_compile_descr_tests.erl", 133 | "descr_src/gpb_compile_descr.erl", 134 | "descr_src/gpb_descriptor.hrl"], 135 | compile_file_cmd("descr_src/gpb_compile_descr_tests.erl", 136 | ErlcTestOpts)}, 137 | 138 | {filename:join(TestPath, "gpb_parse_descr_tests.beam"), 139 | ["descr_src/gpb_parse_descr_tests.erl", 140 | "descr_src/gpb_parse_descr.erl", 141 | "descr_src/gpb_descriptor.hrl"], 142 | compile_file_cmd("descr_src/gpb_parse_descr_tests.erl", 143 | ErlcTestOpts)}], 144 | make(TestMakeScript); 145 | _ -> 146 | next 147 | end. 148 | -------------------------------------------------------------------------------- /build/find-vsn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env escript 2 | %% -*- erlang -*- 3 | -include_lib("kernel/include/file.hrl"). 4 | -mode(compile). 5 | 6 | main(["--show-vsn"]) -> 7 | case find_vsn() of 8 | {ok, {Vsn, _Source}} -> 9 | io:put_chars([Vsn, "\n"]), 10 | do_exit(0); 11 | {error, _} -> 12 | print_no_vsn_error(), 13 | do_exit(1) 14 | end; 15 | main(["--show-vsn-source"]) -> 16 | case find_vsn() of 17 | {ok, {_Vsn, Source}} -> 18 | io:put_chars([atom_to_list(Source), "\n"]), 19 | do_exit(0); 20 | {error, _} -> 21 | print_no_vsn_error(), 22 | do_exit(1) 23 | end; 24 | main(["--have-vsn"]) -> 25 | case find_vsn() of 26 | {ok, {_Vsn, _Source}} -> 27 | io:put_chars("true\n"); 28 | {error, _} -> 29 | io:put_chars("false\n") 30 | end, 31 | do_exit(0); 32 | main(["--check-have-vsn"]) -> 33 | case find_vsn() of 34 | {ok, {_Vsn, _Source}} -> 35 | do_exit(0); 36 | {error, _} -> 37 | do_exit(1) 38 | end; 39 | main(_) -> 40 | io:format("usage: ~s --show-vsn | --show-vsn-source~n", 41 | [escript:script_name()]), 42 | do_exit(1). 43 | 44 | do_exit(ExitCode) -> 45 | halt(ExitCode). 46 | 47 | find_vsn() -> 48 | case find_vsn_from_file() of 49 | {ok, Vsn} -> 50 | {ok, {Vsn, file}}; 51 | {error, Reason1} -> 52 | case find_vsn_from_git() of 53 | {ok, Vsn} -> 54 | {ok, {Vsn, git}}; 55 | {error, Reason2} -> 56 | {error, {Reason1, Reason2}} 57 | end 58 | end. 59 | 60 | find_vsn_from_file() -> 61 | %% assume in top dir 62 | %% else move up until either .git or gpb.vsn?? 63 | %% though not across file systems? 64 | %% or until dir looks like top of gpb (eg src/gpb.erl exists) 65 | case file:get_cwd() of 66 | {ok, Cwd} -> 67 | try_walk_root_wise(Cwd, "gpb.vsn"); 68 | {error, Reason} -> 69 | {error, {no_cwd, Reason}} 70 | end. 71 | 72 | try_walk_root_wise(Dir, Base) -> 73 | case is_at_gpb_root(Dir) of 74 | true -> 75 | case file:read_file(filename:join(Dir, Base)) of 76 | {ok, Vsn} -> 77 | {ok, first_line_no_nl(binary_to_list(Vsn))}; 78 | {error, _} -> 79 | {error, no_file} 80 | end; 81 | false -> 82 | case up_dir(Dir) of 83 | {ok, Up} -> try_walk_root_wise(Up, Base); 84 | {error, Reason} -> {error, Reason} 85 | end 86 | end. 87 | 88 | is_at_gpb_root(Dir) -> 89 | lists:any( 90 | fun(F) -> F() end, 91 | [fun() -> filelib:is_dir(filename:join(Dir, ".git")) end, 92 | fun() -> filelib:is_regular(fjoin(Dir, ".git")) end, % a git worktree? 93 | fun() -> filelib:is_regular(fjoin(Dir, "gpb.vsn")) end, 94 | fun() -> filelib:is_regular(fjoin([Dir, "src", "gpb.erl"])) end]). 95 | 96 | fjoin(Dir, Name) -> filename:join(Dir, Name). 97 | fjoin(Comps) -> filename:join(Comps). 98 | 99 | up_dir(Dir) -> 100 | case filename:dirname(Dir) of 101 | Dir -> 102 | {error, at_file_system_root}; 103 | "." -> % windows 104 | {error, at_file_system_root}; 105 | Up -> 106 | %% Check if we move cross 107 | case {file:read_file_info(Dir), file:read_file_info(Up)} of 108 | {{ok, #file_info{major_device=SameDev}}, 109 | {ok, #file_info{major_device=SameDev}}} -> 110 | {ok, Up}; 111 | {{ok, _}, 112 | {ok, _}} -> 113 | {error, cross_device}; 114 | {_, {error, Reason}} -> 115 | {error, Reason}; 116 | {{error, Reason}, _} -> 117 | {error, Reason}; 118 | _ -> 119 | {error, undefined} 120 | end 121 | end. 122 | 123 | find_vsn_from_git() -> 124 | Cmd = case os:type() of 125 | {win32,_} -> 126 | "git describe --always --tags --match [0-9]*.[0-9]*"; 127 | _ -> 128 | "git describe --always --tags --match '[0-9]*.[0-9]*'" 129 | end, 130 | Output = os:cmd(Cmd), 131 | Line1 = first_line_no_nl(Output), 132 | case looks_like_vsn_output(Line1) of 133 | true -> 134 | {ok, Line1}; 135 | false -> 136 | {error, {Cmd, Output}} 137 | end. 138 | 139 | -define(is_digit(C), ($0 =< C andalso C =< $9)). 140 | 141 | looks_like_vsn_output([C1 | _]=Str) when ?is_digit(C1) -> 142 | %% Examples of valid outputs: 143 | %% "4.17.3" 144 | %% "4.17.3-1-g0bfce0e" 145 | is_vsn_str_1(Str); 146 | looks_like_vsn_output(_) -> 147 | false. 148 | 149 | 150 | is_vsn_str_1([C | Rest]) when ?is_digit(C) -> is_vsn_str_1(Rest); 151 | is_vsn_str_1("." ++ Rest) -> is_vsn_str_2(Rest); 152 | is_vsn_str_1(_) -> false. 153 | 154 | is_vsn_str_2([C | Rest]) when ?is_digit(C) -> is_vsn_str_2(Rest); 155 | is_vsn_str_2("." ++ Rest) -> is_vsn_str_3(Rest); 156 | is_vsn_str_2(_) -> false. 157 | 158 | 159 | is_vsn_str_3([C | Rest]) when ?is_digit(C) -> is_vsn_str_3(Rest); 160 | is_vsn_str_3("-" ++ _) -> true; 161 | is_vsn_str_3("") -> true; 162 | is_vsn_str_3(_) -> false. 163 | 164 | first_line_no_nl("\r" ++ _) -> ""; 165 | first_line_no_nl("\n" ++ _) -> ""; 166 | first_line_no_nl([C | Tl]) -> [C | first_line_no_nl(Tl)]; 167 | first_line_no_nl("") -> "". 168 | 169 | print_no_vsn_error() -> 170 | io:put_chars(["No version information found: no gpb.vsn file " 171 | "and not in a git repo.\n"]). 172 | -------------------------------------------------------------------------------- /build/mk_version_hrl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env escript 2 | %% -*- erlang -*- 3 | 4 | -mode(compile). 5 | main(Argv) -> 6 | {Opts, Args} = parse_opts(Argv, [], []), 7 | [InFile, OutFile] = if length(Args) == 2 -> Args; 8 | true -> usage(), halt(1) 9 | end, 10 | {Vsn, VsnSource} = 11 | case proplists:get_value(override_version, Opts) of 12 | undefined -> 13 | find_vsn_and_source(); 14 | Version -> 15 | {Version, overriding_option} 16 | end, 17 | BaseStr = case file:read_file(InFile) of 18 | {ok, S} -> 19 | S; 20 | {error, Reason} -> 21 | file_err(read_file, InFile, Reason) 22 | end, 23 | SedList = 24 | [ 25 | {<<"@vsn@">>, Vsn}, 26 | {<<"@vsn-source@">>, VsnSource}, 27 | {<<"is expected to be">>, <<"was">>}, 28 | {<<"%% The version below">>, 29 | [<<"%% DO NOT EDIT -- generated from gpb_version.hrl.in\n">>, 30 | <<"%% The version below">>]}, 31 | {<<"%% NB: The build.mk_version_hrl depends.*">>, <<"">>} 32 | ], 33 | Content = 34 | iolist_to_binary( 35 | lists:foldl( 36 | fun({Patten, Replacement}, Acc) -> 37 | re:replace(Acc, Patten, Replacement, [{return, binary}]) 38 | end, BaseStr, SedList)), 39 | case file:read_file(OutFile) of 40 | {ok, Content} -> 41 | %% Don't overwrite the file with identical data. 42 | %% This can cause build systems to rebuild unnecessarily. 43 | ok; 44 | _ -> 45 | case file:write_file(OutFile, Content) of 46 | ok -> 47 | ok; 48 | {error, Reason2} -> 49 | file_err(write_file, OutFile, Reason2) 50 | end 51 | end. 52 | 53 | parse_opts(["--override-version="++Vsn | Rest], Opts, Args) -> 54 | parse_opts(Rest, [{override_version, Vsn} | Opts], Args); 55 | parse_opts([Arg | Rest], Opts, Args) -> 56 | parse_opts(Rest, Opts, [Arg | Args]); 57 | parse_opts([], Opts, Args) -> 58 | {lists:reverse(Opts), lists:reverse(Args)}. 59 | 60 | usage() -> 61 | io:format("mk_version_hrl [Opts] InFile OutFile~n" 62 | "Opts: --override-version=VSN~n"). 63 | 64 | -define(NO_VERSION_ERR_MSG, 65 | "ERROR: To build outside a git work tree, you must explicitly 66 | set the version, either by writing it to a file gpb.vsn, 67 | or by creating a versioned archive, and then unpack and 68 | build that. 69 | 70 | If you want to create a versioned archive, then 71 | use helpers/mk-versioned-archive. 72 | 73 | The helpers/mk-versioned-archive can be used from a git worktree 74 | or from eg Github's automatically generated tar/zip files 75 | or similar. If you use it from a (non-shallow) git work tree 76 | with tags intact, the version will get picked up automatically, 77 | otherwise you must know the proper version and specify it manually, 78 | see mk-versioned-archive --help for further assistance. 79 | 80 | For further info, see the README.md, the section section 81 | named Building outside of a git work tree."). 82 | 83 | 84 | find_vsn_and_source() -> 85 | FindVsnCmd = "escript ./build/find-vsn", 86 | case os:cmd(FindVsnCmd ++ " --have-vsn") of 87 | "true" ++ _ -> 88 | Vsn = first_line_no_nl( 89 | os:cmd(FindVsnCmd ++ " --show-vsn")), 90 | VsnSource = first_line_no_nl( 91 | os:cmd(FindVsnCmd ++ " --show-vsn-source")), 92 | {Vsn, VsnSource}; 93 | "false" ++ _ -> 94 | io:format(standard_error, "~s~n", [?NO_VERSION_ERR_MSG]), 95 | halt(1) 96 | end. 97 | 98 | first_line_no_nl("\r" ++ _) -> ""; 99 | first_line_no_nl("\n" ++ _) -> ""; 100 | first_line_no_nl([C | Tl]) -> [C | first_line_no_nl(Tl)]; 101 | first_line_no_nl("") -> "". 102 | 103 | file_err(FunName, FileName, Reason) -> 104 | io:format(standard_error, "file:~p(~s) execute failed!, Reason :~s ~n", 105 | [FunName, FileName, file:format_error(Reason)]), 106 | halt(1). 107 | 108 | -------------------------------------------------------------------------------- /doc/dev-guide/decoding.md: -------------------------------------------------------------------------------- 1 | Short guide to the design of decoding 2 | ------------------------------------- 3 | 4 | The generated code centers much around decoding of 5 | [varints](https://protobuf.dev/programming-guides/encoding/#varints) 6 | ie variable length integers. The basic loop construct looks like: 7 | 8 | ``` 9 | decode_varint(<<1:1, X:7, Rest/binary>>, N, Acc, Msg) -> 10 | decode_varint(Rest, N+7, X bsl N + Acc, Msg); 11 | decode_varint(<<0:1, X:7, Rest/binary>>, N, Acc, Msg) -> 12 | Varint = X bsl N + Acc, 13 | ...body... 14 | 15 | ``` 16 | 17 | The `...body...` generally adds an updated field to the `Msg` tuple or 18 | map, and then continues to unpack more fields. 19 | 20 | Some varints are known in advance, at code-generation time, and the 21 | generated code has fast-path function clauses for these. But a varint 22 | can also be encoded in a non-minimal way, so there is also an general 23 | varint decoder (this fast-path approach gave some performance 24 | improvement): 25 | 26 | ``` 27 | 28 | %% fast path 29 | dfp(<<10, Rest/binary>>, Msg) -> decode_field_f1(Rest, Msg); 30 | dfp(<<18, Rest/binary>>, Msg) -> decode_field_f2(Rest, Msg); 31 | ... 32 | dfp(<<>>, Msg) -> Msg; 33 | dfp(Other, Msg) -> dg(Other, Msg). 34 | 35 | %% general case 36 | dg(<<1:1, X:7, Rest/binary>>, N, Acc, Msg) -> 37 | dg(Rest, N+7, X bsl N + Acc, Msg); 38 | dg(<<0:1, X:7, Rest/binary>>, N, Acc, Msg) -> 39 | Varint = X bsl N + Acc, 40 | case Varint of 41 | 10 -> decode_field_f1(Rest, Msg); 42 | 18 -> decode_field_f2(Rest, Msg); 43 | ... 44 | end; 45 | dg(<<>>, _N, _Acc, Msg) -> 46 | Msg. 47 | ``` 48 | 49 | Another trick I've employed is that if decoding a message means making 50 | no or few calls to other functions, then I can have all fields as 51 | parameters to the decoder function instead (ie largely untouched in y 52 | registers), and pack the `Msg` (to a record or map) only last, when all 53 | fields have been processed. So the generated functions often have many 54 | arguments, one for each message field. An estimate is made initially, to 55 | determine, per message, whether it is more advantageous to pass fields 56 | as a record/map or as parameters. There is also a limitation in number 57 | of parameters for a function. This approach also meant some performance 58 | gain. When passing fields as parameters, the generated code looks 59 | roughly like: 60 | 61 | ``` 62 | dfp(<<10, Rest/binary>>, F1, F2, ...) -> decode_field_f1(Rest, F1, F2, ...); 63 | dfp(<<18, Rest/binary>>, F1, F2, ...) -> decode_field_f2(Rest, F1, F2, ...); 64 | ... 65 | dfp(<<>>, F1, F2, ...) -> #msg{f1 = F1, f2 = F2, ...}; 66 | dfp(Other, F1, F2, ...) -> dg(Other, F1, F2, ...). 67 | 68 | dg(...) -> 69 | ...similarly.. 70 | 71 | %% let's say the type of field f1 is fixed32 72 | decode_field_f1(<>, _, F2, ...) -> 73 | dfp(Rest, X, F2, ...). 74 | ``` 75 | 76 | The decision whether to pass around a message as a tuple or map, or to 77 | pass the fields as parameters, is taken (per message) in 78 | gpb_analyzer:compute_decode_field_pass_methods/2, and is influenced by 79 | number of fields as well as an estimate on how many function calls needs 80 | to be made. Function calls implies saving parameters to the stack and 81 | restoring from the stack after the function call. 82 | 83 | Code morphing 84 | ------------- 85 | 86 | There are many dimensions: 87 | - field pass method (as record or map fields, or as parameters) 88 | - generate for maps or records 89 | - for maps: generate with unset optionals omitted (default) or 90 | with the value `undefined` (mostly due to historical reasons/mistakes) 91 | - for maps: oneof are tuples or separate keys (flat) 92 | - all the different protobuf field types 93 | - whether each field is repeated, optional or required 94 | 95 | The code generator needs to lay out different code for each of these 96 | cases, but it leads to a quite large combinatorial explosion. 97 | To reduce that explosion somewhat, the generation of the decoding code is 98 | separated into two steps: 99 | 100 | First, generate code for decoding to records, take care of 101 | - always field pass method = pass as record 102 | - all the different protobuf field types 103 | - whether each field is repeated, optional or required 104 | 105 | Second, possibly transform (morph) the generated code, taking these 106 | aspects into consideration: 107 | - field pass method (as record or map fields, or as parameters) 108 | - generate for maps or records 109 | - for maps: generate with unset optionals omitted (default) or 110 | with the value `undefined` (mostly due to historical reasons/mistakes) 111 | - for maps: oneof are tuples or separate keys (flat) 112 | 113 | This second step is done by the `gpb_codemorpher.erl`, which is called 114 | from the gpb_gen_decoders. 115 | -------------------------------------------------------------------------------- /doc/dev-guide/encoding.md: -------------------------------------------------------------------------------- 1 | Short guide to the design of encoding 2 | ------------------------------------- 3 | 4 | The encoding relies heavily on the fact that binaries are 5 | write-appendable as long as possible. (fixme: more clearly define what 6 | this means). 7 | 8 | Each encoding function adds some bytes to the end of the binary. 9 | 10 | An alternative approach could have been to generate iolists, and call 11 | iolist_to_binary at the top level, but it didn't save much over the 12 | write-append approach, when I tried. 13 | -------------------------------------------------------------------------------- /doc/dev-guide/intro.md: -------------------------------------------------------------------------------- 1 | 2 | Encoder/decoder in gpb 3 | ---------------------- 4 | 5 | The gpb module implements a protobuf encoder and decoder without any 6 | bells or whistles. It only supports records, not maps, and no 7 | options. It does not generate any code. It encodes or decodes according 8 | to the proto definitions passed as input. The main purose of it 9 | is to serve another implementation that can be used to cross-check 10 | the encoder and decoder generated from gpb_compile. 11 | Originally, this was the only encoder and decoder in gpb. 12 | 13 | Generated encoder/decoder 14 | ------------------------- 15 | 16 | The gpb_compile can generate code from either a file, a string or 17 | proto definitions. Output is normally an erl file, but it is also 18 | possible to let it return just the proto definitions after parsing 19 | and name resolutions have taken place. 20 | 21 | The generated code can either contain an encoder and decoder in 22 | Erlang, but it is also possible to use the the C++ encoder/decoder 23 | as a NIF. The NIF binding can be useful for interop tests of 24 | encoding and decoding with the reference implementation. 25 | 26 | 27 | Quickcheck suite in a repo 28 | -------------------------- 29 | 30 | The gpb-eqc contains a quickcheck suite for testing encoding and decoding. 31 | Using maps:to_list and maps:from_list, it can test maps as well as records. 32 | -------------------------------------------------------------------------------- /doc/dev-guide/json.md: -------------------------------------------------------------------------------- 1 | JSON formats: 2 | --------------------- 3 | - jsx 4 | objects: proplist() | [{}] % non-empty, empty object respectively 5 | | map() % optionally 6 | keys: binary() 7 | | atom() % on encoding or optionally on decoding 8 | | integer() 9 | arrays: list() 10 | strings: binary() 11 | | atom() % on encoding (only?) 12 | null: null 13 | - mochijson2 14 | https://github.com/bjnortier/mochijson2/blob/master/src/mochijson2.erl 15 | objects: {struct, proplist()} 16 | keys: binary() 17 | | atom() % on encoding 18 | arrays: list() 19 | strings: binary() 20 | | atom() % on encoding 21 | | {json, iolist()} 22 | null: null 23 | - jiffy 24 | https://github.com/davisp/jiffy 25 | objects: {proplist()} 26 | | map() % optionally 27 | keys: binary() 28 | | atom() % on encoding 29 | arrays: list() 30 | strings: binary() 31 | | atom() % on encoding 32 | null: null 33 | | nil % optionally on encoding 34 | - eep0018 35 | https://github.com/erlang/eep/blob/master/eeps/eep-0018.md 36 | objects: proplist() | [{}] % non-empty, empty object respectively 37 | keys: binary() | atom() % binary() is default, atom() optionally 38 | arrays: list() 39 | strings: binary() 40 | null: null 41 | - mochijson 42 | https://github.com/basho/mochiweb/blob/master/src/mochijson.erl 43 | objects: {struct, proplist()} 44 | keys: binary() | atom() | string() 45 | arrays: {array, list()} 46 | strings: binary() | atom() | string() 47 | null: null 48 | - jsonx 49 | https://github.com/iskra/jsonx 50 | objects: {proplist()} 51 | | proplist() % runtime option 52 | | {struct,proplist()} % runtime option 53 | | #rec{...} % runtime option 54 | keys: binary() 55 | arrays: list() 56 | strings: binary() 57 | | {json, iolist()} % on encoding 58 | null: null 59 | - erlang-json-eep-parser 60 | https://github.com/jchris/erlang-json-eep-parser/tree/master 61 | objects: {proplist()} 62 | keys: binary() 63 | arrays: list() 64 | strings: binary() 65 | null: ?? 66 | - yaws json2 67 | https://github.com/klacke/yaws/blob/0244e95/src/json2.erl 68 | objects: {struct, proplist()} 69 | keys: string() 70 | arrays: {array, [ElementList]} 71 | string: [0..65000] 72 | null: null 73 | | undefined % on encoding 74 | - jsone 75 | https://github.com/sile/jsone 76 | objects: {proplist()} 77 | | proplist() | [{}] % optionally 78 | | map() % optionally 79 | keys: binary() 80 | | atom() % on encoding 81 | arrays: list() 82 | strings: binary() 83 | | atom() % on encoding 84 | | {json, iolist()} % on encoding 85 | | {json_utf8, Chars} % on encoding 86 | null: null 87 | | undefined % on encoding 88 | Things to additionally conisder: 89 | - poison (elixir) 90 | https://github.com/devinus/poison 91 | - jazz (elixir) 92 | https://github.com/meh/jazz 93 | - jason (elixir) 94 | https://github.com/michalmuskala/jason 95 | - json (elixir) 96 | https://github.com/cblage/elixir-json 97 | - exjson (elixir) 98 | https://github.com/guedes/exjson 99 | - jsex (elixir) 100 | objects: map() 101 | arrays: list() | Enumerable 102 | null: nil 103 | - tiny (elixir) 104 | https://github.com/whitfin/tiny 105 | objects: map() 106 | keys: binary() 107 | | atom() % on encoding 108 | - erlson (elixir) 109 | https://github.com/alavrik/erlson 110 | objects: erlson dictionary 111 | keys: atom() 112 | strings: binary() 113 | arrays: list() 114 | null: undefined 115 | 116 | GPB options to support (most of) the above (hopefully) 117 | -------------------------------------------------------- 118 | {json_object_format, eep18 | {proplist} | {atom(), proplist} | map} 119 | {json_key_format, atom | binary | string} 120 | {json_array_format, list | {atom(), list}} 121 | {json_string_format, binary | list} 122 | {json_null, atom()} 123 | -------------------------------------------------------------------------------- /doc/dev-guide/proto-defs-versions.md: -------------------------------------------------------------------------------- 1 | Version marker 2 | -------------- 3 | 4 | The format is currently a list of tuples, most are 2-tuples. 5 | 6 | The version is indicated with a `{proto_defs_version, integer()}` item, 7 | preferably first in list. 8 | 9 | If there is no `proto_defs_version`, then it is implicitly version 1. 10 | 11 | Version numbering 12 | ----------------- 13 | 14 | Version numbers are integers, and a new version indicate a 15 | non-backwards-compatible change. 16 | 17 | Even when the version number has not changed, there may still 18 | be differences, but only backwards compatible changes. 19 | 20 | A non-backwards-compatible change is generally a change to an 21 | existing tuple definition item, such as: 22 | 23 | * A change of the interpretation of some value 24 | * A change to the size of a tuple 25 | * Reordering of lists where the order matters, such as 26 | the list of fields in message, or the list of enumerators 27 | in an enum (tooling and users expects same order as in 28 | the proto) 29 | 30 | A change of the entire format, such as from a list of tuples to a 31 | map, would of course be a non-backwards-compatible as well. 32 | 33 | A backwards-compatible change is for example 34 | 35 | * Addition of a new kind of tuple, ie elements with types 36 | different from any other list items, such as tuples with 37 | new first-element keys. 38 | * Reordering of a tuples 39 | * Reordering of inner lists, where the ordering is not 40 | significant, such as elements in a `msg_containment` 41 | tuple. 42 | 43 | Format versions obey the Erlang term order and be compared like 44 | normal Erlang terms with for instance `=<`. 45 | 46 | Conversion between versions 47 | --------------------------- 48 | 49 | Internally, gpb operates on the latest version. 50 | 51 | On input, for example the `gpb_compile:proto_defs/2,3`, definitions are 52 | converted to the latest, if needed. 53 | 54 | On output, for example the `to_proto_defs` option to `gpb_compile:file` or 55 | `gpb_compile:string`, definitions are converted if needed, as indicated 56 | by any `proto_defs_version` option. Another form of output are the 57 | generated introspection functions, the format of which can be 58 | controlled with the `introspect_proto_defs_version` option. 59 | 60 | In gpb-4.x.y, the default `proto_defs_version` is 1, and the default 61 | and the default `introspect_proto_defs_version` is 1 if possible, else 2. 62 | 63 | To opt in to a later version, use `proto_defs_version` option like this: 64 | ``` 65 | gpb_compile:file(..., [to_proto_defs, 66 | {proto_defs_version, }, 67 | ...) 68 | ``` 69 | 70 | There are also functions in `gpb_defs.erl` for converting to and from 71 | the latest version, see the `gpb_defs:convert_defs_to_latest_version/1` 72 | and the `gpb_defs:convert_defs_from_latest_version/2` functions. 73 | 74 | In general, converting from a previous version to the latest is 75 | expected to always succeed, but converting from the latest to a 76 | previous version may fail. 77 | 78 | In a future gpb-5.0.0, the intention is that the default version 79 | will change to 2. 80 | 81 | Specifying versions from other programs 82 | --------------------------------------- 83 | 84 | If you write programs that operate on the proto definitions, then the 85 | recommendation is to specify the targeted version explicitly. 86 | In particular, _do not_ specify it using something like 87 | `lists:max(gpb_defs:supported_defs_versions())`, because then if gpb would 88 | introduce a new version, your program would receive unexpected proto 89 | definitions, which could cause it to break. 90 | 91 | Version 1 92 | --------- 93 | 94 | This is the initial version. 95 | 96 | Version 2 97 | --------- 98 | 99 | In this version, the following has changed: 100 | 101 | For proto files with `syntax="proto3"`, the `occurrence` of fields has 102 | changed from `optional` to `defaulty`. 103 | 104 | In Google's protobuf 3.12.0, as of this writing, experimental support for 105 | `optional` was added also to proto3 messages, see [the field_presence.md document](https://github.com/protocolbuffers/protobuf/blob/v3.12.0/docs/field_presence.md) 106 | for more info. When this is used, `occurrence=optional` is used 107 | to indicate it. 108 | 109 | Example: Given the following proto file: 110 | ``` 111 | syntax="proto3"; 112 | message Msg1 { 113 | uint32 f1 = 1; 114 | } 115 | message Msg2 { 116 | optional uint32 g1 = 1; 117 | } 118 | ``` 119 | the definitions in version 2 is now: 120 | ``` 121 | [{proto_defs_version, 2}, 122 | ... 123 | {proto3_msgs, ['Msg1', 'Msg2']}, 124 | ... 125 | {{msg,'Msg1'}, [#?gpb_field{name=f1, ..., occurrence=defaulty, ...}]}, 126 | %% ^^^^^^^^ 127 | %% in version 1, the occurrence would have been: optional 128 | ... 129 | {{msg,'Msg2'}, [#?gpb_field{name=g1, ..., occurrence=optional, ...}]}, 130 | %% ^^^^^^^^ 131 | %% in version 2, this indicates proto2-style field presence handling. 132 | ...] 133 | ``` 134 | 135 | It is possible to convert from version 2 to version 1 only if there 136 | are no proto3 message with a field with `occurrence=optional`. 137 | 138 | ### Impact 139 | 140 | First some background: With `syntax="proto3"`, when encoding a 141 | field, if it has the type's default value, it must not be serialized, 142 | and on decoding, it must be set to the type's default value if it is 143 | not present in the binary to decode. With `syntax="proto2"` if the 144 | field is set, it is included in the serialized binary regardless of 145 | value. On decoding, if it is not present in the binary to decode, it 146 | is always considered to not be set. 147 | 148 | In version 1, when processing a `#?gpb_field{}` with 149 | `occurrence=optional`, to invoke the correct handling as described 150 | above, it was also necessary to also check whether the message 151 | was a proto3 message or not (using the `proto3_msgs` item.) 152 | In version 2, `occurrence=defaulty` indicates proto3 handling 153 | and `occurrence=optional` indicates proto2 handling, there is no longer 154 | any need to also check whether a message is proto3 or not. 155 | 156 | 157 | Version 3 158 | --------- 159 | 160 | In version 3, options and enums have changed. 161 | 162 | Enumerators in version 2 were `{Sym,Value}` but in version 3, they are: 163 | 164 | ``` 165 | {Symbol::atom(), Value::integer(), Options::list()} 166 | ``` 167 | 168 | Also, enumeration options are moved out to a separate 169 | `{{enum_options, EnumName}, Options}` entry, like how it is for `msg_options`. 170 | 171 | Example: Given the following proto file: 172 | ``` 173 | enum E1 { 174 | option (my_option) = true; 175 | A = 0 [(my_enumerator_option) = true]; 176 | } 177 | ``` 178 | 179 | the definitions in version 3 vs 2 look like: 180 | ``` 181 | [{proto_defs_version, 3}, 182 | ... 183 | {{enum,'E1'}, [{'A', 0, [{[my_enumerator_option], true}]}]}] 184 | {{enum_options, 'E1'}, [{[my_option], true}]} 185 | ...] 186 | 187 | vs 188 | 189 | [{proto_defs_version, 2}, 190 | ... 191 | %% In version 2, the my_enumerator_option is not included 192 | {{enum,'E1'}, [{option, [my_option], true}, 193 | {a, 0}]} 194 | ...] 195 | ``` 196 | 197 | Version 4 198 | --------- 199 | 200 | In version 4, the representation of custom options has changed. 201 | 202 | This concerns options and custom options on file-level, in messages and 203 | fields, in, enumerations and enum values and in services. Options for 204 | rpc methods are a bit of a different story though: they now look like 205 | options in any other positions, which was not the case previously. 206 | 207 | Still in version 4, custom option names are not resolved, but instead 208 | preserved as they occor in the .proto file, though on erlang format. 209 | 210 | The table below summarizes the option format versions. 211 | 212 | | In the `.proto` | format ≥ 4 | format ≤ 3 | rpc opts ≤ 3 | 213 | | --------------- | ---------------- | ----------------- | --------------- | 214 | | `opt_name` | `opt_name` | `opt_name` | `opt_name` | 215 | | `(custom_opt)` | `[{custom_opt}]` | `[custom_opt]` | `custom_opt` | 216 | | `(pkg.opt)` | `[{pkg,opt}]` | `[pkg,'.',opt]` | `'pkg...opt'` | 217 | | `(pkg.opt).f` | `[{pkg,opt},f]` | `[pkg,'.',opt,f]` | `'pkg...opt.f'` | 218 | | `(opt).f.g` | `[{opt},f,g]` | `[opt,f,g]` | `'opt.f.g'` | 219 | | `(p).(f).g` | `[{p},{f},g]` | `[p,f,g]` | `'p.f.g'` | 220 | | `(.p).g` | `[{'.',p},g]` | `['.',p,'.',f,g]` | `'..p...f.g'` | 221 | 222 | Below is an example of proto definitions to indicate where 223 | these option names have changed format. This example does not 224 | show all places where (custom) options can occur, but highlights 225 | where the options in the table above occur. 226 | 227 | ``` 228 | .proto: 229 | 230 | enum E1 { 231 | allow_alias = true; 232 | (my_custom_option) = 1; 233 | (other_custom_opt).x = "abc"; 234 | A = 0 [(a_opt) = 1]; 235 | } 236 | message M1 { 237 | option (b_opt) = true; 238 | required uint32 f = 1 [packed, deprecated=false, (c_opt).d=2]; 239 | } 240 | service S1 { 241 | rpc Cc (M1) returns (M1) { 242 | option (m_opt) = 1; 243 | } 244 | } 245 | 246 | Defs: 247 | 248 | [{proto_defs_version, 4}, 249 | ... 250 | {{enum, 'E1'}, [{'A', 0, [{[{a_opt}], 1}]} 251 | ]}, 252 | {{enum_options,'E1'}, [{allow_alias,true}, 253 | {[{my_custom_option}], 1}, 254 | {[{other_custom_option},x], "abc"}]}, 255 | ... 256 | {{msg, 'M1'}, [#?gpb_field{name=f, opts=[{packed,true}, 257 | {deprecated,false}, 258 | {[{c_opt},d], 2}]}]}, 259 | {{msg_options,'M1'}, [{[{b_opt}], true}}]}, 260 | ... 261 | {{service,'S1'}, [#?gpb_rpc{opts=[{[{m_opt}], 1}]}]} 262 | %% ^^^^^^^^^ 263 | %% rpc opts in the table above 264 | ...] 265 | ``` 266 | -------------------------------------------------------------------------------- /doc/dev-guide/translations.md: -------------------------------------------------------------------------------- 1 | Short guide to the translations 2 | ------------------------------- 3 | 4 | For each translation there are a function calls on the following format: 5 | 6 | - `tr_encode_Msg.field(Value, UserData)` 7 | - `tr_decode_Msg.field(Value, UserData)` 8 | - `tr_merge_Msg.field(Value1, Value2, UserData)` 9 | 10 | and so on. 11 | 12 | If no translation is needed, the body if such a `tr_...` function 13 | is just `id(Value)`. 14 | 15 | To get some speed (avoiding function calls, see the reasoning decoding.md), 16 | each such `tr_...` call is marked `-compile({inline,Fn/Arity})`, 17 | so it is inlined at the call site, often causing minimal extra cost, 18 | especially for `id` translations. 19 | 20 | This means it is possible to make the generation of translations into a 21 | separate step, it is not necessary to mix this into all the other 22 | intricacies of encoding, decoding, merging and so on. Those need only 23 | generate the call, and the actual translation, possible stacking of 24 | multiple translations, and argument templating can be done separately. 25 | 26 | The generation of (inline-marked) translation functions needs to handle 27 | - possible underscoring of unused parameters, 28 | to avoid warnings about unused variables 29 | - argument templating 30 | - stacking of translations 31 | 32 | The templating is illustrated like this: if an option 33 | to `gpb_compile:file/2` is 34 | ``` 35 | {translate_field, 36 | {['MsgName',field_name], 37 | [{encode, {mod, e_fn, ['$1']}}, 38 | {decode, {mod, d_fn, ['$user_data', '$1', a, b, c]}}]}} 39 | ``` 40 | then the generated translation functions would look roughly like: 41 | ``` 42 | tr_encode_MsgName.field_name(Value, _UserData) -> % nb: undercore! 43 | mod:e_fn(Value). 44 | 45 | tr_decode_MsgName.field_name(Value, UserData) -> '$1' refers to 1st param 46 | mod:d_fn(UserData, Value, a, b, c). % template use 47 | ``` 48 | 49 | The idea to be able to have translations stackable works like this: if 50 | there are 2 encode-translations, A and B in that order for some field, 51 | then the `tr_encode_` function would look like: 52 | ``` 53 | tr_encode_MsgName.field_name(Value, _UserData) -> 54 | mod_b:e_fn_b( 55 | mod_a:e_fn_a(Value)). 56 | ``` 57 | 58 | Map type fields 59 | --------------- 60 | 61 | Internally within gpb, the translation mechanism is also (re-)used for 62 | `map<_,_>` type fields. A field in a message `M` 63 | ``` 64 | message M { 65 | ... 66 | map f = 17; 67 | ... 68 | } 69 | ``` 70 | is translated internally like this: 71 | ``` 72 | message M { 73 | ... 74 | repeated SomeDynamicallyGeneratedName f = 17; 75 | ... 76 | } 77 | 78 | message SomeDynamicallyGeneratedName { 79 | optional KeyType key = 1; 80 | optional ValueType value = 2; 81 | } 82 | ``` 83 | 84 | In fact, I had had the translation idea in my head for a long time, but 85 | when protobuf 3.0.0 arrived with the `map<_,_>` type fields and 86 | `google.protobuf.Any` wellknown fields, I decided to implement those as 87 | translations. Only later on, I opened up for translations to be applied 88 | to all kinds of fields, and also to be stackable. 89 | 90 | Specifying translators for fields and by type 91 | --------------------------------------------- 92 | 93 | It is possible to specify translators to be applied to individual 94 | fields, or for all fields of a certain type. 95 | 96 | The "all fields of a certain type" gets expanded/converted by 97 | `gpb_analyzer` into translation options by for the individual fields, by 98 | running a separate pass to see which message fields are of that 99 | specified type. 100 | -------------------------------------------------------------------------------- /helpers/export-from-git: -------------------------------------------------------------------------------- 1 | mk-versioned-archive -------------------------------------------------------------------------------- /helpers/extract-top-changelog-entry: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | cdup=$(git rev-parse --show-toplevel) && 4 | cd "$cdup" || { 5 | echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree" 6 | exit 1 7 | } 8 | 9 | cat ChangeLog | \ 10 | awk '/Version.*[0-9]+/ { 11 | do { 12 | if ($0 ~ / {8,}+/) 13 | { 14 | print substr($0, 9); 15 | } 16 | else 17 | { 18 | print $0; 19 | } 20 | getline; 21 | } while ($0 !~ /Version.*[0-9.]+/) 22 | exit; 23 | }' 24 | -------------------------------------------------------------------------------- /helpers/git-hooks/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # An example hook script to verify what is about to be pushed. Called by "git 4 | # push" after it has checked the remote status, but before anything has been 5 | # pushed. If this script exits with a non-zero status nothing will be pushed. 6 | # 7 | # This hook is called with the following parameters: 8 | # 9 | # $1 -- Name of the remote to which the push is being done 10 | # $2 -- URL to which the push is being done 11 | # 12 | # If pushing without using a named remote those arguments will be equal. 13 | # 14 | # Information about the commits which are being pushed is supplied as lines to 15 | # the standard input in the form: 16 | # 17 | # 18 | # 19 | 20 | remote="$1" 21 | url="$2" 22 | 23 | z40=0000000000000000000000000000000000000000 24 | 25 | IFS=' ' 26 | while read local_ref local_sha remote_ref remote_sha 27 | do 28 | case "$local_ref"::"$url" in 29 | refs/heads/master::*github.com*) 30 | # Example: url = git@github.com:SOME-GITHUB-USER/gpb.git 31 | d=`git describe --always --tags --match '[0-9]*.[0-9]*' $local_sha` 32 | if ! (echo "$d" | egrep '^[0-9]+(\.[0-9]+)*$' >/dev/null) 33 | then 34 | echo "ERROR: attempt to push non-n.m...-tagged version" 35 | echo " on master ($local_ref)" 36 | echo " to github: $d" 37 | exit 1 38 | fi 39 | ;; 40 | esac 41 | done 42 | 43 | exit 0 44 | -------------------------------------------------------------------------------- /helpers/import-protobuf-protos: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | usage () { 4 | cat < 6 | Example: $(basename "$0") /usr/local/src/protobuf 7 | 8 | Import .proto files from a local clone of the protobuf git repo 9 | to this gpb repo 10 | EOF 11 | } 12 | 13 | local_protobuf_repo="$1" 14 | if [ -z "$local_protobuf_repo" ] 15 | then 16 | usage 17 | exit 1 18 | fi 19 | 20 | if [ ! -d "$local_protobuf_repo" ] 21 | then 22 | echo "$local_protobuf_repo does not seem to be a directory" 23 | exit 1 24 | fi 25 | 26 | set -e 27 | 28 | echo "Ensureing we are at the top of the gpb repo..." 29 | repotop="$(git rev-parse --show-toplevel)" 30 | cd "$repotop" 31 | echo 32 | 33 | protobuf_shortsha=$(cd "$local_protobuf_repo" && git log -1 --format="%h") 34 | if [ -f "$local_protobuf_repo"/CMakeLists.txt ] 35 | then 36 | protobuf_version=$(grep set.protobuf_VERSION_STRING \ 37 | "$local_protobuf_repo"/CMakeLists.txt | \ 38 | cut -d'"' -f2) 39 | elif [ -f "$local_protobuf_repo"/CHANGES.txt ] 40 | then 41 | protobuf_version=$(cat "$local_protobuf_repo"/CHANGES.txt | \ 42 | awk '/.* version .*/ { \ 43 | for (i=1;i "$dest" <> "$dest" 70 | } 71 | 72 | 73 | destdir=priv/proto3/google/protobuf 74 | if [ -d "$destdir" ] 75 | then 76 | for f in $(ls "$local_protobuf_repo"/src/google/protobuf/*.proto | \ 77 | egrep -v '(unittest|_test)') 78 | do 79 | # can not rename due to import statements in the imported files. 80 | echo "$f" 81 | import_proto "$f" "$destdir/$(basename "$f")" 82 | done 83 | else 84 | echo "Warning: No directory $destdir, so not importing." 85 | fi 86 | -------------------------------------------------------------------------------- /helpers/install-git-hooks: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | scriptdir=`dirname "$0"` 4 | 5 | force=false 6 | 7 | while getopts "f" opt 8 | do 9 | case "$opt" in 10 | f) force=true;; 11 | esac 12 | done 13 | shift $(($OPTIND - 1)) 14 | 15 | cd "$scriptdir" 16 | src_dir="$scriptdir/git-hooks" 17 | 18 | git_dir=`git rev-parse --git-dir` 19 | dest_dir="$git_dir/hooks" 20 | if ! [ -d "$dest_dir" ] 21 | then 22 | echo "Error: no git hooks dir?!" >&2 23 | exit 1 24 | fi 25 | 26 | if [ -x "$dest_dir"/pre-push -a $force = false ] 27 | then 28 | if ( cmp "$dest_dir"/pre-push "$src_dir"/pre-push >/dev/null ) 29 | then 30 | echo "Identical pre-push git hook already installed." 31 | echo "Run with -f if you want to force an installation." 32 | exit 0 33 | else 34 | echo "ERROR: Executable pre-push git hook already exists!" >&2 35 | echo "Not overwriting. Aborting." >&2 36 | echo >&2 37 | echo "If you want to install the git hook manually, then" >&2 38 | echo "either run this script with the -f option, or run" >&2 39 | echo >&2 40 | echo " cp "$src_dir"/pre-push" "$dest_dir/" >&2 41 | echo >&2 42 | exit 1 43 | fi 44 | fi 45 | 46 | /bin/cp "$src_dir"/pre-push "$dest_dir"/ 47 | 48 | exit 0 49 | -------------------------------------------------------------------------------- /helpers/mk-versioned-archive: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | usage () { 4 | cat < then 26 | the is taken as the version number. Example: 27 | if this script is executed from /path/to/somewhere/gpb-1.0.0 28 | then the version is assumed to be 1.0.0. 29 | See also further info in the notes below. 30 | 31 | --dest-dir=DIR 32 | Create the resulting archive in DIR instead of in the 33 | current dir. 34 | 35 | For both options --override-version= --override-version-from-cwd-path, 36 | the following holds: 37 | * The version is used verbatim. No attempt is made to check that 38 | it looks like a version gpb would normally find when from a git repo. 39 | * The current working directory is expected to be in the top 40 | of the gpb, ie there should be a 'src' sub-directory in the current dir. 41 | EOF 42 | } 43 | 44 | vsn_source=from_git 45 | vsn=undefined 46 | dest_archive_dir="." 47 | opts_done=false 48 | get_opt_val () { echo "${1#*=}"; } 49 | while [ $opts_done = false ] 50 | do 51 | case "$1" in 52 | --override-version=*) 53 | vsn_source=specified 54 | vsn=$(get_opt_val "$1"); 55 | shift;; 56 | --override-version-from-cwd-path) 57 | vsn_source=from_cwd_path 58 | shift;; 59 | --dest-dir=*) 60 | dest_archive_dir=$(get_opt_val "$1") 61 | shift;; 62 | --help|-h) usage; exit 0;; 63 | -*) echo "Unrecognized option '$1'" >&2; exit 1;; 64 | *) opts_done=true;; 65 | esac 66 | done 67 | 68 | fetch_vsn_from_pwd() { 69 | d=$(pwd) 70 | d_orig=$d 71 | at_top=false 72 | while [ $at_top = false ] 73 | do 74 | b=$(basename "$d") 75 | case "$b" in 76 | gpb-*) 77 | echo ${b#*-} 78 | return 79 | ;; 80 | *) 81 | true 82 | esac 83 | d_up=$(dirname "$d") 84 | [ "$d_up" = "$d" ] && at_top=true 85 | d=$d_up 86 | done 87 | echo >&2 "Could not find the version from path, '$d_orig'" 88 | exit 1 89 | } 90 | set -e 91 | 92 | case $vsn_source in 93 | specified) 94 | if ! [ -f ./src/gpb.erl ] 95 | then 96 | echo >&2 "Expected to be executed in the top of the gpb." 97 | echo >&2 "but cannot find ./src/gpb.erl" 98 | exit 1 99 | fi 100 | tmpdir=${TMPDIR:-/tmp} 101 | dest_dir=$(mktemp -d "/$tmpdir/tmp-export-XXXXXXXX") 102 | trap "ec=\$?; /bin/rm -rf '$dest_dir'; exit \$ec" 0 INT QUIT TERM 103 | mkdir "$dest_dir/gpb-$vsn" 104 | cp -p -r ./ "$dest_dir/gpb-$vsn/" 105 | mk_version_hrl_opts=("--override-version=$vsn") 106 | ;; 107 | from_cwd_path) 108 | if ! [ -f ./src/gpb.erl ] 109 | then 110 | echo >&2 "Expected to be executed in the top of the gpb." 111 | echo >&2 "but cannot find ./src/gpb.erl" 112 | exit 1 113 | fi 114 | vsn=$(fetch_vsn_from_pwd) 115 | echo "Found version '$vsn' from current working directory path." 116 | tmpdir=${TMPDIR:-/tmp} 117 | dest_dir=$(mktemp -d "/$tmpdir/tmp-export-XXXXXXXX") 118 | trap "ec=\$?; /bin/rm -rf '$dest_dir'; exit \$ec" 0 INT QUIT TERM 119 | mkdir "$dest_dir/gpb-$vsn" 120 | cp -p -r ./ "$dest_dir/gpb-$vsn/" 121 | mk_version_hrl_opts=("--override-version=$vsn") 122 | ;; 123 | from_git) 124 | cdup=$(git rev-parse --show-toplevel) && \ 125 | cd "$cdup" || { 126 | echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree" 127 | exit 1 128 | } 129 | vsn=$(./build/find-vsn --show-vsn) 130 | dest_dir=$(mktemp -d "tmp-export-XXXXXXXX") 131 | trap "ec=\$?; /bin/rm -rf '$dest_dir'; exit \$ec" 0 INT QUIT TERM 132 | mkdir "$dest_dir/gpb-$vsn" 133 | git archive --format=tar HEAD | (cd "$dest_dir/gpb-$vsn" && tar xfp -) 134 | mk_version_hrl_opts=("--override-version=$vsn") 135 | ;; 136 | esac 137 | 138 | echo "Exporting version $vsn -> gpb-$vsn.tar.gz" 139 | 140 | echo "$vsn" > "$dest_dir/gpb-$vsn/gpb.vsn" 141 | 142 | # Remove some development auxiliaries 143 | /bin/rm -rf "$dest_dir/gpb-$vsn/helpers" 144 | 145 | ( 146 | cd "$dest_dir" 147 | tar cfpz "gpb-$vsn.tar.gz" "gpb-$vsn" 148 | ) 149 | cp -p "$dest_dir/gpb-$vsn.tar.gz" "$dest_archive_dir"/ 150 | /bin/rm "$dest_dir/gpb-$vsn.tar.gz" 151 | -------------------------------------------------------------------------------- /helpers/package-for-hex.pm: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | show_usage() { 4 | cat </dev/null) 45 | then 46 | echo "ERROR: bad version \"$vsn\", will only publish versions" >&2 47 | echo "that are dotted numbers only." >&2 48 | echo "Aborting." >&2 49 | cleanup 50 | exit 1 51 | fi 52 | fi 53 | echo "Version of gpb: $vsn" 54 | 55 | set -e 56 | cd "$d" 57 | 58 | yes_no () { 59 | echo "Run?" "$@" 60 | valid_answer=false 61 | while [ $valid_answer = false ] 62 | do 63 | printf "Proceed? [Yn]" 64 | read x 65 | case "$x" in 66 | y|Y|yes|Yes|YES|"") 67 | valid_answer=true 68 | "$@" 69 | ;; 70 | n|N|no|No|NO) 71 | valid_answer=true 72 | echo "Not running that command" 73 | ;; 74 | *) 75 | : 76 | ;; 77 | esac 78 | done 79 | } 80 | 81 | ( 82 | 83 | git clone -q "$repo_path" 84 | cd "$(basename "$repo_path")" 85 | unset ERL_LIBS 86 | git checkout -q "$repo_sha" 87 | make -j all 88 | echo "$vsn" > gpb.vsn 89 | cat > .publish-tags < lists:keystore(K,1,Acc,Item) end, 113 | Infos, New), 114 | [FHead | _] = re:split(B, <<"{application,.*gpb">>), 115 | B2 = [FHead, io_lib:format("~p.~n", [{application,gpb,Infos2}])], 116 | case file:write_file(AppSrc, B2) of 117 | ok -> halt(0); 118 | Error -> io:format(standard_error, "Error writing ~p:~n ~p~n", 119 | [AppSrc, Error]), 120 | halt(1) 121 | end. 122 | ' 123 | if [ $? != 0 ] 124 | then 125 | exit 1 126 | fi 127 | cat src/gpb.app.src 128 | export DIAGNOSTIC=1 129 | yes_no rebar3 hex publish 130 | ) 131 | -------------------------------------------------------------------------------- /helpers/send-pr-to-rebar3-gpb-plugin: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | show_usage() { 4 | cat <&2 49 | exit 1 50 | fi 51 | github_access_token=$(echo "$github_access_token" | \ 52 | openssl enc -d -base64 \ 53 | -aes-256-cbc -pbkdf2 -in - -out -) 54 | 55 | echo "$upstream_owner=$upstream_owner" 56 | echo "$upstream_repo=$upstream_repo" 57 | echo "github_access_token=$github_access_token" 58 | 59 | # we must execute from inside the gpb repo, or else the 60 | # version retrieval will fail. 61 | # 62 | 63 | script_dir="$(dirname "$0")" 64 | script_path="$(cd "$script_dir"; pwd)" 65 | cd "$script_dir" 66 | repo_top=$(git rev-parse --show-toplevel) 67 | cd "$repo_top" 68 | repo_path="$(pwd)" 69 | 70 | # Use the git name/email of this repo 71 | git_name=$(git config --get user.name) 72 | git_email=$(git config --get user.email) 73 | 74 | [ -z "$github_user" ] && { 75 | echo "Failed to determine your corresponding github user id" 2>&1 76 | exit 1 77 | } 78 | echo "Your github user appears to be: $github_user" 79 | 80 | d="$(mktemp -d "tmp-pr-for-$repo_name-XXXXXXX")" 81 | cleanup () { /bin/rm -rf "$repo_path/$d"; } 82 | trap 'xc=$?; cleanup; exit $xc' EXIT INT QUIT TERM 83 | 84 | vsn="$(git describe --always --tags --match '[0-9]*.[0-9]*')" 85 | if [ $dry_run = false -a $moist_run = false ] 86 | then 87 | if ! (echo "$vsn" | egrep '^[0-9]+(\.[0-9]+)*$' >/dev/null) 88 | then 89 | echo "ERROR: bad version \"$vsn\", will only publish versions" >&2 90 | echo "that are dotted numbers only." >&2 91 | echo "Aborting." >&2 92 | cleanup 93 | exit 1 94 | fi 95 | fi 96 | echo "Version of gpb: $vsn" 97 | 98 | set -e 99 | cd "$d" 100 | 101 | yes_no () { 102 | echo "Run?" "$@" 103 | valid_answer=false 104 | while [ $valid_answer = false ] 105 | do 106 | printf "Proceed? [Yn]" 107 | read x 108 | case "$x" in 109 | y|Y|yes|Yes|YES|"") 110 | valid_answer=true 111 | "$@" 112 | ;; 113 | n|N|no|No|NO) 114 | valid_answer=true 115 | echo "Not running that command" 116 | ;; 117 | *) 118 | : 119 | ;; 120 | esac 121 | done 122 | } 123 | 124 | pr_br=pr-for-version-"$vsn" 125 | echo "Cloning your $repo_name from github" 126 | git clone -q git@github.com:"$github_user"/"$repo_name" 127 | ( 128 | cd "$repo_name" 129 | git config user.name "$git_name" 130 | git config user.email "$git_email" 131 | echo "Fetching upstream $repo_name from github" 132 | git remote add upstream "$upstream_url" 133 | git fetch -q upstream $default_br 134 | git reset -q --hard upstream/$default_br 135 | 136 | if [ x"$branch_point" = xdefault ] 137 | then 138 | git checkout -b "$pr_br" 139 | else 140 | git checkout -b "$pr_br" "$branch_point" 141 | fi 142 | # Grep for rebar / omit README.md because it contains line number references 143 | # likely to get wrong if we substitute version numbers in that too: 144 | # https://github.com/tomas-abrahamsson/gpb/blob/3.19.0/src/gpb_compile.erl#L66-L93 145 | if [ -f rebar.config ]; then f=rebar.config 146 | elif [ -f rebar.config.script ]; then f=rebar.config.script 147 | else echo "Neither rebar.config nor rebar.config.script exists" >&2; exit 1 148 | fi 149 | tmpf=$(mktemp "$f.tmp-XXXXXXX") 150 | cp "$f" "$tmpf" 151 | # the [^_] is there so we do not change lines like 152 | # {rebar3_gpb_plugin, "1.10.0"} 153 | # but only lines like these: 154 | # {'gpb', "3.26.4"} 155 | # [{<<"gpb">>,{pkg,<<"gpb">>,<<"3.26.4">>},0}]. 156 | sed -e 's/^\(.*[^_]gpb.*\)[0-9]\+\.[0-9]\+\.[0-9]\+/\1'"$vsn"'/' \ 157 | < "$tmpf" \ 158 | > "$f" 159 | rm "$tmpf" 160 | git add "$f" 161 | unset ERL_LIBS 162 | rebar3 unlock gpb 163 | rebar3 upgrade --all 164 | git add rebar.lock 165 | git commit -q -m "Bump gpb to $vsn" 166 | echo "This is the change:-----------------------------------" 167 | PAGER=cat git log -p -1 168 | echo "------------------------------------------------------" 169 | 170 | if [ $dry_run = true -o $moist_run = true ] 171 | then 172 | echo "Dry run: not pushing to update your github repo" 173 | else 174 | echo "Pushing the change to your github repo" 175 | yes_no git push -q --tags origin "$default_br" "$pr_br" 176 | fi 177 | 178 | # Json structure, fields: 179 | # title, body -- title, body text of the pr 180 | # head -- name of the branch where the changes are 181 | # base -- name of the branch you want your changes pulled into 182 | changelog_url="https://github.com/$github_user/gpb/blob/$vsn/ChangeLog" 183 | title="New version of gpb: $vsn" 184 | body="New version of gpb: [$vsn]($changelog_url)" 185 | head="$github_user:$pr_br" 186 | base="$default_br" 187 | data='{ 188 | "title": "'"$title"'", 189 | "body": "'"$body"'", 190 | "head": "'"$head"'", 191 | "base": "'"$base"'" 192 | }' 193 | 194 | if [ $dry_run = true -o $moist_run = true ] 195 | then 196 | maybe_dry=echo 197 | else 198 | maybe_dry=yes_no 199 | fi 200 | 201 | $maybe_dry \ 202 | curl --request POST \ 203 | -H "Authorization: token $github_access_token" \ 204 | -H "Accept: application/vnd.github.v3+json" \ 205 | --data "$data" \ 206 | https://api.github.com/repos/"$upstream_owner"/"$upstream_repo"/pulls 207 | ) 208 | -------------------------------------------------------------------------------- /helpers/tag-next-minor-vsn: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | curr_tag=$(git describe --always --tags --match '[0-9]*.[0-9]*' --abbrev=0) 4 | 5 | increase_last_vsn_part () 6 | { 7 | echo "$@" | \ 8 | awk -F. '{ 9 | for (i=1; i $new_vsn" 18 | echo "Tagging with: $new_vsn" 19 | git tag "$new_vsn" 20 | ;; 21 | [0-9]*.[0-9]*.[0-9]*) 22 | new_vsn=$(increase_last_vsn_part "$curr_tag") 23 | echo "Version change: $curr_tag -> $new_vsn" 24 | echo "Tagging with: $new_vsn" 25 | echo git tag "$new_vsn" 26 | ;; 27 | *) 28 | ## What should a version number bump of x.y.z.w mean? 29 | ## Perhaps x.y.z.w+1 or x.y.z.w+1.0? 30 | ## If we're not on the form x.y or x.y.z, then we might be 31 | ## versioning on a side branch, or some totally different format? 32 | ## Better to leave it to a human to take care of. 33 | echo "ERROR: Current tag, $curr_tag, not on form n.m or n.m.x." >&2 34 | echo "ERROR: I am only a very simple script." >&2 35 | echo "ERROR: Please set the tag manually!" >&2 36 | ;; 37 | esac 38 | -------------------------------------------------------------------------------- /helpers/upload-hexdoc: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | show_usage() { 4 | cat </dev/null) 45 | then 46 | echo "ERROR: bad version \"$vsn\", will only publish versions" >&2 47 | echo "that are dotted numbers only." >&2 48 | echo "Aborting." >&2 49 | cleanup 50 | exit 1 51 | fi 52 | fi 53 | echo "Version of gpb: $vsn" 54 | 55 | set -e 56 | cd "$d" 57 | 58 | yes_no () { 59 | echo "Run?" "$@" 60 | valid_answer=false 61 | while [ $valid_answer = false ] 62 | do 63 | printf "Proceed? [Yn]" 64 | read x 65 | case "$x" in 66 | y|Y|yes|Yes|YES|"") 67 | valid_answer=true 68 | "$@" 69 | ;; 70 | n|N|no|No|NO) 71 | valid_answer=true 72 | echo "Not running that command" 73 | ;; 74 | *) 75 | : 76 | ;; 77 | esac 78 | done 79 | } 80 | 81 | ( 82 | 83 | git clone -q "$repo_path" 84 | cd "$(basename "$repo_path")" 85 | unset ERL_LIBS 86 | git checkout -q "$repo_sha" 87 | make -j all doc 88 | yes_no rebar3 hex docs 89 | ) 90 | -------------------------------------------------------------------------------- /include/gpb.hrl: -------------------------------------------------------------------------------- 1 | -ifndef(gpb_hrl). 2 | -define(gpb_hrl, true). 3 | 4 | -type gpb_scalar() :: 5 | int32 | int64 | uint32 | uint64 | sint32 | sint64 6 | | fixed32 | fixed64 | sfixed32 | sfixed64 7 | | bool 8 | | float | double 9 | | string 10 | | bytes. 11 | 12 | -type gpb_map_key() :: % "any scalar type except floating point types and bytes" 13 | int32 | int64 | uint32 | uint64 | sint32 | sint64 14 | | fixed32 | fixed64 | sfixed32 | sfixed64 15 | | bool 16 | | string. 17 | 18 | %% It is not possible to have maps in maps directly, 19 | %% so this type is any gpb_field_type() except {map,K,V}. 20 | -type gpb_map_value() :: 21 | gpb_scalar() 22 | | {enum,atom()} 23 | | {msg,atom()}. 24 | 25 | -type gpb_field_type() :: %% Erlang type Comment 26 | int32 | int64 % integer() variable-length encoded 27 | | uint32 | uint64 % integer() variable-length encoded 28 | | sint32 | sint64 % integer() variable-length zig-zag encoded 29 | | fixed32 | fixed64 % integer() always 4 | 8 bytes on wire 30 | | sfixed32 | sfixed64 % integer() always 4 | 8 bytes on wire 31 | | bool % true | false 32 | | float | double % float() 33 | | string % string() UTF-8 encoded 34 | % | binary() iff option `strings_as_binaries' 35 | | bytes % binary() 36 | | {enum,atom()} % atom() the enum literal is the atom 37 | | {msg,atom()} % record() the message name is record name 38 | % | map() iff option `maps' 39 | | {group,atom()} % record() name is _ 40 | % | map() iff option `maps' 41 | | {map,gpb_map_key(),gpb_map_value()} % [{K,V}] | map() 42 | | unknown. % iff option `preserve_unknown_fields' 43 | 44 | %% An intermediary type temporarily used internally within gpb during parsing, 45 | %% neither returned from gpb, nor accepted as input go gpb. 46 | -type gpb_internal_intermediary_ref() :: 47 | {ref, term()} | 48 | {msg, list()} | 49 | {group, list()} | 50 | {enum, list()}. 51 | 52 | -type gpb_internal_intermediary_map_ref() :: 53 | {map, gpb_map_key(), gpb_map_value() | gpb_internal_intermediary_ref()}. 54 | 55 | %% The following two definitions (`gpb_field' and `gpb_rpc') are to 56 | %% avoid clashes with other code, since the `field' and `rpc' are 57 | %% really too general names, they should have been prefixed. 58 | %% 59 | %% Unfortunately, they are already part of the API, so they can't 60 | %% be changed without breaking backwards compatibility. 61 | %% (They appear as parameters or return values for functions in `gpb' 62 | %% in generated code.) 63 | %% 64 | %% In case a clash, it is possible to redefine the name locally. 65 | %% The recommendation is to redefine them with prefix, ie to `gpb_field' 66 | %% and `gpb_rpc', since this is what they will change to in some future. 67 | %% 68 | -ifdef(gpb_field_record_name). 69 | -define(gpb_field, ?gpb_field_record_name). 70 | -else. 71 | -define(gpb_field, field). %% odd definition is due to backwards compatibility 72 | -endif. 73 | 74 | -ifdef(gpb_rpc_record_name). 75 | -define(gpb_rpc, ?gpb_rpc_record_name). 76 | -else. 77 | -define(gpb_rpc, rpc). %% odd definition is due to backwards compatibility 78 | -endif. 79 | 80 | -record(?gpb_field, % NB: record name is (currently) `field' (not `gpb_field')! 81 | {name :: atom() 82 | | undefined, % temporarily in some phases 83 | fnum :: integer() 84 | | undefined, % temporarily in some phases 85 | rnum :: pos_integer() % field number in the record 86 | | undefined, % temporarily, during parsing 87 | type :: gpb_field_type() | 88 | gpb_internal_intermediary_ref() | 89 | gpb_internal_intermediary_map_ref() 90 | | undefined, % temporarily in some phases 91 | occurrence :: 'required' | 'optional' | 'repeated' 92 | | defaulty % in proto3: non-optional 93 | | undefined, % temporarily in some phases 94 | opts = [] :: [term()] 95 | }). 96 | 97 | -record(gpb_oneof, 98 | {name :: atom() 99 | | undefined, % temporarily in some phases 100 | rnum :: pos_integer() % field number in the record 101 | | undefined, % temporarily, during parsing 102 | fields :: [#?gpb_field{}] % all fields have the same rnum 103 | | undefined, % temporarily in some phases 104 | opts = [] :: [term()] 105 | }). 106 | 107 | -record(?gpb_rpc, % NB: record name is (currently) `rpc' (not `gpb_rpc')! 108 | {name :: atom() 109 | | undefined, % temporarily in some phases 110 | input, 111 | output, 112 | input_stream :: boolean() 113 | | undefined, % temporarily in some phases 114 | output_stream :: boolean() 115 | | undefined, % temporarily in some phases 116 | opts :: [term()] 117 | | undefined % temporarily in some phases 118 | }). 119 | 120 | -endif. 121 | -------------------------------------------------------------------------------- /include/gpb_version.hrl.in: -------------------------------------------------------------------------------- 1 | -ifndef(gpb_version_hrl). 2 | -define(gpb_version_hrl, true). 3 | 4 | %% The version below is expected to be substituted 5 | %% at build-time, see the rebar.config or the Makefile 6 | %% NB: The build/mk_version_hrl depends on the exact wording 7 | 8 | -define(gpb_version, "@vsn@"). 9 | 10 | -define(gpb_version_source, "@vsn-source@"). 11 | 12 | -endif. %% gpb_version_hrl 13 | -------------------------------------------------------------------------------- /priv/proto3/google/protobuf/LICENSE: -------------------------------------------------------------------------------- 1 | The copyright notice and license text below covers only the proto 2 | files in this directory. It does not apply to the rest of the gpb. 3 | The text below was copied from the Google protobuf repository. The 4 | phrases "This code" and "This support library" refer to the Google 5 | protobuf and not to gpb. 6 | 7 | ---------------------------------------------------------------------- 8 | 9 | Copyright 2008 Google Inc. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are 13 | met: 14 | 15 | * Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | * Redistributions in binary form must reproduce the above 18 | copyright notice, this list of conditions and the following disclaimer 19 | in the documentation and/or other materials provided with the 20 | distribution. 21 | * Neither the name of Google Inc. nor the names of its 22 | contributors may be used to endorse or promote products derived from 23 | this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | 37 | Code generated by the Protocol Buffer compiler is owned by the owner 38 | of the input file used when generating it. This code is not 39 | standalone and requires a support library to be linked with it. This 40 | support library is itself covered by the above license. 41 | -------------------------------------------------------------------------------- /priv/proto3/google/protobuf/any.proto: -------------------------------------------------------------------------------- 1 | // This file is imported from protobuf 4.25.1 2 | // 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // https://developers.google.com/protocol-buffers/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | syntax = "proto3"; 35 | 36 | package google.protobuf; 37 | 38 | option go_package = "google.golang.org/protobuf/types/known/anypb"; 39 | option java_package = "com.google.protobuf"; 40 | option java_outer_classname = "AnyProto"; 41 | option java_multiple_files = true; 42 | option objc_class_prefix = "GPB"; 43 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 44 | 45 | // `Any` contains an arbitrary serialized protocol buffer message along with a 46 | // URL that describes the type of the serialized message. 47 | // 48 | // Protobuf library provides support to pack/unpack Any values in the form 49 | // of utility functions or additional generated methods of the Any type. 50 | // 51 | // Example 1: Pack and unpack a message in C++. 52 | // 53 | // Foo foo = ...; 54 | // Any any; 55 | // any.PackFrom(foo); 56 | // ... 57 | // if (any.UnpackTo(&foo)) { 58 | // ... 59 | // } 60 | // 61 | // Example 2: Pack and unpack a message in Java. 62 | // 63 | // Foo foo = ...; 64 | // Any any = Any.pack(foo); 65 | // ... 66 | // if (any.is(Foo.class)) { 67 | // foo = any.unpack(Foo.class); 68 | // } 69 | // // or ... 70 | // if (any.isSameTypeAs(Foo.getDefaultInstance())) { 71 | // foo = any.unpack(Foo.getDefaultInstance()); 72 | // } 73 | // 74 | // Example 3: Pack and unpack a message in Python. 75 | // 76 | // foo = Foo(...) 77 | // any = Any() 78 | // any.Pack(foo) 79 | // ... 80 | // if any.Is(Foo.DESCRIPTOR): 81 | // any.Unpack(foo) 82 | // ... 83 | // 84 | // Example 4: Pack and unpack a message in Go 85 | // 86 | // foo := &pb.Foo{...} 87 | // any, err := anypb.New(foo) 88 | // if err != nil { 89 | // ... 90 | // } 91 | // ... 92 | // foo := &pb.Foo{} 93 | // if err := any.UnmarshalTo(foo); err != nil { 94 | // ... 95 | // } 96 | // 97 | // The pack methods provided by protobuf library will by default use 98 | // 'type.googleapis.com/full.type.name' as the type URL and the unpack 99 | // methods only use the fully qualified type name after the last '/' 100 | // in the type URL, for example "foo.bar.com/x/y.z" will yield type 101 | // name "y.z". 102 | // 103 | // JSON 104 | // ==== 105 | // The JSON representation of an `Any` value uses the regular 106 | // representation of the deserialized, embedded message, with an 107 | // additional field `@type` which contains the type URL. Example: 108 | // 109 | // package google.profile; 110 | // message Person { 111 | // string first_name = 1; 112 | // string last_name = 2; 113 | // } 114 | // 115 | // { 116 | // "@type": "type.googleapis.com/google.profile.Person", 117 | // "firstName": , 118 | // "lastName": 119 | // } 120 | // 121 | // If the embedded message type is well-known and has a custom JSON 122 | // representation, that representation will be embedded adding a field 123 | // `value` which holds the custom JSON in addition to the `@type` 124 | // field. Example (for message [google.protobuf.Duration][]): 125 | // 126 | // { 127 | // "@type": "type.googleapis.com/google.protobuf.Duration", 128 | // "value": "1.212s" 129 | // } 130 | // 131 | message Any { 132 | // A URL/resource name that uniquely identifies the type of the serialized 133 | // protocol buffer message. This string must contain at least 134 | // one "/" character. The last segment of the URL's path must represent 135 | // the fully qualified name of the type (as in 136 | // `path/google.protobuf.Duration`). The name should be in a canonical form 137 | // (e.g., leading "." is not accepted). 138 | // 139 | // In practice, teams usually precompile into the binary all types that they 140 | // expect it to use in the context of Any. However, for URLs which use the 141 | // scheme `http`, `https`, or no scheme, one can optionally set up a type 142 | // server that maps type URLs to message definitions as follows: 143 | // 144 | // * If no scheme is provided, `https` is assumed. 145 | // * An HTTP GET on the URL must yield a [google.protobuf.Type][] 146 | // value in binary format, or produce an error. 147 | // * Applications are allowed to cache lookup results based on the 148 | // URL, or have them precompiled into a binary to avoid any 149 | // lookup. Therefore, binary compatibility needs to be preserved 150 | // on changes to types. (Use versioned type names to manage 151 | // breaking changes.) 152 | // 153 | // Note: this functionality is not currently available in the official 154 | // protobuf release, and it is not used for type URLs beginning with 155 | // type.googleapis.com. As of May 2023, there are no widely used type server 156 | // implementations and no plans to implement one. 157 | // 158 | // Schemes other than `http`, `https` (or the empty scheme) might be 159 | // used with implementation specific semantics. 160 | // 161 | string type_url = 1; 162 | 163 | // Must be a valid serialized protocol buffer of the above specified type. 164 | bytes value = 2; 165 | } 166 | -------------------------------------------------------------------------------- /priv/proto3/google/protobuf/api.proto: -------------------------------------------------------------------------------- 1 | // This file is imported from protobuf 4.25.1 2 | // 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // https://developers.google.com/protocol-buffers/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | syntax = "proto3"; 35 | 36 | package google.protobuf; 37 | 38 | import "google/protobuf/source_context.proto"; 39 | import "google/protobuf/type.proto"; 40 | 41 | option java_package = "com.google.protobuf"; 42 | option java_outer_classname = "ApiProto"; 43 | option java_multiple_files = true; 44 | option objc_class_prefix = "GPB"; 45 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 46 | option go_package = "google.golang.org/protobuf/types/known/apipb"; 47 | 48 | // Api is a light-weight descriptor for an API Interface. 49 | // 50 | // Interfaces are also described as "protocol buffer services" in some contexts, 51 | // such as by the "service" keyword in a .proto file, but they are different 52 | // from API Services, which represent a concrete implementation of an interface 53 | // as opposed to simply a description of methods and bindings. They are also 54 | // sometimes simply referred to as "APIs" in other contexts, such as the name of 55 | // this message itself. See https://cloud.google.com/apis/design/glossary for 56 | // detailed terminology. 57 | message Api { 58 | // The fully qualified name of this interface, including package name 59 | // followed by the interface's simple name. 60 | string name = 1; 61 | 62 | // The methods of this interface, in unspecified order. 63 | repeated Method methods = 2; 64 | 65 | // Any metadata attached to the interface. 66 | repeated Option options = 3; 67 | 68 | // A version string for this interface. If specified, must have the form 69 | // `major-version.minor-version`, as in `1.10`. If the minor version is 70 | // omitted, it defaults to zero. If the entire version field is empty, the 71 | // major version is derived from the package name, as outlined below. If the 72 | // field is not empty, the version in the package name will be verified to be 73 | // consistent with what is provided here. 74 | // 75 | // The versioning schema uses [semantic 76 | // versioning](http://semver.org) where the major version number 77 | // indicates a breaking change and the minor version an additive, 78 | // non-breaking change. Both version numbers are signals to users 79 | // what to expect from different versions, and should be carefully 80 | // chosen based on the product plan. 81 | // 82 | // The major version is also reflected in the package name of the 83 | // interface, which must end in `v`, as in 84 | // `google.feature.v1`. For major versions 0 and 1, the suffix can 85 | // be omitted. Zero major versions must only be used for 86 | // experimental, non-GA interfaces. 87 | // 88 | string version = 4; 89 | 90 | // Source context for the protocol buffer service represented by this 91 | // message. 92 | SourceContext source_context = 5; 93 | 94 | // Included interfaces. See [Mixin][]. 95 | repeated Mixin mixins = 6; 96 | 97 | // The source syntax of the service. 98 | Syntax syntax = 7; 99 | } 100 | 101 | // Method represents a method of an API interface. 102 | message Method { 103 | // The simple name of this method. 104 | string name = 1; 105 | 106 | // A URL of the input message type. 107 | string request_type_url = 2; 108 | 109 | // If true, the request is streamed. 110 | bool request_streaming = 3; 111 | 112 | // The URL of the output message type. 113 | string response_type_url = 4; 114 | 115 | // If true, the response is streamed. 116 | bool response_streaming = 5; 117 | 118 | // Any metadata attached to the method. 119 | repeated Option options = 6; 120 | 121 | // The source syntax of this method. 122 | Syntax syntax = 7; 123 | } 124 | 125 | // Declares an API Interface to be included in this interface. The including 126 | // interface must redeclare all the methods from the included interface, but 127 | // documentation and options are inherited as follows: 128 | // 129 | // - If after comment and whitespace stripping, the documentation 130 | // string of the redeclared method is empty, it will be inherited 131 | // from the original method. 132 | // 133 | // - Each annotation belonging to the service config (http, 134 | // visibility) which is not set in the redeclared method will be 135 | // inherited. 136 | // 137 | // - If an http annotation is inherited, the path pattern will be 138 | // modified as follows. Any version prefix will be replaced by the 139 | // version of the including interface plus the [root][] path if 140 | // specified. 141 | // 142 | // Example of a simple mixin: 143 | // 144 | // package google.acl.v1; 145 | // service AccessControl { 146 | // // Get the underlying ACL object. 147 | // rpc GetAcl(GetAclRequest) returns (Acl) { 148 | // option (google.api.http).get = "/v1/{resource=**}:getAcl"; 149 | // } 150 | // } 151 | // 152 | // package google.storage.v2; 153 | // service Storage { 154 | // rpc GetAcl(GetAclRequest) returns (Acl); 155 | // 156 | // // Get a data record. 157 | // rpc GetData(GetDataRequest) returns (Data) { 158 | // option (google.api.http).get = "/v2/{resource=**}"; 159 | // } 160 | // } 161 | // 162 | // Example of a mixin configuration: 163 | // 164 | // apis: 165 | // - name: google.storage.v2.Storage 166 | // mixins: 167 | // - name: google.acl.v1.AccessControl 168 | // 169 | // The mixin construct implies that all methods in `AccessControl` are 170 | // also declared with same name and request/response types in 171 | // `Storage`. A documentation generator or annotation processor will 172 | // see the effective `Storage.GetAcl` method after inherting 173 | // documentation and annotations as follows: 174 | // 175 | // service Storage { 176 | // // Get the underlying ACL object. 177 | // rpc GetAcl(GetAclRequest) returns (Acl) { 178 | // option (google.api.http).get = "/v2/{resource=**}:getAcl"; 179 | // } 180 | // ... 181 | // } 182 | // 183 | // Note how the version in the path pattern changed from `v1` to `v2`. 184 | // 185 | // If the `root` field in the mixin is specified, it should be a 186 | // relative path under which inherited HTTP paths are placed. Example: 187 | // 188 | // apis: 189 | // - name: google.storage.v2.Storage 190 | // mixins: 191 | // - name: google.acl.v1.AccessControl 192 | // root: acls 193 | // 194 | // This implies the following inherited HTTP annotation: 195 | // 196 | // service Storage { 197 | // // Get the underlying ACL object. 198 | // rpc GetAcl(GetAclRequest) returns (Acl) { 199 | // option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; 200 | // } 201 | // ... 202 | // } 203 | message Mixin { 204 | // The fully qualified name of the interface which is included. 205 | string name = 1; 206 | 207 | // If non-empty specifies a path under which inherited HTTP paths 208 | // are rooted. 209 | string root = 2; 210 | } 211 | -------------------------------------------------------------------------------- /priv/proto3/google/protobuf/duration.proto: -------------------------------------------------------------------------------- 1 | // This file is imported from protobuf 4.25.1 2 | // 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // https://developers.google.com/protocol-buffers/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | syntax = "proto3"; 35 | 36 | package google.protobuf; 37 | 38 | option cc_enable_arenas = true; 39 | option go_package = "google.golang.org/protobuf/types/known/durationpb"; 40 | option java_package = "com.google.protobuf"; 41 | option java_outer_classname = "DurationProto"; 42 | option java_multiple_files = true; 43 | option objc_class_prefix = "GPB"; 44 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 45 | 46 | // A Duration represents a signed, fixed-length span of time represented 47 | // as a count of seconds and fractions of seconds at nanosecond 48 | // resolution. It is independent of any calendar and concepts like "day" 49 | // or "month". It is related to Timestamp in that the difference between 50 | // two Timestamp values is a Duration and it can be added or subtracted 51 | // from a Timestamp. Range is approximately +-10,000 years. 52 | // 53 | // # Examples 54 | // 55 | // Example 1: Compute Duration from two Timestamps in pseudo code. 56 | // 57 | // Timestamp start = ...; 58 | // Timestamp end = ...; 59 | // Duration duration = ...; 60 | // 61 | // duration.seconds = end.seconds - start.seconds; 62 | // duration.nanos = end.nanos - start.nanos; 63 | // 64 | // if (duration.seconds < 0 && duration.nanos > 0) { 65 | // duration.seconds += 1; 66 | // duration.nanos -= 1000000000; 67 | // } else if (duration.seconds > 0 && duration.nanos < 0) { 68 | // duration.seconds -= 1; 69 | // duration.nanos += 1000000000; 70 | // } 71 | // 72 | // Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. 73 | // 74 | // Timestamp start = ...; 75 | // Duration duration = ...; 76 | // Timestamp end = ...; 77 | // 78 | // end.seconds = start.seconds + duration.seconds; 79 | // end.nanos = start.nanos + duration.nanos; 80 | // 81 | // if (end.nanos < 0) { 82 | // end.seconds -= 1; 83 | // end.nanos += 1000000000; 84 | // } else if (end.nanos >= 1000000000) { 85 | // end.seconds += 1; 86 | // end.nanos -= 1000000000; 87 | // } 88 | // 89 | // Example 3: Compute Duration from datetime.timedelta in Python. 90 | // 91 | // td = datetime.timedelta(days=3, minutes=10) 92 | // duration = Duration() 93 | // duration.FromTimedelta(td) 94 | // 95 | // # JSON Mapping 96 | // 97 | // In JSON format, the Duration type is encoded as a string rather than an 98 | // object, where the string ends in the suffix "s" (indicating seconds) and 99 | // is preceded by the number of seconds, with nanoseconds expressed as 100 | // fractional seconds. For example, 3 seconds with 0 nanoseconds should be 101 | // encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should 102 | // be expressed in JSON format as "3.000000001s", and 3 seconds and 1 103 | // microsecond should be expressed in JSON format as "3.000001s". 104 | // 105 | message Duration { 106 | // Signed seconds of the span of time. Must be from -315,576,000,000 107 | // to +315,576,000,000 inclusive. Note: these bounds are computed from: 108 | // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years 109 | int64 seconds = 1; 110 | 111 | // Signed fractions of a second at nanosecond resolution of the span 112 | // of time. Durations less than one second are represented with a 0 113 | // `seconds` field and a positive or negative `nanos` field. For durations 114 | // of one second or more, a non-zero value for the `nanos` field must be 115 | // of the same sign as the `seconds` field. Must be from -999,999,999 116 | // to +999,999,999 inclusive. 117 | int32 nanos = 2; 118 | } 119 | -------------------------------------------------------------------------------- /priv/proto3/google/protobuf/empty.proto: -------------------------------------------------------------------------------- 1 | // This file is imported from protobuf 4.25.1 2 | // 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // https://developers.google.com/protocol-buffers/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | syntax = "proto3"; 35 | 36 | package google.protobuf; 37 | 38 | option go_package = "google.golang.org/protobuf/types/known/emptypb"; 39 | option java_package = "com.google.protobuf"; 40 | option java_outer_classname = "EmptyProto"; 41 | option java_multiple_files = true; 42 | option objc_class_prefix = "GPB"; 43 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 44 | option cc_enable_arenas = true; 45 | 46 | // A generic empty message that you can re-use to avoid defining duplicated 47 | // empty messages in your APIs. A typical example is to use it as the request 48 | // or the response type of an API method. For instance: 49 | // 50 | // service Foo { 51 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); 52 | // } 53 | // 54 | message Empty {} 55 | -------------------------------------------------------------------------------- /priv/proto3/google/protobuf/field_mask.proto: -------------------------------------------------------------------------------- 1 | // This file is imported from protobuf 4.25.1 2 | // 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // https://developers.google.com/protocol-buffers/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | syntax = "proto3"; 35 | 36 | package google.protobuf; 37 | 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "FieldMaskProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 43 | option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; 44 | option cc_enable_arenas = true; 45 | 46 | // `FieldMask` represents a set of symbolic field paths, for example: 47 | // 48 | // paths: "f.a" 49 | // paths: "f.b.d" 50 | // 51 | // Here `f` represents a field in some root message, `a` and `b` 52 | // fields in the message found in `f`, and `d` a field found in the 53 | // message in `f.b`. 54 | // 55 | // Field masks are used to specify a subset of fields that should be 56 | // returned by a get operation or modified by an update operation. 57 | // Field masks also have a custom JSON encoding (see below). 58 | // 59 | // # Field Masks in Projections 60 | // 61 | // When used in the context of a projection, a response message or 62 | // sub-message is filtered by the API to only contain those fields as 63 | // specified in the mask. For example, if the mask in the previous 64 | // example is applied to a response message as follows: 65 | // 66 | // f { 67 | // a : 22 68 | // b { 69 | // d : 1 70 | // x : 2 71 | // } 72 | // y : 13 73 | // } 74 | // z: 8 75 | // 76 | // The result will not contain specific values for fields x,y and z 77 | // (their value will be set to the default, and omitted in proto text 78 | // output): 79 | // 80 | // 81 | // f { 82 | // a : 22 83 | // b { 84 | // d : 1 85 | // } 86 | // } 87 | // 88 | // A repeated field is not allowed except at the last position of a 89 | // paths string. 90 | // 91 | // If a FieldMask object is not present in a get operation, the 92 | // operation applies to all fields (as if a FieldMask of all fields 93 | // had been specified). 94 | // 95 | // Note that a field mask does not necessarily apply to the 96 | // top-level response message. In case of a REST get operation, the 97 | // field mask applies directly to the response, but in case of a REST 98 | // list operation, the mask instead applies to each individual message 99 | // in the returned resource list. In case of a REST custom method, 100 | // other definitions may be used. Where the mask applies will be 101 | // clearly documented together with its declaration in the API. In 102 | // any case, the effect on the returned resource/resources is required 103 | // behavior for APIs. 104 | // 105 | // # Field Masks in Update Operations 106 | // 107 | // A field mask in update operations specifies which fields of the 108 | // targeted resource are going to be updated. The API is required 109 | // to only change the values of the fields as specified in the mask 110 | // and leave the others untouched. If a resource is passed in to 111 | // describe the updated values, the API ignores the values of all 112 | // fields not covered by the mask. 113 | // 114 | // If a repeated field is specified for an update operation, new values will 115 | // be appended to the existing repeated field in the target resource. Note that 116 | // a repeated field is only allowed in the last position of a `paths` string. 117 | // 118 | // If a sub-message is specified in the last position of the field mask for an 119 | // update operation, then new value will be merged into the existing sub-message 120 | // in the target resource. 121 | // 122 | // For example, given the target message: 123 | // 124 | // f { 125 | // b { 126 | // d: 1 127 | // x: 2 128 | // } 129 | // c: [1] 130 | // } 131 | // 132 | // And an update message: 133 | // 134 | // f { 135 | // b { 136 | // d: 10 137 | // } 138 | // c: [2] 139 | // } 140 | // 141 | // then if the field mask is: 142 | // 143 | // paths: ["f.b", "f.c"] 144 | // 145 | // then the result will be: 146 | // 147 | // f { 148 | // b { 149 | // d: 10 150 | // x: 2 151 | // } 152 | // c: [1, 2] 153 | // } 154 | // 155 | // An implementation may provide options to override this default behavior for 156 | // repeated and message fields. 157 | // 158 | // In order to reset a field's value to the default, the field must 159 | // be in the mask and set to the default value in the provided resource. 160 | // Hence, in order to reset all fields of a resource, provide a default 161 | // instance of the resource and set all fields in the mask, or do 162 | // not provide a mask as described below. 163 | // 164 | // If a field mask is not present on update, the operation applies to 165 | // all fields (as if a field mask of all fields has been specified). 166 | // Note that in the presence of schema evolution, this may mean that 167 | // fields the client does not know and has therefore not filled into 168 | // the request will be reset to their default. If this is unwanted 169 | // behavior, a specific service may require a client to always specify 170 | // a field mask, producing an error if not. 171 | // 172 | // As with get operations, the location of the resource which 173 | // describes the updated values in the request message depends on the 174 | // operation kind. In any case, the effect of the field mask is 175 | // required to be honored by the API. 176 | // 177 | // ## Considerations for HTTP REST 178 | // 179 | // The HTTP kind of an update operation which uses a field mask must 180 | // be set to PATCH instead of PUT in order to satisfy HTTP semantics 181 | // (PUT must only be used for full updates). 182 | // 183 | // # JSON Encoding of Field Masks 184 | // 185 | // In JSON, a field mask is encoded as a single string where paths are 186 | // separated by a comma. Fields name in each path are converted 187 | // to/from lower-camel naming conventions. 188 | // 189 | // As an example, consider the following message declarations: 190 | // 191 | // message Profile { 192 | // User user = 1; 193 | // Photo photo = 2; 194 | // } 195 | // message User { 196 | // string display_name = 1; 197 | // string address = 2; 198 | // } 199 | // 200 | // In proto a field mask for `Profile` may look as such: 201 | // 202 | // mask { 203 | // paths: "user.display_name" 204 | // paths: "photo" 205 | // } 206 | // 207 | // In JSON, the same mask is represented as below: 208 | // 209 | // { 210 | // mask: "user.displayName,photo" 211 | // } 212 | // 213 | // # Field Masks and Oneof Fields 214 | // 215 | // Field masks treat fields in oneofs just as regular fields. Consider the 216 | // following message: 217 | // 218 | // message SampleMessage { 219 | // oneof test_oneof { 220 | // string name = 4; 221 | // SubMessage sub_message = 9; 222 | // } 223 | // } 224 | // 225 | // The field mask can be: 226 | // 227 | // mask { 228 | // paths: "name" 229 | // } 230 | // 231 | // Or: 232 | // 233 | // mask { 234 | // paths: "sub_message" 235 | // } 236 | // 237 | // Note that oneof type names ("test_oneof" in this case) cannot be used in 238 | // paths. 239 | // 240 | // ## Field Mask Verification 241 | // 242 | // The implementation of any API method which has a FieldMask type field in the 243 | // request should verify the included field paths, and return an 244 | // `INVALID_ARGUMENT` error if any path is unmappable. 245 | message FieldMask { 246 | // The set of field mask paths. 247 | repeated string paths = 1; 248 | } 249 | -------------------------------------------------------------------------------- /priv/proto3/google/protobuf/source_context.proto: -------------------------------------------------------------------------------- 1 | // This file is imported from protobuf 4.25.1 2 | // 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // https://developers.google.com/protocol-buffers/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | syntax = "proto3"; 35 | 36 | package google.protobuf; 37 | 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "SourceContextProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 43 | option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; 44 | 45 | // `SourceContext` represents information about the source of a 46 | // protobuf element, like the file in which it is defined. 47 | message SourceContext { 48 | // The path-qualified name of the .proto file that contained the associated 49 | // protobuf element. For example: `"google/protobuf/source_context.proto"`. 50 | string file_name = 1; 51 | } 52 | -------------------------------------------------------------------------------- /priv/proto3/google/protobuf/struct.proto: -------------------------------------------------------------------------------- 1 | // This file is imported from protobuf 4.25.1 2 | // 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // https://developers.google.com/protocol-buffers/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | syntax = "proto3"; 35 | 36 | package google.protobuf; 37 | 38 | option cc_enable_arenas = true; 39 | option go_package = "google.golang.org/protobuf/types/known/structpb"; 40 | option java_package = "com.google.protobuf"; 41 | option java_outer_classname = "StructProto"; 42 | option java_multiple_files = true; 43 | option objc_class_prefix = "GPB"; 44 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 45 | 46 | // `Struct` represents a structured data value, consisting of fields 47 | // which map to dynamically typed values. In some languages, `Struct` 48 | // might be supported by a native representation. For example, in 49 | // scripting languages like JS a struct is represented as an 50 | // object. The details of that representation are described together 51 | // with the proto support for the language. 52 | // 53 | // The JSON representation for `Struct` is JSON object. 54 | message Struct { 55 | // Unordered map of dynamically typed values. 56 | map fields = 1; 57 | } 58 | 59 | // `Value` represents a dynamically typed value which can be either 60 | // null, a number, a string, a boolean, a recursive struct value, or a 61 | // list of values. A producer of value is expected to set one of these 62 | // variants. Absence of any variant indicates an error. 63 | // 64 | // The JSON representation for `Value` is JSON value. 65 | message Value { 66 | // The kind of value. 67 | oneof kind { 68 | // Represents a null value. 69 | NullValue null_value = 1; 70 | // Represents a double value. 71 | double number_value = 2; 72 | // Represents a string value. 73 | string string_value = 3; 74 | // Represents a boolean value. 75 | bool bool_value = 4; 76 | // Represents a structured value. 77 | Struct struct_value = 5; 78 | // Represents a repeated `Value`. 79 | ListValue list_value = 6; 80 | } 81 | } 82 | 83 | // `NullValue` is a singleton enumeration to represent the null value for the 84 | // `Value` type union. 85 | // 86 | // The JSON representation for `NullValue` is JSON `null`. 87 | enum NullValue { 88 | // Null value. 89 | NULL_VALUE = 0; 90 | } 91 | 92 | // `ListValue` is a wrapper around a repeated field of values. 93 | // 94 | // The JSON representation for `ListValue` is JSON array. 95 | message ListValue { 96 | // Repeated field of dynamically typed values. 97 | repeated Value values = 1; 98 | } 99 | -------------------------------------------------------------------------------- /priv/proto3/google/protobuf/timestamp.proto: -------------------------------------------------------------------------------- 1 | // This file is imported from protobuf 4.25.1 2 | // 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // https://developers.google.com/protocol-buffers/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | syntax = "proto3"; 35 | 36 | package google.protobuf; 37 | 38 | option cc_enable_arenas = true; 39 | option go_package = "google.golang.org/protobuf/types/known/timestamppb"; 40 | option java_package = "com.google.protobuf"; 41 | option java_outer_classname = "TimestampProto"; 42 | option java_multiple_files = true; 43 | option objc_class_prefix = "GPB"; 44 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 45 | 46 | // A Timestamp represents a point in time independent of any time zone or local 47 | // calendar, encoded as a count of seconds and fractions of seconds at 48 | // nanosecond resolution. The count is relative to an epoch at UTC midnight on 49 | // January 1, 1970, in the proleptic Gregorian calendar which extends the 50 | // Gregorian calendar backwards to year one. 51 | // 52 | // All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap 53 | // second table is needed for interpretation, using a [24-hour linear 54 | // smear](https://developers.google.com/time/smear). 55 | // 56 | // The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By 57 | // restricting to that range, we ensure that we can convert to and from [RFC 58 | // 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. 59 | // 60 | // # Examples 61 | // 62 | // Example 1: Compute Timestamp from POSIX `time()`. 63 | // 64 | // Timestamp timestamp; 65 | // timestamp.set_seconds(time(NULL)); 66 | // timestamp.set_nanos(0); 67 | // 68 | // Example 2: Compute Timestamp from POSIX `gettimeofday()`. 69 | // 70 | // struct timeval tv; 71 | // gettimeofday(&tv, NULL); 72 | // 73 | // Timestamp timestamp; 74 | // timestamp.set_seconds(tv.tv_sec); 75 | // timestamp.set_nanos(tv.tv_usec * 1000); 76 | // 77 | // Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. 78 | // 79 | // FILETIME ft; 80 | // GetSystemTimeAsFileTime(&ft); 81 | // UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; 82 | // 83 | // // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z 84 | // // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. 85 | // Timestamp timestamp; 86 | // timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); 87 | // timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); 88 | // 89 | // Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. 90 | // 91 | // long millis = System.currentTimeMillis(); 92 | // 93 | // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) 94 | // .setNanos((int) ((millis % 1000) * 1000000)).build(); 95 | // 96 | // Example 5: Compute Timestamp from Java `Instant.now()`. 97 | // 98 | // Instant now = Instant.now(); 99 | // 100 | // Timestamp timestamp = 101 | // Timestamp.newBuilder().setSeconds(now.getEpochSecond()) 102 | // .setNanos(now.getNano()).build(); 103 | // 104 | // Example 6: Compute Timestamp from current time in Python. 105 | // 106 | // timestamp = Timestamp() 107 | // timestamp.GetCurrentTime() 108 | // 109 | // # JSON Mapping 110 | // 111 | // In JSON format, the Timestamp type is encoded as a string in the 112 | // [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the 113 | // format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" 114 | // where {year} is always expressed using four digits while {month}, {day}, 115 | // {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional 116 | // seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), 117 | // are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone 118 | // is required. A proto3 JSON serializer should always use UTC (as indicated by 119 | // "Z") when printing the Timestamp type and a proto3 JSON parser should be 120 | // able to accept both UTC and other timezones (as indicated by an offset). 121 | // 122 | // For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 123 | // 01:30 UTC on January 15, 2017. 124 | // 125 | // In JavaScript, one can convert a Date object to this format using the 126 | // standard 127 | // [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) 128 | // method. In Python, a standard `datetime.datetime` object can be converted 129 | // to this format using 130 | // [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with 131 | // the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use 132 | // the Joda Time's [`ISODateTimeFormat.dateTime()`]( 133 | // http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() 134 | // ) to obtain a formatter capable of generating timestamps in this format. 135 | // 136 | message Timestamp { 137 | // Represents seconds of UTC time since Unix epoch 138 | // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 139 | // 9999-12-31T23:59:59Z inclusive. 140 | int64 seconds = 1; 141 | 142 | // Non-negative fractions of a second at nanosecond resolution. Negative 143 | // second values with fractions must still have non-negative nanos values 144 | // that count forward in time. Must be from 0 to 999,999,999 145 | // inclusive. 146 | int32 nanos = 2; 147 | } 148 | -------------------------------------------------------------------------------- /priv/proto3/google/protobuf/type.proto: -------------------------------------------------------------------------------- 1 | // This file is imported from protobuf 4.25.1 2 | // 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // https://developers.google.com/protocol-buffers/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | syntax = "proto3"; 35 | 36 | package google.protobuf; 37 | 38 | import "google/protobuf/any.proto"; 39 | import "google/protobuf/source_context.proto"; 40 | 41 | option cc_enable_arenas = true; 42 | option java_package = "com.google.protobuf"; 43 | option java_outer_classname = "TypeProto"; 44 | option java_multiple_files = true; 45 | option objc_class_prefix = "GPB"; 46 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 47 | option go_package = "google.golang.org/protobuf/types/known/typepb"; 48 | 49 | // A protocol buffer message type. 50 | message Type { 51 | // The fully qualified message name. 52 | string name = 1; 53 | // The list of fields. 54 | repeated Field fields = 2; 55 | // The list of types appearing in `oneof` definitions in this type. 56 | repeated string oneofs = 3; 57 | // The protocol buffer options. 58 | repeated Option options = 4; 59 | // The source context. 60 | SourceContext source_context = 5; 61 | // The source syntax. 62 | Syntax syntax = 6; 63 | // The source edition string, only valid when syntax is SYNTAX_EDITIONS. 64 | string edition = 7; 65 | } 66 | 67 | // A single field of a message type. 68 | message Field { 69 | // Basic field types. 70 | enum Kind { 71 | // Field type unknown. 72 | TYPE_UNKNOWN = 0; 73 | // Field type double. 74 | TYPE_DOUBLE = 1; 75 | // Field type float. 76 | TYPE_FLOAT = 2; 77 | // Field type int64. 78 | TYPE_INT64 = 3; 79 | // Field type uint64. 80 | TYPE_UINT64 = 4; 81 | // Field type int32. 82 | TYPE_INT32 = 5; 83 | // Field type fixed64. 84 | TYPE_FIXED64 = 6; 85 | // Field type fixed32. 86 | TYPE_FIXED32 = 7; 87 | // Field type bool. 88 | TYPE_BOOL = 8; 89 | // Field type string. 90 | TYPE_STRING = 9; 91 | // Field type group. Proto2 syntax only, and deprecated. 92 | TYPE_GROUP = 10; 93 | // Field type message. 94 | TYPE_MESSAGE = 11; 95 | // Field type bytes. 96 | TYPE_BYTES = 12; 97 | // Field type uint32. 98 | TYPE_UINT32 = 13; 99 | // Field type enum. 100 | TYPE_ENUM = 14; 101 | // Field type sfixed32. 102 | TYPE_SFIXED32 = 15; 103 | // Field type sfixed64. 104 | TYPE_SFIXED64 = 16; 105 | // Field type sint32. 106 | TYPE_SINT32 = 17; 107 | // Field type sint64. 108 | TYPE_SINT64 = 18; 109 | } 110 | 111 | // Whether a field is optional, required, or repeated. 112 | enum Cardinality { 113 | // For fields with unknown cardinality. 114 | CARDINALITY_UNKNOWN = 0; 115 | // For optional fields. 116 | CARDINALITY_OPTIONAL = 1; 117 | // For required fields. Proto2 syntax only. 118 | CARDINALITY_REQUIRED = 2; 119 | // For repeated fields. 120 | CARDINALITY_REPEATED = 3; 121 | } 122 | 123 | // The field type. 124 | Kind kind = 1; 125 | // The field cardinality. 126 | Cardinality cardinality = 2; 127 | // The field number. 128 | int32 number = 3; 129 | // The field name. 130 | string name = 4; 131 | // The field type URL, without the scheme, for message or enumeration 132 | // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. 133 | string type_url = 6; 134 | // The index of the field type in `Type.oneofs`, for message or enumeration 135 | // types. The first type has index 1; zero means the type is not in the list. 136 | int32 oneof_index = 7; 137 | // Whether to use alternative packed wire representation. 138 | bool packed = 8; 139 | // The protocol buffer options. 140 | repeated Option options = 9; 141 | // The field JSON name. 142 | string json_name = 10; 143 | // The string value of the default value of this field. Proto2 syntax only. 144 | string default_value = 11; 145 | } 146 | 147 | // Enum type definition. 148 | message Enum { 149 | // Enum type name. 150 | string name = 1; 151 | // Enum value definitions. 152 | repeated EnumValue enumvalue = 2; 153 | // Protocol buffer options. 154 | repeated Option options = 3; 155 | // The source context. 156 | SourceContext source_context = 4; 157 | // The source syntax. 158 | Syntax syntax = 5; 159 | // The source edition string, only valid when syntax is SYNTAX_EDITIONS. 160 | string edition = 6; 161 | } 162 | 163 | // Enum value definition. 164 | message EnumValue { 165 | // Enum value name. 166 | string name = 1; 167 | // Enum value number. 168 | int32 number = 2; 169 | // Protocol buffer options. 170 | repeated Option options = 3; 171 | } 172 | 173 | // A protocol buffer option, which can be attached to a message, field, 174 | // enumeration, etc. 175 | message Option { 176 | // The option's name. For protobuf built-in options (options defined in 177 | // descriptor.proto), this is the short name. For example, `"map_entry"`. 178 | // For custom options, it should be the fully-qualified name. For example, 179 | // `"google.api.http"`. 180 | string name = 1; 181 | // The option's value packed in an Any message. If the value is a primitive, 182 | // the corresponding wrapper type defined in google/protobuf/wrappers.proto 183 | // should be used. If the value is an enum, it should be stored as an int32 184 | // value using the google.protobuf.Int32Value type. 185 | Any value = 2; 186 | } 187 | 188 | // The syntax in which a protocol buffer element is defined. 189 | enum Syntax { 190 | // Syntax `proto2`. 191 | SYNTAX_PROTO2 = 0; 192 | // Syntax `proto3`. 193 | SYNTAX_PROTO3 = 1; 194 | // Syntax `editions`. 195 | SYNTAX_EDITIONS = 2; 196 | } 197 | -------------------------------------------------------------------------------- /priv/proto3/google/protobuf/wrappers.proto: -------------------------------------------------------------------------------- 1 | // This file is imported from protobuf 4.25.1 2 | // 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // https://developers.google.com/protocol-buffers/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | // 34 | // Wrappers for primitive (non-message) types. These types are useful 35 | // for embedding primitives in the `google.protobuf.Any` type and for places 36 | // where we need to distinguish between the absence of a primitive 37 | // typed field and its default value. 38 | // 39 | // These wrappers have no meaningful use within repeated fields as they lack 40 | // the ability to detect presence on individual elements. 41 | // These wrappers have no meaningful use within a map or a oneof since 42 | // individual entries of a map or fields of a oneof can already detect presence. 43 | 44 | syntax = "proto3"; 45 | 46 | package google.protobuf; 47 | 48 | option cc_enable_arenas = true; 49 | option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; 50 | option java_package = "com.google.protobuf"; 51 | option java_outer_classname = "WrappersProto"; 52 | option java_multiple_files = true; 53 | option objc_class_prefix = "GPB"; 54 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 55 | 56 | // Wrapper message for `double`. 57 | // 58 | // The JSON representation for `DoubleValue` is JSON number. 59 | message DoubleValue { 60 | // The double value. 61 | double value = 1; 62 | } 63 | 64 | // Wrapper message for `float`. 65 | // 66 | // The JSON representation for `FloatValue` is JSON number. 67 | message FloatValue { 68 | // The float value. 69 | float value = 1; 70 | } 71 | 72 | // Wrapper message for `int64`. 73 | // 74 | // The JSON representation for `Int64Value` is JSON string. 75 | message Int64Value { 76 | // The int64 value. 77 | int64 value = 1; 78 | } 79 | 80 | // Wrapper message for `uint64`. 81 | // 82 | // The JSON representation for `UInt64Value` is JSON string. 83 | message UInt64Value { 84 | // The uint64 value. 85 | uint64 value = 1; 86 | } 87 | 88 | // Wrapper message for `int32`. 89 | // 90 | // The JSON representation for `Int32Value` is JSON number. 91 | message Int32Value { 92 | // The int32 value. 93 | int32 value = 1; 94 | } 95 | 96 | // Wrapper message for `uint32`. 97 | // 98 | // The JSON representation for `UInt32Value` is JSON number. 99 | message UInt32Value { 100 | // The uint32 value. 101 | uint32 value = 1; 102 | } 103 | 104 | // Wrapper message for `bool`. 105 | // 106 | // The JSON representation for `BoolValue` is JSON `true` and `false`. 107 | message BoolValue { 108 | // The bool value. 109 | bool value = 1; 110 | } 111 | 112 | // Wrapper message for `string`. 113 | // 114 | // The JSON representation for `StringValue` is JSON string. 115 | message StringValue { 116 | // The string value. 117 | string value = 1; 118 | } 119 | 120 | // Wrapper message for `bytes`. 121 | // 122 | // The JSON representation for `BytesValue` is JSON string. 123 | message BytesValue { 124 | // The bytes value. 125 | bytes value = 1; 126 | } 127 | -------------------------------------------------------------------------------- /rebar.config.script: -------------------------------------------------------------------------------- 1 | %% -*- erlang -*- 2 | 3 | NoHaveMapsOpts = try maps:size(maps:new()) of 4 | 0 -> [] 5 | catch error:undef -> [{d,'NO_HAVE_MAPS',true}] 6 | end. 7 | 8 | %% In Erlang 19, the random module is deprecated 9 | NoHaveRandOpts = try rand:uniform() of 10 | F when is_float(F) -> [] 11 | catch error:undef -> [{d,'NO_HAVE_RAND',true}] 12 | end. 13 | 14 | %% In Erlang 21, a number of string module functions are deprecated: 15 | %% string:join/2 -> lists:join/2 (appeared in Erlang 19) 16 | %% string:str/2 -> string:find/2 (appeared in Erlang 20) 17 | %% string:substr/2 -> string:slice/2 (appeared in Erlang 20) 18 | %% string:tokens/2 -> string:lexemes/2 (appeared in Erlang 20) 19 | %% string:{to_lower,to_upper}/1 -> and string:{lowercase,uppercase}/1 20 | NoHaveErl20StrFunctions = 21 | try string:find("abc", "b") of 22 | "bc" -> [] 23 | catch error:undef -> [{d,'NO_HAVE_ERL20_STR_FUNCTIONS'}] 24 | end. 25 | 26 | %% In Erlang 27, the expression +0.0 =:= -0.0 will evaluate to false 27 | %% whereas in Erlang 26 and earlier, it evaluates to true. 28 | %% In Erlang 26.1, as a prep for Erlang 27, using 0.0 in match expreessions or 29 | %% in comparisons with =:= or =/= will result in a warning that hints about 30 | %% rewriting the value to either +0.0 or -0.0. 31 | %% This preprocessor definition is for we want to run something, eg a unit 32 | %% test, in Erlang versions that can tell +0.0 and -0.0 apart. 33 | NoHavePlusMinusZeroFloat = 34 | case +0.0 =:= -0.0 of 35 | true -> [{d,'NO_HAVE_PLUS_MINUS_ZERO_FLOAT'}]; 36 | false -> [] 37 | end. 38 | 39 | ConfigOpts = NoHaveMapsOpts ++ NoHaveRandOpts ++ NoHaveErl20StrFunctions ++ 40 | NoHavePlusMinusZeroFloat. 41 | 42 | [{require_otp_vsn, ".*"}, 43 | 44 | {pre_hooks, 45 | [{compile, 46 | "escript build/mk_version_hrl include/gpb_version.hrl.in" 47 | " include/gpb_version.hrl"} 48 | ]}, 49 | 50 | %% Erlang compiler options 51 | {erl_opts, [debug_info] ++ ConfigOpts}, 52 | 53 | {erl_first_files, ["src/gpb_codegen.erl"]}, 54 | 55 | %% This line is useful if you have gpb_eqc.erl symlinked to 56 | %% the symlink in the test/ directory. 57 | {eunit_compile_opts, [{i,"../include"}]}, 58 | 59 | {edoc_opts, [{preprocess,true}, {pretty_printer,erl_pp}]}, 60 | 61 | {post_hooks, 62 | [{compile, 63 | "escript build/compile_descriptor"} 64 | ]}, 65 | 66 | %% XRef checks to perform 67 | {xref_checks, [undefined_function_calls]}, 68 | 69 | %% Clean files 70 | {clean_files, [".eunit", "ebin/*.beam", "include/gpb_version.hrl", 71 | "descr_src/gpb_descriptor.erl", "descr_src/gpb_descriptor.hrl"]} 72 | ]. 73 | -------------------------------------------------------------------------------- /src/gpb.app.src: -------------------------------------------------------------------------------- 1 | %% -*- erlang -*- 2 | 3 | %%% Copyright (C) 2010-2013 Tomas Abrahamsson 4 | %%% 5 | %%% Author: Tomas Abrahamsson 6 | %%% 7 | %%% This library is free software; you can redistribute it and/or 8 | %%% modify it under the terms of the GNU Lesser General Public 9 | %%% License as published by the Free Software Foundation; either 10 | %%% version 2.1 of the License, or (at your option) any later version. 11 | %%% 12 | %%% This library is distributed in the hope that it will be useful, 13 | %%% but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | %%% Lesser General Public License for more details. 16 | %%% 17 | %%% You should have received a copy of the GNU Lesser General Public 18 | %%% License along with this library; if not, write to the Free Software 19 | %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 20 | %%% MA 02110-1301 USA 21 | 22 | {application, gpb, 23 | [{description, "Google protocol buffer compiler and runtime support"}, 24 | {vsn, {cmd, "escript ./build/find-vsn --show-vsn"}}, 25 | {modules, [gpb, gpb_analyzer, gpb_codegen, gpb_codemorpher, 26 | gpb_compile, gpb_decoders_lib, gpb_defs, 27 | gpb_gen_decoders, gpb_gen_encoders, gpb_gen_introspect, 28 | gpb_gen_json_decoders, gpb_gen_json_encoders, 29 | gpb_gen_mergers, gpb_gen_nif, gpb_gen_translators, 30 | gpb_gen_types, gpb_gen_verifiers, gpb_scan, gpb_parse, 31 | gpb_lib, gpb_names]}, 32 | {applications, [kernel, stdlib]}, 33 | {registered, []}, 34 | {env, []}]}. 35 | -------------------------------------------------------------------------------- /src/gpb_codegen.hrl: -------------------------------------------------------------------------------- 1 | -ifndef(gpb_codegen_hrl). 2 | -define(gpb_codegen_hrl, true). 3 | 4 | -compile({parse_transform,gpb_codegen}). 5 | 6 | -define(case_clause(Clause), 7 | gpb_codegen:case_clause(case dummy of Clause end)). 8 | 9 | -define(case_clause(Clause, Transforms), % FIXME; Transforms gets misindented 10 | gpb_codegen:case_clause(case dummy of Clause end, 11 | Transforms)). 12 | 13 | -define(fn_clause(FunExpr), 14 | gpb_codegen:fn_clause(FunExpr)). 15 | 16 | -define(fn_clause(FunExpr, Transforms), 17 | gpb_codegen:fn_clause(FunExpr, Transforms)). 18 | 19 | -define(if_clause(Clause), 20 | gpb_codegen:if_clause(if Clause end)). 21 | 22 | -define(if_clause(Clause, Transforms), % FIXME; Transforms gets misindented 23 | gpb_codegen:if_clause(if Clause end, Transforms)). 24 | 25 | -define(receive_clause(Clause), 26 | gpb_codegen:receive_clause(receive Clause end)). 27 | 28 | -define(receive_clause(Clause, Transforms), % FIXME; Transforms gets misindented 29 | gpb_codegen:receive_clause(receive Clause end, Transforms)). 30 | 31 | -define(expr(X), 32 | gpb_codegen:expr(X)). 33 | 34 | -define(expr(X, Transforms), 35 | gpb_codegen:expr(X, Transforms)). 36 | 37 | -define(exprs(X1, Transforms), 38 | gpb_codegen:exprs(X1, Transforms)). 39 | 40 | -define(exprs(X1, X2, Transforms), 41 | gpb_codegen:exprs(X1, X2, Transforms)). 42 | 43 | -define(exprs(X1, X2, X3, Transforms), 44 | gpb_codegen:exprs(X1, X2, X3, Transforms)). 45 | 46 | -define(exprs(X1, X2, X3, X4, Transforms), 47 | gpb_codegen:exprs(X1, X2, X3, X4, Transforms)). 48 | 49 | -define(exprs(X1, X2, X3, X4, X5, Transforms), 50 | gpb_codegen:exprs(X1, X2, X3, X4, X5, Transforms)). 51 | 52 | -endif. %% gpb_codegen_hrl. 53 | -------------------------------------------------------------------------------- /src/gpb_compile.hrl: -------------------------------------------------------------------------------- 1 | -ifndef(gpb_compile_hrl). 2 | -define(gpb_compile_hrl, true). 3 | 4 | -record(ft, {type, occurrence, is_packed}). 5 | -record(anres, %% result of analysis 6 | { 7 | source_filenames, % :: [string()] 8 | used_types, % :: sets:set(gpb_field_type()), 9 | known_msg_size, % :: dict:dict(), %% MsgName -> Size | undefined 10 | fixlen_types, % :: sets:set(#ft{}), 11 | num_packed_fields, % :: integer(), 12 | num_fields, % :: dict:dict(), %% MsgName -> integer() 13 | d_field_pass_method,% :: dict:dict() %% MsgName -> pass_as_record | 14 | % %% pass_as_params 15 | maps_as_msgs, % :: list() % same format as `Defs' 16 | dec_maps_as_msgs, % :: list() % ditto, for decoding 17 | translations, % :: dict:dict(), %% FieldPath -> TranslationOps 18 | types_only_via_translations,% :: sets:set(gpb_field_type()), 19 | map_types, % :: sets:set({map,_,_}) 20 | map_value_types, % :: {boolean(), boolean()} % submsgs?/nonsubmsgs? 21 | group_occurrences, % :: dict:dict() %% GroupName -> repeated | ... 22 | has_p3_opt_strings, % :: boolean(), 23 | unknowns_info, % :: both_with_and_without_field_for_unknowns | 24 | % all_are_without_field_for_unknowns | 25 | % all_are_with_field_for_unknowns | 26 | % no_msgs 27 | renamings % :: no_renamings | gpb_names:renamings(). 28 | }). 29 | -record(maps, { 30 | unset_optional, % :: omitted | present_undefined 31 | oneof % :: tuples | flat 32 | }). 33 | 34 | -define(f(Fmt), io_lib:format(Fmt, [])). 35 | -define(f(Fmt, Args), io_lib:format(Fmt, Args)). 36 | -define(ff(Fmt, Args), lists:flatten(io_lib:format(Fmt, Args))). 37 | 38 | -endif. % gpb_compile_hrl 39 | -------------------------------------------------------------------------------- /src/gpb_decoders_lib.hrl: -------------------------------------------------------------------------------- 1 | -ifndef(gpb_decoders_lib_hrl). 2 | -define(gpb_decoders_lib_hrl, true). 3 | 4 | -record(fn, { 5 | name :: atom(), 6 | initializes_fields = false :: boolean(), 7 | has_finalizer = false :: boolean(), 8 | fields_in_tail_calls = false :: boolean(), 9 | passes_msg = false :: boolean(), 10 | tree % the syntax tree 11 | }). 12 | 13 | -endif. % gpb_decoders_lib_hrl 14 | -------------------------------------------------------------------------------- /test/gpb_lib_tests.erl: -------------------------------------------------------------------------------- 1 | %%% Copyright (C) 2017 Tomas Abrahamsson 2 | %%% 3 | %%% Author: Tomas Abrahamsson 4 | %%% 5 | %%% This library is free software; you can redistribute it and/or 6 | %%% modify it under the terms of the GNU Lesser General Public 7 | %%% License as published by the Free Software Foundation; either 8 | %%% version 2.1 of the License, or (at your option) any later version. 9 | %%% 10 | %%% This library is distributed in the hope that it will be useful, 11 | %%% but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | %%% Lesser General Public License for more details. 14 | %%% 15 | %%% You should have received a copy of the GNU Lesser General Public 16 | %%% License along with this library; if not, write to the Free Software 17 | %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | %%% MA 02110-1301 USA 19 | 20 | -module(gpb_lib_tests). 21 | 22 | -include_lib("eunit/include/eunit.hrl"). 23 | 24 | snake_case_test() -> 25 | "winter_is_a_time_of_year" = gpb_lib:snake_case("WinterIsATimeOfYear"), 26 | "winter_is_a_time_of_year" = gpb_lib:snake_case("winterIsATimeOfYear"), 27 | "a_later_time" = gpb_lib:snake_case("ALaterTime"), 28 | "a_later_time" = gpb_lib:snake_case("aLaterTime"), 29 | %"dotted.name_part" = gpb_lib:snake_case("Dotted.NamePart"), 30 | "already_snake_case" = gpb_lib:snake_case("already_snake_case"), 31 | "this_is_273_k" = gpb_lib:snake_case("ThisIs273K"), 32 | ok. 33 | 34 | basenameify_ish_test() -> 35 | ["b/c/f.proto", "d/c/f.proto", "z/f.proto", "g.proto"] = 36 | gpb_lib:basenameify_ish(["/home/u/a/b/c/f.proto", 37 | "/home/u/a/d/c/f.proto", 38 | "/home/u/x/y/z/f.proto", 39 | "/home/u/x/y/z/g.proto"]), 40 | ["f.proto", "g.proto", "h.proto", "i.proto"] = 41 | gpb_lib:basenameify_ish(["/home/u/a/b/c/f.proto", 42 | "/home/u/a/b/c/g.proto", 43 | "/home/u/a/b/c/h.proto", 44 | "/home/u/a/b/c/i.proto"]), 45 | ["c/f1.proto","f2.proto","z/f1.proto","f4.proto"] = 46 | gpb_lib:basenameify_ish(["a/b/c/f1.proto", 47 | "a/b/f2.proto", 48 | "x/y/z/f1.proto", 49 | "f4.proto"]), 50 | ?assertError({gpb_error, {multiply_defined_file_or_files, _}}, 51 | gpb_lib:basenameify_ish(["x", "x"])). 52 | 53 | -------------------------------------------------------------------------------- /test/gpb_nif_test_helpers.hrl: -------------------------------------------------------------------------------- 1 | -ifndef(GPB_NIF_TEST_HELPERS__HRL). 2 | -define(GPB_NIF_TEST_HELPERS__HRL, true). 3 | 4 | -define(nif_if_supported(FnName), 5 | fun() -> 6 | ExtraChecks = try FnName(extra_checks) 7 | catch error:function_clause -> [] 8 | end, 9 | Needed = FnName(features), 10 | case gpb_compile_tests:check_nif_features_supported( 11 | Needed, ExtraChecks) of 12 | ok -> 13 | {FnName(title), fun FnName/0}; 14 | {error, Why} -> 15 | Skipping = "Skipping \"" ++ FnName(title) ++ "\"", 16 | Title = Skipping ++ ": " ++ Why, 17 | {Title, []} 18 | end 19 | end()). 20 | 21 | -endif. %% -ifndef(GPB_NIF_TEST_HELPERS__HRL). 22 | -------------------------------------------------------------------------------- /test/gpb_scan_tests.erl: -------------------------------------------------------------------------------- 1 | %%% Copyright (C) 2019 Tomas Abrahamsson 2 | %%% 3 | %%% Author: Tomas Abrahamsson 4 | %%% 5 | %%% This library is free software; you can redistribute it and/or 6 | %%% modify it under the terms of the GNU Lesser General Public 7 | %%% License as published by the Free Software Foundation; either 8 | %%% version 2.1 of the License, or (at your option) any later version. 9 | %%% 10 | %%% This library is distributed in the hope that it will be useful, 11 | %%% but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | %%% Lesser General Public License for more details. 14 | %%% 15 | %%% You should have received a copy of the GNU Lesser General Public 16 | %%% License along with this library; if not, write to the Free Software 17 | %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | %%% MA 02110-1301 USA 19 | 20 | %% Test gpb_scan.erl 21 | 22 | -module(gpb_scan_tests). 23 | 24 | -include_lib("eunit/include/eunit.hrl"). 25 | 26 | string_test() -> 27 | [{str_lit, "x"}] = ok_scan(<<"'x'">>), 28 | [{str_lit, "'x'"}] = ok_scan(<<"\"'x'\"">>), 29 | [{str_lit, "\"x\""}] = ok_scan(<<"'\"x\"'">>), 30 | %% \x: max 2 hex chars 31 | [{str_lit, [2]}] = ok_scan(<<"'\\x2'">>), 32 | [{str_lit, " "}] = ok_scan(<<"'\\x20'">>), 33 | [{str_lit, " 1"}] = ok_scan(<<"'\\x201'">>), 34 | [{str_lit, [2, $z]}] = ok_scan(<<"'\\x2z'">>), 35 | %% \u: max 4 hex chars 36 | [{str_lit, [16#2]}] = ok_scan(<<"'\\u2'">>), 37 | [{str_lit, [16#20]}] = ok_scan(<<"'\\u20'">>), 38 | [{str_lit, [16#200]}] = ok_scan(<<"'\\u200'">>), 39 | [{str_lit, [16#2000]}] = ok_scan(<<"'\\u2000'">>), 40 | [{str_lit, [16#2000, $1]}] = ok_scan(<<"'\\u20001'">>), 41 | [{str_lit, [16#2, $z]}] = ok_scan(<<"'\\u2z'">>), 42 | %% \U: max 8 hex chars 43 | [{str_lit, [16#2]}] = ok_scan(<<"'\\U2'">>), 44 | [{str_lit, [16#20]}] = ok_scan(<<"'\\U20'">>), 45 | [{str_lit, [16#200]}] = ok_scan(<<"'\\U200'">>), 46 | [{str_lit, [16#2000]}] = ok_scan(<<"'\\U2000'">>), 47 | [{str_lit, [16#20000]}] = ok_scan(<<"'\\U20000'">>), 48 | [{str_lit, [16#000200]}] = ok_scan(<<"'\\U000200'">>), 49 | [{str_lit, [16#0002000]}] = ok_scan(<<"'\\U0002000'">>), 50 | [{str_lit, [16#00020000]}] = ok_scan(<<"'\\U00020000'">>), 51 | [{str_lit, [16#00020000, $1]}] = ok_scan(<<"'\\U000200001'">>), 52 | [{str_lit, [16#10ffff]}] = ok_scan(<<"'\\U10ffff'">>), 53 | [{str_lit, [16#2, $z]}] = ok_scan(<<"'\\U2z'">>), 54 | ok. 55 | 56 | dot_test() -> 57 | ['.'] = ok_scan(<<".">>), 58 | ok. 59 | 60 | int_test() -> 61 | [{int_lit, {dec, 0}}] = ok_scan(<<"0">>). 62 | 63 | float_test() -> 64 | [ {float_lit, +0.0}] = ok_scan(<<"0.">>), 65 | [ {float_lit, 125.0}] = ok_scan(<<"125.">>), 66 | [ {float_lit, +0.0}] = ok_scan(<<"0.0">>), 67 | [ {float_lit, +0.0}] = ok_scan(<<".0">>), 68 | [ {float_lit, +0.0}] = ok_scan(<<".0e1">>), 69 | ['+', {float_lit, +0.0}] = ok_scan(<<"+0.0">>), 70 | ['+', {float_lit, +0.0}] = ok_scan(<<"+.0">>), 71 | ['+', {float_lit, +0.0}] = ok_scan(<<"+.0e1">>), 72 | ['-', {float_lit, +0.0}] = ok_scan(<<"-0.0">>), 73 | ['-', {float_lit, +0.0}] = ok_scan(<<"-.0">>), 74 | ['-', {float_lit, +0.0}] = ok_scan(<<"-.0e1">>), 75 | [ {float_lit, +0.0}] = ok_scan(<<"0e1">>), 76 | ['+', {float_lit, +0.0}] = ok_scan(<<"+0e1">>), 77 | ['-', {float_lit, +0.0}] = ok_scan(<<"-0e1">>), 78 | [ {float_lit, 0.125}] = ok_scan(<<"0.125">>), 79 | ['-', {float_lit, 0.125}] = ok_scan(<<"-0.125">>), 80 | [ {float_lit, 0.125e3}] = ok_scan(<<"0.125e3">>), 81 | [ {float_lit, 0.125e3}] = ok_scan(<<"0.125e+3">>), 82 | [ {float_lit, 0.000125}] = ok_scan(<<"0.125e-3">>), 83 | [ {float_lit, 1.125}] = ok_scan(<<"1.125">>), 84 | [ {float_lit, 125.0e3}] = ok_scan(<<"125e3">>), 85 | [ {float_lit, 125.0e3}] = ok_scan(<<"125.e3">>), 86 | ok. 87 | 88 | hex_test() -> 89 | [ {int_lit, {hex, 0}}] = ok_scan(<<"0x0">>), 90 | ['+', {int_lit, {hex, 0}}] = ok_scan(<<"+0x0">>), 91 | ['-', {int_lit, {hex, 0}}] = ok_scan(<<"-0x0">>), 92 | [ {int_lit, {hex, 65535}}] = ok_scan(<<"0xffFF">>), 93 | [ {int_lit, {hex, 0}}] = ok_scan(<<"0X0">>), 94 | ['+', {int_lit, {hex, 0}}] = ok_scan(<<"+0X0">>), 95 | ['-', {int_lit, {hex, 0}}] = ok_scan(<<"-0X0">>), 96 | [ {int_lit, {hex, 65535}}] = ok_scan(<<"0XffFF">>), 97 | ok. 98 | 99 | oct_test() -> 100 | [ {int_lit, {oct, 10}}] = ok_scan(<<"012">>), 101 | ['+', {int_lit, {oct, 10}}] = ok_scan(<<"+012">>), 102 | ['-', {int_lit, {oct, 10}}] = ok_scan(<<"-012">>), 103 | ok. 104 | 105 | parses_integer_test() -> %% tests inspired by tests in tokenizer_unittest.cc 106 | [ {int_lit, {dec, 123}}] = ok_scan(<<"123">>), 107 | [ {int_lit, {hex, 2742}}] = ok_scan(<<"0xab6">>), 108 | [ {int_lit, {hex, 2742}}] = ok_scan(<<"0XAB6">>), 109 | [ {int_lit, {hex, 19088743}}] = ok_scan(<<"0X1234567">>), 110 | [ {int_lit, {hex, 2309737967}}] = ok_scan(<<"0x89abcdef">>), 111 | [ {int_lit, {hex, 2309737967}}] = ok_scan(<<"0x89ABCDEF">>), 112 | [ {int_lit, {oct, 342391}}] = ok_scan(<<"01234567">>), 113 | ['-', {int_lit, {dec, 123}}] = ok_scan(<<"-123">>), 114 | ['-', {int_lit, {hex, 2742}}] = ok_scan(<<"-0xab6">>), 115 | ['-', {int_lit, {hex, 2742}}] = ok_scan(<<"-0XAB6">>), 116 | ['-', {int_lit, {hex, 19088743}}] = ok_scan(<<"-0X1234567">>), 117 | ['-', {int_lit, {hex, 2309737967}}] = ok_scan(<<"-0x89abcdef">>), 118 | ['-', {int_lit, {hex, 2309737967}}] = ok_scan(<<"-0x89ABCDEF">>), 119 | ['-', {int_lit, {oct, 342391}}] = ok_scan(<<"-01234567">>), 120 | ok. 121 | 122 | parses_floats_test() -> %% tests inspired by tests in tokenizer_unittest.cc 123 | [{float_lit, 123.45}] = ok_scan(<<"123.45">>), 124 | [{float_lit, 1.0}] = ok_scan(<<"1.">>), 125 | [{float_lit, 1.0e3}] = ok_scan(<<"1e3">>), 126 | [{float_lit, 1.0e3}] = ok_scan(<<"1E3">>), 127 | [{float_lit, 1.0e-3}] = ok_scan(<<"1e-3">>), 128 | [{float_lit, 1.0e3}] = ok_scan(<<"1e+3">>), 129 | [{float_lit, 1.0e3}] = ok_scan(<<"1.e3">>), 130 | [{float_lit, 1.2e3}] = ok_scan(<<"1.2e3">>), 131 | [{float_lit, 0.1}] = ok_scan(<<".1">>), 132 | [{float_lit, 0.1e3}] = ok_scan(<<".1e3">>), 133 | [{float_lit, 0.1e-3}] = ok_scan(<<".1e-3">>), 134 | [{float_lit, 0.1e3}] = ok_scan(<<".1e+3">>), 135 | ok. 136 | 137 | skips_comments_test() -> 138 | [{int_lit, {dec,_}}] = ok_scan(<<"//abv\n12">>), 139 | %% no \n on last line: 140 | [{int_lit, {dec,_}}] = ok_scan(<<"12//def">>), 141 | ok. 142 | 143 | skips_c_style_comments_test() -> 144 | %% not a comment: 145 | {error, _, _} = gpb_scan:binary(<<"/*/12">>), 146 | %% smallest comment: 147 | [{int_lit, _}] = ok_scan(<<"/**/12">>), 148 | [{int_lit, _}] = ok_scan(<<"/* - */12">>), 149 | [{int_lit, _}] = ok_scan(<<"/*****/12">>), 150 | %% greedy test: 151 | [{int_lit, _}] = ok_scan(<<"/*****/12/****/">>), 152 | %% \n in comment: 153 | [{int_lit, _}] = ok_scan(<<"/**\n *\n*/12">>), 154 | %% comment in str: 155 | S = "x/* xyz */y", 156 | [{str_lit,S}] = ok_scan(list_to_binary("\""++S++"\"")), 157 | ok. 158 | 159 | parses_strings_test() -> 160 | [{str_lit,""}] = ok_scan(<<"\"\"">>), 161 | [{str_lit,""}] = ok_scan(<<"''">>), 162 | [{str_lit,"abc"}] = ok_scan(<<"\"abc\"">>), 163 | [{str_lit,"abc"}] = ok_scan(<<"'abc'">>), %% single quotes 164 | [{str_lit,"a\"c"}] = ok_scan(<<"\"a\\\"c\"">>), 165 | [{str_lit,"abz"}] = ok_scan(<<"\"a\\142z\"">>), % 0142=b 166 | [{str_lit,"abz"}] = ok_scan(<<"\"a\\x62z\"">>), % 0x62=b 167 | [{str_lit,"a"}, {str_lit,"b"}] = ok_scan(<<"'a' 'b'">>), 168 | ok. 169 | 170 | max_3_escaped_octdigits_test() -> 171 | [{str_lit,"ab3"}] = ok_scan(<<"\"a\\1423\"">>). 172 | 173 | max_2_escaped_hexdigits_test() -> 174 | [{str_lit,"ab3"}] = ok_scan(<<"\"a\\x623\"">>). 175 | 176 | parses_unicode_escapes_test() -> 177 | %% \u: exactly 4 following 178 | [{str_lit, [$a,16#1234,$b]}] = 179 | ok_scan(<<"\"a\\u1234b\"">>), 180 | %% \U: exactly 8 following hex digits 181 | [{str_lit, [$a,16#101234,$b]}] = 182 | ok_scan(<<"\"a\\U00101234b\"">>), 183 | ok. 184 | 185 | ignores_whitespace_test() -> 186 | [{int_lit,_},{int_lit,_},{int_lit,_}] = 187 | ok_scan(<<"\n 12 13 \t 15">>), 188 | ok. 189 | 190 | saves_orig_test() -> 191 | Strings = [{<<"'abcdef'">>, single_quoted}, 192 | {<<"\"abc\"">>, double_quoted}, 193 | {<<"'a\\u1234bc'">>, up_to_4_hex_chars}, 194 | {<<"'a\\U101234 zz'">>, up_to_8_hex_chars}, 195 | {<<"'a\\x10 zz'">>, up_to_2_hex_chars}, 196 | {<<"'a\\0377 zz'">>, octal}, 197 | {<<"'a\\n\\r\\v\\t\\b zz'">>, backslash_sequences}], 198 | [{{ok, [{{str_lit,_}, _, Orig}], _}, _} = {scan(Orig), What} 199 | || {Orig, What} <- Strings], 200 | 201 | Words = [{<<"message">>, message}, 202 | {<<"max">>, max}, 203 | {<<"inf">>, inf}, 204 | {<<"m12_99">>, m12_99}], 205 | [{{ok, [{Word, _, Word}], _}, _} = {scan(Word), What} 206 | || {Word, What} <- Words], 207 | 208 | IntNumbers = [{<<"0">>, int_zero}, 209 | {<<"0x1234">>, hex}, 210 | {<<"0x1234ffff">>, hex_2}, 211 | {<<"0X1234">>, hex_3}, 212 | {<<"0377">>, oct_255}, 213 | {<<"1234">>, dec}], 214 | [{{ok, [{{int_lit,{_,_}}, _, Orig}], _}, _} = {scan(Orig), What} 215 | || {Orig, What} <- IntNumbers], 216 | 217 | FloatNumbers = [{<<".125">>, leading_point}, 218 | {<<".125e3">>, leading_point_exp}, 219 | {<<".125e-3">>, leading_point_signed_exp}, 220 | {<<"0.125">>, zero_point}, 221 | {<<"0.125e3">>, zero_point_digits_exp}, 222 | {<<"0.125e-3">>, zero_point_digits_signed_exp}, 223 | {<<"0.e3">>, zero_point_exp}, 224 | {<<"0.e-3">>, zero_point_signed_exp}, 225 | {<<"0e3">>, zero_exp}, 226 | {<<"0e-3">>, zero_signed_exp}], 227 | [{{ok, [{{float_lit,_}, _, Orig}], _}, _} = {scan(Orig), What} 228 | || {Orig, What} <- FloatNumbers], 229 | 230 | Punctuations = ".:;{}[]()=,<>-+", 231 | [begin 232 | B = <>, 233 | T = list_to_atom([C]), 234 | {{ok, [{T, _, T}], _}, _} = {scan(B), [C]} 235 | end 236 | || C <- Punctuations], 237 | ok. 238 | 239 | line_numbers_in_tokens_test() -> 240 | B = <<"'abc'\n" 241 | ".\n" 242 | "//\n" % shortest possible 243 | "/**/\n" 244 | "/* ... */ // ...\n" 245 | "10\n" 246 | "1.25e3\n" 247 | "true">>, 248 | {ok, [{{str_lit,_}, 1, _}, 249 | {'.', 2, _}, 250 | %% C++ comment, one line line 251 | %% C comment, 2 lines 252 | %% C comment 1 line, then c++ comment same line 253 | {{int_lit, _}, 6, _}, 254 | {{float_lit, _}, 7, _}, 255 | {<<"true">>, 8, _}]=Tokens, 8 = _EndLine} = 256 | gpb_scan:binary(B), 257 | {ok, Tokens, 9} = gpb_scan:binary(<>), 258 | ok. 259 | 260 | scan_error_test() -> 261 | %% Invalid lexemes 262 | err_scan(<<"&">>, []), 263 | %% Comments 264 | err_scan(<<"/*">>, ["unterminated", "comment"]), 265 | %% Strings 266 | err_scan(<<"'abc">>, ["unterminated", "string"]), 267 | err_scan(<<"'\\u">>, ["unterminated", "string"]), 268 | err_scan(<<"'\\U">>, ["unterminated", "string"]), 269 | err_scan(<<"'\\x">>, ["unterminated", "string"]), 270 | err_scan(<<"'\\">>, ["unterminated", "string"]), 271 | err_scan(<<"'", 255, "'">>, ["utf-8"]), % invalid utf8 octet 272 | err_scan(<<"'", 2#11100011, "'">>, ["utf-8"]), % incomplete utf8 char 273 | err_scan(<<"'\\UffffFFFF'">>, ["invalid", "code", "point"]), % too large 274 | err_scan(<<"'\\ud800'">>, ["invalid", "code", "point"]), 275 | err_scan(<<"'\\udc00'">>, ["invalid", "code", "point"]), 276 | %% Numbers 277 | err_scan(<<"0x">>, ["unterminated", "numeral"]), 278 | err_scan(<<"0xabz">>, ["need", "space"]), 279 | err_scan(<<"09">>, ["invalid", "octal"]), 280 | err_scan(<<"0z">>, ["need", "space"]), 281 | err_scan(<<"0.e">>, ["invalid", "number"]), 282 | err_scan(<<"0.e-">>, ["invalid", "number"]), 283 | err_scan(<<"15e1.2">>, ["invalid", "number"]), 284 | err_scan(<<"15e1z">>, ["need", "space"]), 285 | err_scan(<<"0.z">>, ["need", "space"]), 286 | err_scan(<<"0..">>, ["invalid", "number"]), 287 | ok. 288 | 289 | ok_scan(B) when is_binary(B) -> 290 | {ok, TokensLines, _EndLine} = gpb_scan:binary(B), 291 | [Token || {Token, _Line, _Orig} <- TokensLines]. 292 | 293 | scan(B) when is_binary(B) -> 294 | gpb_scan:binary(B). 295 | 296 | err_scan(B, ExpectedErrTextFragmentsLowerCase) when is_binary(B) -> 297 | {error, {Line, Mod, Reason}, _EndLine} = gpb_scan:binary(B), 298 | ?assert(is_integer(Line)), 299 | ErrText = Mod:format_error(Reason), 300 | ?assert(is_io_data(ErrText)), 301 | ErrStrLC = gpb_lib:lowercase(binary_to_list(iolist_to_binary(ErrText))), 302 | MissingErrTextFragments = 303 | [Fragment || Fragment <- ExpectedErrTextFragmentsLowerCase, 304 | not gpb_lib:is_substr(Fragment, ErrStrLC)], 305 | if MissingErrTextFragments /= [] -> 306 | io:format("ErrStr=~s~n", [ErrStrLC]); % debug 307 | true -> ok 308 | end, 309 | ?assertEqual([], MissingErrTextFragments), 310 | ErrText. 311 | 312 | is_io_data(X) -> 313 | try 314 | iolist_to_binary(X), 315 | true 316 | catch error:badarg -> 317 | false 318 | end. 319 | --------------------------------------------------------------------------------