├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── Makefile.TRAVIS ├── NOTICE ├── README.md ├── ext └── moved.go ├── go.mod ├── go.sum ├── pbtest └── deleted.go ├── pbutil ├── .gitignore ├── Makefile ├── all_test.go ├── decode.go ├── decode_test.go ├── doc.go ├── encode.go └── encode_test.go └── testdata ├── test.pb.go └── test.proto /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.19.x 5 | - tip 6 | 7 | script: make -f Makefile.TRAVIS 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Next 4 | 5 | Here are fragments to be discussed in the next release notes: 6 | 7 | * Retirement notice. 8 | * Reimplemented in terms of `package protodelim`. 9 | 10 | ## v2.0.0 11 | 12 | **Summary**: Modernization of this package to Go standards in 2022, mostly 13 | through internal cleanups. 14 | 15 | **New Features**: None 16 | 17 | The last time this package was significantly modified was 2016, which predates 18 | `cmp`, subtests, the modern Protocol Buffer implementation, and numerous Go 19 | practices that emerged in the intervening years. The new release is tested 20 | against Go 1.19, though I expect it would work with Go 1.13 just fine. 21 | 22 | Finally, I declared bankruptcy on the vendored test fixtures and opted for 23 | creating my own. This is due to the underlying implementation of the generated 24 | code in conjunction with working with a moving target that is an external data 25 | model representation. 26 | 27 | **Upgrade Notes**: This is the aborted v1.0.3 release repackaged as a new 28 | major version 2. To use this, you will need to do or check the following: 29 | 30 | 1. The Protocol Buffer messages you provide to this API are from the 31 | `google.golang.org/protobuf` module. Take special care to audit any 32 | generated or checked-in Protocol Buffer message file assets. They may need 33 | to be regenerated. 34 | 35 | 2. Your code should presumably use the `google.golang.org/protobuf` module for 36 | Protocol Buffers. 37 | 38 | 3. This is a new major version of the module, so you will need to transition 39 | from module `github.com/matttproud/golang_protobuf_extensions` to 40 | `github.com/matttproud/golang_protobuf_extensions/v2`. 41 | 42 | ## v1.0.4 43 | 44 | **Summary**: This is an emergency re-tag of v1.0.2 since v1.0.3 broke API 45 | compatibility for legacy users. See the description of v1.0.2 for details. 46 | 47 | ## v1.0.3 48 | 49 | **DO NOT USE**: Use v1.0.4 instead. What is described in v1.0.3 will be 50 | transitioned to a new major version. 51 | 52 | **Summary**: Modernization of this package to Go standards in 2022, mostly 53 | through internal cleanups. 54 | 55 | **New Features**: None 56 | 57 | The last time this package was significantly modified was 2016, which predates 58 | `cmp`, subtests, the modern Protocol Buffer implementation, and numerous Go 59 | practices that emerged in the intervening years. The new release is tested 60 | against Go 1.19, though I expect it would work with Go 1.13 just fine. 61 | 62 | Finally, I declared bankruptcy on the vendored test fixtures and opted for 63 | creating my own. This is due to the underlying implementation of the generated 64 | code in conjunction with working with a moving target that is an external data 65 | model representation. 66 | 67 | ## v1.0.2 68 | 69 | **Summary**: Tagged version with Go module support. 70 | 71 | **New Features**: None 72 | 73 | End-users wanted a tagged release that includes Go module support. 74 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile.TRAVIS: -------------------------------------------------------------------------------- 1 | all: build cover test vet 2 | 3 | build: 4 | go build -v ./... 5 | 6 | cover: test 7 | $(MAKE) -C pbutil cover 8 | 9 | test: build 10 | go test -v ./... 11 | 12 | vet: build 13 | go vet -v ./... 14 | 15 | .PHONY: build cover test vet 16 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2012 Matt T. Proud (matt.proud@gmail.com) 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | **Note:** This Go package is on the road to retirement. You can learn more 3 | at this blog post: https://matttproud.com/blog/posts/retiring-pbutil.html. 4 | 5 | This repository provides various Protocol Buffer feature extensions for the Go 6 | programming language (golang), namely support for record length-delimited 7 | message streaming. 8 | 9 | | Java | Go | 10 | | ------------------------------ | --------------------- | 11 | | MessageLite#parseDelimitedFrom | pbutil.ReadDelimited | 12 | | MessageLite#writeDelimitedTo | pbutil.WriteDelimited | 13 | 14 | Because [Code Review 9102043](https://codereview.appspot.com/9102043/) is 15 | destined to never be merged into mainline (i.e., never be promoted to formal 16 | [goprotobuf features](https://github.com/golang/protobuf)), this repository 17 | will live here in the wild. 18 | 19 | # Documentation 20 | We have [generated Go Doc documentation](http://godoc.org/github.com/matttproud/golang_protobuf_extensions/pbutil) here. 21 | 22 | # Testing 23 | [![Build Status](https://travis-ci.org/matttproud/golang_protobuf_extensions.png?branch=master)](https://travis-ci.org/matttproud/golang_protobuf_extensions) 24 | -------------------------------------------------------------------------------- /ext/moved.go: -------------------------------------------------------------------------------- 1 | // Package ext moved to a new location: github.com/matttproud/golang_protobuf_extensions/pbutil. 2 | package ext 3 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/matttproud/golang_protobuf_extensions/v2 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/google/go-cmp v0.5.9 7 | google.golang.org/protobuf v1.31.0 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 2 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 3 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 4 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 5 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 6 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 7 | google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= 8 | google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 9 | -------------------------------------------------------------------------------- /pbtest/deleted.go: -------------------------------------------------------------------------------- 1 | // Package pbtest is deleted for the time being, because upstream Protocol Buffer 3 may have rendered quick.Value-based blackbox generation impossible. 2 | package pbtest 3 | -------------------------------------------------------------------------------- /pbutil/.gitignore: -------------------------------------------------------------------------------- 1 | cover.dat 2 | -------------------------------------------------------------------------------- /pbutil/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | 3 | cover: 4 | go test -cover -v -coverprofile=cover.dat ./... 5 | go tool cover -func cover.dat 6 | 7 | .PHONY: cover 8 | -------------------------------------------------------------------------------- /pbutil/all_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Matt T. Proud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package pbutil 16 | 17 | import ( 18 | "bytes" 19 | "errors" 20 | "testing" 21 | 22 | "google.golang.org/protobuf/proto" 23 | "google.golang.org/protobuf/testing/protocmp" 24 | 25 | "github.com/google/go-cmp/cmp" 26 | "github.com/matttproud/golang_protobuf_extensions/v2/testdata" 27 | ) 28 | 29 | func TestWriteDelimited(t *testing.T) { 30 | for _, test := range []struct { 31 | name string 32 | msg proto.Message 33 | buf []byte 34 | n int 35 | err error 36 | }{ 37 | { 38 | name: "empty", 39 | msg: new(testdata.Record), 40 | n: 1, 41 | buf: []byte{0}, 42 | }, 43 | { 44 | name: "firstfield", 45 | msg: &testdata.Record{First: proto.Uint64(1)}, 46 | n: 3, 47 | buf: []byte{2, 8, 1}, 48 | }, 49 | { 50 | name: "thirdfield", 51 | msg: &testdata.Record{ 52 | Third: proto.String(`This is my gigantic, unhappy string. It exceeds 53 | the encoding size of a single byte varint. We are using it to fuzz test the 54 | correctness of the header decoding mechanisms, which may prove problematic. 55 | I expect it may. Let's hope you enjoy testing as much as we do.`), 56 | }, 57 | n: 271, 58 | buf: []byte{141, 2, 26, 138, 2, 84, 104, 105, 115, 32, 105, 115, 32, 109, 59 | 121, 32, 103, 105, 103, 97, 110, 116, 105, 99, 44, 32, 117, 110, 104, 60 | 97, 112, 112, 121, 32, 115, 116, 114, 105, 110, 103, 46, 32, 32, 73, 61 | 116, 32, 101, 120, 99, 101, 101, 100, 115, 10, 116, 104, 101, 32, 101, 62 | 110, 99, 111, 100, 105, 110, 103, 32, 115, 105, 122, 101, 32, 111, 102, 63 | 32, 97, 32, 115, 105, 110, 103, 108, 101, 32, 98, 121, 116, 101, 32, 64 | 118, 97, 114, 105, 110, 116, 46, 32, 32, 87, 101, 32, 97, 114, 101, 32, 65 | 117, 115, 105, 110, 103, 32, 105, 116, 32, 116, 111, 32, 102, 117, 122, 66 | 122, 32, 116, 101, 115, 116, 32, 116, 104, 101, 10, 99, 111, 114, 114, 67 | 101, 99, 116, 110, 101, 115, 115, 32, 111, 102, 32, 116, 104, 101, 32, 68 | 104, 101, 97, 100, 101, 114, 32, 100, 101, 99, 111, 100, 105, 110, 103, 69 | 32, 109, 101, 99, 104, 97, 110, 105, 115, 109, 115, 44, 32, 119, 104, 70 | 105, 99, 104, 32, 109, 97, 121, 32, 112, 114, 111, 118, 101, 32, 112, 71 | 114, 111, 98, 108, 101, 109, 97, 116, 105, 99, 46, 10, 73, 32, 101, 120, 72 | 112, 101, 99, 116, 32, 105, 116, 32, 109, 97, 121, 46, 32, 32, 76, 101, 73 | 116, 39, 115, 32, 104, 111, 112, 101, 32, 121, 111, 117, 32, 101, 110, 74 | 106, 111, 121, 32, 116, 101, 115, 116, 105, 110, 103, 32, 97, 115, 32, 75 | 109, 117, 99, 104, 32, 97, 115, 32, 119, 101, 32, 100, 111, 46}, 76 | }, 77 | } { 78 | t.Run(test.name, func(t *testing.T) { 79 | var buf bytes.Buffer 80 | // TODO: Split out error arm in next patch version. 81 | if n, err := WriteDelimited(&buf, test.msg); !cmp.Equal(n, test.n) || !errors.Is(err, test.err) { 82 | t.Errorf("WriteDelimited(buf, %#v) = %v, %v; want %v, %v", test.msg, n, err, test.n, test.err) 83 | } 84 | if out := buf.Bytes(); !cmp.Equal(out, test.buf) { 85 | t.Errorf("WriteDelimited(buf, %#v); buf = %v; want %v", test.msg, out, test.buf) 86 | } 87 | }) 88 | } 89 | } 90 | 91 | func TestReadDelimited(t *testing.T) { 92 | for _, test := range []struct { 93 | name string 94 | buf []byte 95 | msg proto.Message 96 | n int 97 | err error 98 | }{ 99 | { 100 | name: "empty", 101 | buf: []byte{0}, 102 | msg: new(testdata.Record), 103 | n: 1, 104 | }, 105 | { 106 | name: "firstfield", 107 | n: 3, 108 | buf: []byte{2, 8, 1}, 109 | msg: &testdata.Record{First: proto.Uint64(1)}, 110 | }, 111 | { 112 | name: "thirdfield", 113 | buf: []byte{141, 2, 26, 138, 2, 84, 104, 105, 115, 32, 105, 115, 32, 109, 114 | 121, 32, 103, 105, 103, 97, 110, 116, 105, 99, 44, 32, 117, 110, 104, 115 | 97, 112, 112, 121, 32, 115, 116, 114, 105, 110, 103, 46, 32, 32, 73, 116 | 116, 32, 101, 120, 99, 101, 101, 100, 115, 10, 116, 104, 101, 32, 101, 117 | 110, 99, 111, 100, 105, 110, 103, 32, 115, 105, 122, 101, 32, 111, 102, 118 | 32, 97, 32, 115, 105, 110, 103, 108, 101, 32, 98, 121, 116, 101, 32, 119 | 118, 97, 114, 105, 110, 116, 46, 32, 32, 87, 101, 32, 97, 114, 101, 32, 120 | 117, 115, 105, 110, 103, 32, 105, 116, 32, 116, 111, 32, 102, 117, 122, 121 | 122, 32, 116, 101, 115, 116, 32, 116, 104, 101, 10, 99, 111, 114, 114, 122 | 101, 99, 116, 110, 101, 115, 115, 32, 111, 102, 32, 116, 104, 101, 32, 123 | 104, 101, 97, 100, 101, 114, 32, 100, 101, 99, 111, 100, 105, 110, 103, 124 | 32, 109, 101, 99, 104, 97, 110, 105, 115, 109, 115, 44, 32, 119, 104, 125 | 105, 99, 104, 32, 109, 97, 121, 32, 112, 114, 111, 118, 101, 32, 112, 126 | 114, 111, 98, 108, 101, 109, 97, 116, 105, 99, 46, 10, 73, 32, 101, 120, 127 | 112, 101, 99, 116, 32, 105, 116, 32, 109, 97, 121, 46, 32, 32, 76, 101, 128 | 116, 39, 115, 32, 104, 111, 112, 101, 32, 121, 111, 117, 32, 101, 110, 129 | 106, 111, 121, 32, 116, 101, 115, 116, 105, 110, 103, 32, 97, 115, 32, 130 | 109, 117, 99, 104, 32, 97, 115, 32, 119, 101, 32, 100, 111, 46}, 131 | msg: &testdata.Record{ 132 | Third: proto.String(`This is my gigantic, unhappy string. It exceeds 133 | the encoding size of a single byte varint. We are using it to fuzz test the 134 | correctness of the header decoding mechanisms, which may prove problematic. 135 | I expect it may. Let's hope you enjoy testing as much as we do.`), 136 | }, 137 | n: 271, 138 | }, 139 | } { 140 | t.Run(test.name, func(t *testing.T) { 141 | msg := proto.Clone(test.msg) 142 | proto.Reset(msg) 143 | // TODO: Split out error arm in next patch version. 144 | if n, err := ReadDelimited(bytes.NewBuffer(test.buf), msg); !cmp.Equal(n, test.n) || !errors.Is(err, test.err) { 145 | t.Errorf("ReadDelimited(%v, msg) = %v, %v; want %v, %v", test.buf, n, err, test.n, test.err) 146 | } 147 | if !cmp.Equal(msg, test.msg, protocmp.Transform()) { 148 | t.Errorf("ReadDelimited(%v, msg); msg = %v; want %v", test.buf, msg, test.msg) 149 | } 150 | }) 151 | } 152 | } 153 | 154 | func TestEndToEndValid(t *testing.T) { 155 | for _, test := range []struct { 156 | name string 157 | data []proto.Message 158 | }{ 159 | { 160 | name: "empty", 161 | data: []proto.Message{new(testdata.Record)}, 162 | }, 163 | { 164 | name: "simpleseq", 165 | data: []proto.Message{&testdata.Record{First: proto.Uint64(1)}, new(testdata.Record), &testdata.Record{First: proto.Uint64(1)}}, 166 | }, 167 | { 168 | name: "singleton", 169 | data: []proto.Message{&testdata.Record{First: proto.Uint64(1)}}, 170 | }, 171 | { 172 | name: "headerlength", 173 | data: []proto.Message{&testdata.Record{ 174 | Third: proto.String(`This is my gigantic, unhappy string. It exceeds 175 | the encoding size of a single byte varint. We are using it to fuzz test the 176 | correctness of the header decoding mechanisms, which may prove problematic. 177 | I expect it may. Let's hope you enjoy testing as much as we do.`), 178 | }}, 179 | }, 180 | } { 181 | t.Run(test.name, func(t *testing.T) { 182 | var buf bytes.Buffer 183 | var written int 184 | for i, msg := range test.data { 185 | n, err := WriteDelimited(&buf, msg) 186 | if err != nil { 187 | // Assumption: TestReadDelimited and TestWriteDelimited are sufficient 188 | // and inputs for this test are explicitly exercised there. 189 | t.Fatalf("WriteDelimited(buf, %v[%d]) = ?, %v; wanted ?, nil", test.data, i, err) 190 | } 191 | written += n 192 | } 193 | var read int 194 | for i, msg := range test.data { 195 | out := proto.Clone(msg) 196 | proto.Reset(out) 197 | n, err := ReadDelimited(&buf, out) 198 | read += n 199 | if !cmp.Equal(out, msg, protocmp.Transform()) { 200 | t.Errorf("out = %v; want %v[%d] = %#v", out, test, i, msg) 201 | } 202 | if got, want := err, error(nil); !errors.Is(got, want) { 203 | t.Errorf("err = %v, want %v", got, want) 204 | } 205 | } 206 | if read != written { 207 | t.Errorf("%v read = %d; want %d", test, read, written) 208 | } 209 | }) 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /pbutil/decode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Matt T. Proud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package pbutil 16 | 17 | import ( 18 | "io" 19 | 20 | "google.golang.org/protobuf/encoding/protodelim" 21 | "google.golang.org/protobuf/proto" 22 | ) 23 | 24 | type countingReader struct { 25 | r io.Reader 26 | n int 27 | } 28 | 29 | // implements protodelim.Reader 30 | func (r *countingReader) Read(p []byte) (n int, err error) { 31 | n, err = r.r.Read(p) 32 | if n > 0 { 33 | r.n += n 34 | } 35 | return n, err 36 | } 37 | 38 | // implements protodelim.Reader 39 | func (c *countingReader) ReadByte() (byte, error) { 40 | var buf [1]byte 41 | for { 42 | n, err := c.Read(buf[:]) 43 | if n == 0 && err == nil { 44 | // io.Reader states: Callers should treat a return of 0 and nil as 45 | // indicating that nothing happened; in particular it does not 46 | // indicate EOF. 47 | continue 48 | } 49 | return buf[0], err 50 | } 51 | } 52 | 53 | // ReadDelimited decodes a message from the provided length-delimited stream, 54 | // where the length is encoded as 32-bit varint prefix to the message body. 55 | // It returns the total number of bytes read and any applicable error. This is 56 | // roughly equivalent to the companion Java API's 57 | // MessageLite#parseDelimitedFrom. As per the reader contract, this function 58 | // calls r.Read repeatedly as required until exactly one message including its 59 | // prefix is read and decoded (or an error has occurred). The function never 60 | // reads more bytes from the stream than required. The function never returns 61 | // an error if a message has been read and decoded correctly, even if the end 62 | // of the stream has been reached in doing so. In that case, any subsequent 63 | // calls return (0, io.EOF). 64 | func ReadDelimited(r io.Reader, m proto.Message) (n int, err error) { 65 | cr := &countingReader{r: r} 66 | opts := protodelim.UnmarshalOptions{ 67 | MaxSize: -1, 68 | } 69 | err = opts.UnmarshalFrom(cr, m) 70 | return cr.n, err 71 | } 72 | -------------------------------------------------------------------------------- /pbutil/decode_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Matt T. Proud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package pbutil 16 | 17 | import ( 18 | "bytes" 19 | "encoding/binary" 20 | "errors" 21 | "io" 22 | "testing" 23 | "testing/iotest" 24 | 25 | "github.com/google/go-cmp/cmp" 26 | "github.com/matttproud/golang_protobuf_extensions/v2/testdata" 27 | "google.golang.org/protobuf/proto" 28 | "google.golang.org/protobuf/testing/protocmp" 29 | ) 30 | 31 | func TestReadDelimitedIllegalVarint(t *testing.T) { 32 | var tests = []struct { 33 | name string 34 | in []byte 35 | n int 36 | }{ 37 | { 38 | name: "all 0xFF", 39 | in: []byte{255, 255, 255, 255, 255}, 40 | n: 5, 41 | }, 42 | 43 | // Ensure ReadDelimited eventually stops parsing a varint instead of 44 | // looping as long as the input bytes have the continuation bit set. 45 | { 46 | name: "infinite continuation bits", 47 | in: bytes.Repeat([]byte{255}, 2*binary.MaxVarintLen64), 48 | n: binary.MaxVarintLen64, 49 | }, 50 | } 51 | for _, test := range tests { 52 | t.Run(test.name, func(t *testing.T) { 53 | n, err := ReadDelimited(bytes.NewReader(test.in), nil) 54 | if got, want := n, test.n; !cmp.Equal(got, want) { 55 | t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %#v, ?", test.in, got, want) 56 | } 57 | if err == nil { 58 | t.Errorf("ReadDelimited(%#v) unexpectedly did not result in an error", test.in) 59 | } 60 | }) 61 | } 62 | } 63 | 64 | func TestReadDelimitedPrematureHeader(t *testing.T) { 65 | var data = []byte{128, 5} // 256 + 256 + 128 66 | n, err := ReadDelimited(bytes.NewReader(data[0:1]), nil) 67 | if got, want := n, 1; !cmp.Equal(got, want) { 68 | t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %#v, ?", data[0:1], got, want) 69 | } 70 | if got, want := err, io.ErrUnexpectedEOF; !errors.Is(got, want) { 71 | t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data[0:1], got, want) 72 | } 73 | } 74 | 75 | func TestReadDelimitedPrematureBody(t *testing.T) { 76 | var data = []byte{128, 5, 0, 0, 0} // 256 + 256 + 128 77 | n, err := ReadDelimited(bytes.NewReader(data[:]), nil) 78 | if got, want := n, 5; !cmp.Equal(got, want) { 79 | t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %#v, ?", data, got, want) 80 | } 81 | if got, want := err, io.ErrUnexpectedEOF; !errors.Is(got, want) { 82 | t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data, got, want) 83 | } 84 | } 85 | 86 | func TestReadDelimitedPrematureHeaderIncremental(t *testing.T) { 87 | var data = []byte{128, 5} // 256 + 256 + 128 88 | n, err := ReadDelimited(iotest.OneByteReader(bytes.NewReader(data[0:1])), nil) 89 | if got, want := n, 1; !cmp.Equal(got, want) { 90 | t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %#v, ?", data[0:1], got, want) 91 | } 92 | if got, want := err, io.ErrUnexpectedEOF; !errors.Is(got, want) { 93 | t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data[0:1], got, want) 94 | } 95 | } 96 | 97 | func TestReadDelimitedPrematureBodyIncremental(t *testing.T) { 98 | var data = []byte{128, 5, 0, 0, 0} // 256 + 256 + 128 99 | n, err := ReadDelimited(iotest.OneByteReader(bytes.NewReader(data[:])), nil) 100 | if got, want := n, 5; !cmp.Equal(got, want) { 101 | t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %#v, ?", data, got, want) 102 | } 103 | if got, want := err, io.ErrUnexpectedEOF; !errors.Is(got, want) { 104 | t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data, got, want) 105 | } 106 | } 107 | 108 | var _ io.Reader = (*firstReadNoop)(nil) 109 | 110 | type firstReadNoop struct { 111 | read bool 112 | r io.Reader 113 | } 114 | 115 | func (r *firstReadNoop) Read(p []byte) (int, error) { 116 | if !r.read { 117 | r.read = true 118 | return 0, nil 119 | } 120 | return r.r.Read(p) 121 | } 122 | 123 | func TestFirstNoop(t *testing.T) { 124 | r := &firstReadNoop{ 125 | r: bytes.NewReader([]byte{6, 26, 4, 110, 111, 111, 112}), 126 | } 127 | var msg testdata.Record 128 | n, err := ReadDelimited(r, &msg) 129 | if got, want := n, 7; !cmp.Equal(got, want) { 130 | t.Errorf("ReadDelimited(r, &msg) n = %v, want %v", got, want) 131 | } 132 | if got, want := err, error(nil); !errors.Is(got, want) { 133 | t.Errorf("ReadDelimited(r, &msg) err = %v, want %v", got, want) 134 | } 135 | if got, want := &msg, (&testdata.Record{Third: proto.String("noop")}); !cmp.Equal(got, want, protocmp.Transform()) { 136 | t.Errorf("ReadDelimited(r, &msg) msg = %v, want %v", got, want) 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /pbutil/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Matt T. Proud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package pbutil provides record length-delimited Protocol Buffer streaming. 16 | package pbutil 17 | -------------------------------------------------------------------------------- /pbutil/encode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Matt T. Proud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package pbutil 16 | 17 | import ( 18 | "io" 19 | 20 | "google.golang.org/protobuf/encoding/protodelim" 21 | "google.golang.org/protobuf/proto" 22 | ) 23 | 24 | // WriteDelimited encodes and dumps a message to the provided writer prefixed 25 | // with a 32-bit varint indicating the length of the encoded message, producing 26 | // a length-delimited record stream, which can be used to chain together 27 | // encoded messages of the same type together in a file. It returns the total 28 | // number of bytes written and any applicable error. This is roughly 29 | // equivalent to the companion Java API's MessageLite#writeDelimitedTo. 30 | func WriteDelimited(w io.Writer, m proto.Message) (n int, err error) { 31 | return protodelim.MarshalTo(w, m) 32 | } 33 | -------------------------------------------------------------------------------- /pbutil/encode_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Matt T. Proud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package pbutil 16 | 17 | import ( 18 | "bytes" 19 | "errors" 20 | "testing" 21 | 22 | "github.com/google/go-cmp/cmp" 23 | "github.com/matttproud/golang_protobuf_extensions/v2/testdata" 24 | "google.golang.org/protobuf/proto" 25 | ) 26 | 27 | func TestWriteDelimitedMarshalErr(t *testing.T) { 28 | // data will not successfully marshal due to required field not being set, 29 | // but with the way that package proto is designed at the moment this only 30 | // matches on a coarse-grained error type. 31 | data := new(testdata.Required) 32 | var buf bytes.Buffer 33 | n, err := WriteDelimited(&buf, data) 34 | if got, want := n, 0; !cmp.Equal(got, want) { 35 | t.Errorf("WriteDelimited(buf, %#v) = %#v, ?; want = %#v, ?", data, got, want) 36 | } 37 | if got, want := err, proto.Error; !errors.Is(got, want) { 38 | t.Errorf("WriteDelimited(buf, %#v) = ?, %#v; want = ?, %#v", data, got, want) 39 | } 40 | } 41 | 42 | var errWrite = errors.New("pbutil: can't write") 43 | 44 | type cantWrite struct{} 45 | 46 | func (cantWrite) Write([]byte) (int, error) { return 0, errWrite } 47 | 48 | func TestWriteDelimitedWriteErr(t *testing.T) { 49 | data := new(testdata.Record) 50 | var buf cantWrite 51 | n, err := WriteDelimited(buf, data) 52 | if got, want := n, 0; !cmp.Equal(got, want) { 53 | t.Errorf("WriteDelimited(buf, %#v) = %#v, ?; want = %#v, ?", data, got, want) 54 | } 55 | if got, want := err, errWrite; !errors.Is(got, want) { 56 | t.Errorf("WriteDelimited(buf, %#v) = ?, %#v; want = ?, %#v", data, got, want) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /testdata/test.pb.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Matt T. Proud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by protoc-gen-go. DO NOT EDIT. 16 | // versions: 17 | // protoc-gen-go v1.28.1-devel 18 | // protoc v3.21.6 19 | // source: test.proto 20 | 21 | package testdata 22 | 23 | import ( 24 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 25 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 26 | reflect "reflect" 27 | sync "sync" 28 | ) 29 | 30 | const ( 31 | // Verify that this generated code is sufficiently up-to-date. 32 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 33 | // Verify that runtime/protoimpl is sufficiently up-to-date. 34 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 35 | ) 36 | 37 | type Record struct { 38 | state protoimpl.MessageState 39 | sizeCache protoimpl.SizeCache 40 | unknownFields protoimpl.UnknownFields 41 | 42 | First *uint64 `protobuf:"varint,1,opt,name=first" json:"first,omitempty"` 43 | Third *string `protobuf:"bytes,3,opt,name=third" json:"third,omitempty"` 44 | } 45 | 46 | func (x *Record) Reset() { 47 | *x = Record{} 48 | if protoimpl.UnsafeEnabled { 49 | mi := &file_test_proto_msgTypes[0] 50 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 51 | ms.StoreMessageInfo(mi) 52 | } 53 | } 54 | 55 | func (x *Record) String() string { 56 | return protoimpl.X.MessageStringOf(x) 57 | } 58 | 59 | func (*Record) ProtoMessage() {} 60 | 61 | func (x *Record) ProtoReflect() protoreflect.Message { 62 | mi := &file_test_proto_msgTypes[0] 63 | if protoimpl.UnsafeEnabled && x != nil { 64 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 65 | if ms.LoadMessageInfo() == nil { 66 | ms.StoreMessageInfo(mi) 67 | } 68 | return ms 69 | } 70 | return mi.MessageOf(x) 71 | } 72 | 73 | // Deprecated: Use Record.ProtoReflect.Descriptor instead. 74 | func (*Record) Descriptor() ([]byte, []int) { 75 | return file_test_proto_rawDescGZIP(), []int{0} 76 | } 77 | 78 | func (x *Record) GetFirst() uint64 { 79 | if x != nil && x.First != nil { 80 | return *x.First 81 | } 82 | return 0 83 | } 84 | 85 | func (x *Record) GetThird() string { 86 | if x != nil && x.Third != nil { 87 | return *x.Third 88 | } 89 | return "" 90 | } 91 | 92 | type Required struct { 93 | state protoimpl.MessageState 94 | sizeCache protoimpl.SizeCache 95 | unknownFields protoimpl.UnknownFields 96 | 97 | First *uint64 `protobuf:"varint,1,req,name=first" json:"first,omitempty"` 98 | } 99 | 100 | func (x *Required) Reset() { 101 | *x = Required{} 102 | if protoimpl.UnsafeEnabled { 103 | mi := &file_test_proto_msgTypes[1] 104 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 105 | ms.StoreMessageInfo(mi) 106 | } 107 | } 108 | 109 | func (x *Required) String() string { 110 | return protoimpl.X.MessageStringOf(x) 111 | } 112 | 113 | func (*Required) ProtoMessage() {} 114 | 115 | func (x *Required) ProtoReflect() protoreflect.Message { 116 | mi := &file_test_proto_msgTypes[1] 117 | if protoimpl.UnsafeEnabled && x != nil { 118 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 119 | if ms.LoadMessageInfo() == nil { 120 | ms.StoreMessageInfo(mi) 121 | } 122 | return ms 123 | } 124 | return mi.MessageOf(x) 125 | } 126 | 127 | // Deprecated: Use Required.ProtoReflect.Descriptor instead. 128 | func (*Required) Descriptor() ([]byte, []int) { 129 | return file_test_proto_rawDescGZIP(), []int{1} 130 | } 131 | 132 | func (x *Required) GetFirst() uint64 { 133 | if x != nil && x.First != nil { 134 | return *x.First 135 | } 136 | return 0 137 | } 138 | 139 | var File_test_proto protoreflect.FileDescriptor 140 | 141 | var file_test_proto_rawDesc = []byte{ 142 | 0x0a, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x74, 0x65, 143 | 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3a, 0x0a, 0x06, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 144 | 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x72, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 145 | 0x05, 0x66, 0x69, 0x72, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x68, 0x69, 0x72, 0x64, 0x18, 146 | 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x68, 0x69, 0x72, 0x64, 0x4a, 0x04, 0x08, 0x02, 147 | 0x10, 0x03, 0x22, 0x20, 0x0a, 0x08, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x14, 148 | 0x0a, 0x05, 0x66, 0x69, 0x72, 0x73, 0x74, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x05, 0x66, 149 | 0x69, 0x72, 0x73, 0x74, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 150 | 0x6f, 0x6d, 0x2f, 0x6d, 0x61, 0x74, 0x74, 0x74, 0x70, 0x72, 0x6f, 0x75, 0x64, 0x2f, 0x67, 0x6f, 151 | 0x6c, 0x61, 0x6e, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x5f, 0x65, 0x78, 152 | 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 153 | 0x61, 154 | } 155 | 156 | var ( 157 | file_test_proto_rawDescOnce sync.Once 158 | file_test_proto_rawDescData = file_test_proto_rawDesc 159 | ) 160 | 161 | func file_test_proto_rawDescGZIP() []byte { 162 | file_test_proto_rawDescOnce.Do(func() { 163 | file_test_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_proto_rawDescData) 164 | }) 165 | return file_test_proto_rawDescData 166 | } 167 | 168 | var file_test_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 169 | var file_test_proto_goTypes = []interface{}{ 170 | (*Record)(nil), // 0: testdata.Record 171 | (*Required)(nil), // 1: testdata.Required 172 | } 173 | var file_test_proto_depIdxs = []int32{ 174 | 0, // [0:0] is the sub-list for method output_type 175 | 0, // [0:0] is the sub-list for method input_type 176 | 0, // [0:0] is the sub-list for extension type_name 177 | 0, // [0:0] is the sub-list for extension extendee 178 | 0, // [0:0] is the sub-list for field type_name 179 | } 180 | 181 | func init() { file_test_proto_init() } 182 | func file_test_proto_init() { 183 | if File_test_proto != nil { 184 | return 185 | } 186 | if !protoimpl.UnsafeEnabled { 187 | file_test_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 188 | switch v := v.(*Record); i { 189 | case 0: 190 | return &v.state 191 | case 1: 192 | return &v.sizeCache 193 | case 2: 194 | return &v.unknownFields 195 | default: 196 | return nil 197 | } 198 | } 199 | file_test_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 200 | switch v := v.(*Required); i { 201 | case 0: 202 | return &v.state 203 | case 1: 204 | return &v.sizeCache 205 | case 2: 206 | return &v.unknownFields 207 | default: 208 | return nil 209 | } 210 | } 211 | } 212 | type x struct{} 213 | out := protoimpl.TypeBuilder{ 214 | File: protoimpl.DescBuilder{ 215 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 216 | RawDescriptor: file_test_proto_rawDesc, 217 | NumEnums: 0, 218 | NumMessages: 2, 219 | NumExtensions: 0, 220 | NumServices: 0, 221 | }, 222 | GoTypes: file_test_proto_goTypes, 223 | DependencyIndexes: file_test_proto_depIdxs, 224 | MessageInfos: file_test_proto_msgTypes, 225 | }.Build() 226 | File_test_proto = out.File 227 | file_test_proto_rawDesc = nil 228 | file_test_proto_goTypes = nil 229 | file_test_proto_depIdxs = nil 230 | } 231 | -------------------------------------------------------------------------------- /testdata/test.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Matt T. Proud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto2"; 16 | 17 | package testdata; 18 | 19 | option go_package = "github.com/matttproud/golang_protobuf_extensions/v2/testdata"; 20 | 21 | message Record { 22 | optional uint64 first = 1; 23 | reserved 2; 24 | optional string third = 3; 25 | } 26 | 27 | message Required { 28 | required uint64 first = 1; 29 | } 30 | --------------------------------------------------------------------------------