├── .github └── workflows │ └── ci-unit.yaml ├── .gitignore ├── LICENSE ├── NOTICE ├── README.md ├── benchmark ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── github │ └── splunk │ └── lightproto │ └── benchmark │ ├── ProtoBenchmark.java │ ├── SimpleBenchmark.java │ └── StringEncodingBenchmark.java ├── code-generator ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── splunk │ │ └── lightproto │ │ └── generator │ │ ├── LightProto.java │ │ ├── LightProtoAbstractRepeated.java │ │ ├── LightProtoBooleanField.java │ │ ├── LightProtoBytesField.java │ │ ├── LightProtoEnum.java │ │ ├── LightProtoEnumField.java │ │ ├── LightProtoField.java │ │ ├── LightProtoGenerator.java │ │ ├── LightProtoMessage.java │ │ ├── LightProtoMessageField.java │ │ ├── LightProtoNumberField.java │ │ ├── LightProtoRepeatedBytesField.java │ │ ├── LightProtoRepeatedEnumField.java │ │ ├── LightProtoRepeatedMessageField.java │ │ ├── LightProtoRepeatedNumberField.java │ │ ├── LightProtoRepeatedStringField.java │ │ ├── LightProtoStringField.java │ │ └── Util.java │ └── resources │ └── com │ └── github │ └── splunk │ └── lightproto │ └── generator │ └── LightProtoCodec.java ├── license-header.txt ├── maven-plugin ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── github │ └── splunk │ └── lightproto │ └── maven │ └── plugin │ └── LightProtoMojo.java ├── pom.xml └── tests ├── pom.xml └── src ├── main └── proto │ ├── PulsarApi.proto │ ├── PulsarMarkers.proto │ ├── Test.proto │ ├── addressbook.proto │ ├── bytes.proto │ ├── enums.proto │ ├── messages.proto │ ├── numbers.proto │ ├── repeated_numbers.proto │ ├── required.proto │ └── strings.proto └── test └── java └── com └── github └── splunk └── lightproto └── tests ├── AddressBookTest.java ├── BytesTest.java ├── EnumsTest.java ├── LightProtoCodecTest.java ├── MessagesTest.java ├── NumbersTest.java ├── RepeatedNumbersTest.java ├── RequiredTest.java └── StringsTest.java /.github/workflows/ci-unit.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020 Splunk Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | name: CI - Unit 18 | on: 19 | pull_request: 20 | branches: 21 | - master 22 | push: 23 | branches: 24 | - branch-* 25 | 26 | jobs: 27 | 28 | unit-tests: 29 | name: 30 | runs-on: ubuntu-latest 31 | container: 32 | image: maven:3.6.3-jdk-11 33 | timeout-minutes: 30 34 | 35 | steps: 36 | 37 | - name: checkout 38 | uses: actions/checkout@v2 39 | with: 40 | fetch-depth: 25 41 | ref: ${{ github.event.pull_request.head.sha }} 42 | 43 | - name: Cache local Maven repository 44 | uses: actions/cache@v2 45 | with: 46 | path: ~/.m2/repository 47 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 48 | restore-keys: | 49 | ${{ runner.os }}-maven- 50 | 51 | - name: build and run tests 52 | run: mvn -B -ntp -Dgpg.skip license:check install 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .project 3 | .settings 4 | .classpath 5 | .idea 6 | **/*.iml 7 | **/*.versionsBackup 8 | 9 | .DS_Store 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | 2 | LightProto 3 | Copyright 2020 Splunk Inc. 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### IMPORTANT 2 | Starting 21st of February 2024, splunk/lightproto project is archived. 3 | That means Splunk organization is no longer maintaining and supporting lightproto features/project. 4 | 5 | ### Light Proto serialization 6 | 7 | ### Features 8 | 9 | 1. Generate the fastest possible Java code for Protobuf SerDe 10 | 1. 100% Compatible with proto2 definition and wire protocol 11 | 1. Zero-copy deserialization using Netty ByteBuf 12 | 1. Deserialize from direct memory 13 | 1. Zero heap allocations in serialization / deserialization 14 | 1. Lazy deserialization of strings and bytes 15 | 1. Reusable mutable objects 16 | 1. No runtime dependency library 17 | 1. Java based code generator with Maven plugin 18 | 19 | ### Benchmark 20 | 21 | ``` 22 | java -jar benchmark/target/benchmarks.jar 23 | 24 | Benchmark Mode Cnt Score Error Units 25 | ProtoBenchmark.lightProtoDeserialize thrpt 3 8.445 ± 1.734 ops/us 26 | ProtoBenchmark.lightProtoSerialize thrpt 3 4.056 ± 1.628 ops/us 27 | ProtoBenchmark.protobufDeserialize thrpt 3 2.465 ± 0.682 ops/us 28 | ProtoBenchmark.protobufSerialize thrpt 3 2.242 ± 0.186 ops/us 29 | SimpleBenchmark.lightProtoDeserialize thrpt 3 37.414 ± 4.980 ops/us 30 | SimpleBenchmark.lightProtoDeserializeReadString thrpt 3 17.367 ± 1.790 ops/us 31 | SimpleBenchmark.lightProtoSerialize thrpt 3 35.473 ± 6.325 ops/us 32 | SimpleBenchmark.protobufDeserialize thrpt 3 8.255 ± 1.104 ops/us 33 | SimpleBenchmark.protobufSerialize thrpt 3 18.960 ± 4.626 ops/us 34 | StringEncodingBenchmark.jdkEncoding thrpt 10 14.031 ± 0.394 ops/us 35 | StringEncodingBenchmark.jdkEncodingAscii thrpt 10 19.279 ± 0.448 ops/us 36 | StringEncodingBenchmark.nettyEncoding thrpt 10 27.273 ± 0.988 ops/us 37 | StringEncodingBenchmark.nettyEncodingAscii thrpt 10 36.140 ± 0.693 ops/us 38 | ``` 39 | -------------------------------------------------------------------------------- /benchmark/pom.xml: -------------------------------------------------------------------------------- 1 | 18 | 21 | 4.0.0 22 | 23 | 24 | com.github.splunk.lightproto 25 | lightproto 26 | 0.5-SNAPSHOT 27 | .. 28 | 29 | 30 | lightproto-benchmark 31 | jar 32 | 33 | 34 | 35 | ${project.groupId} 36 | lightproto-tests 37 | ${project.version} 38 | 39 | 40 | io.netty 41 | netty-buffer 42 | 43 | 44 | org.openjdk.jmh 45 | jmh-core 46 | 47 | 48 | org.openjdk.jmh 49 | jmh-generator-annprocess 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-shade-plugin 58 | 3.2.1 59 | 60 | 61 | package 62 | 63 | shade 64 | 65 | 66 | benchmarks 67 | 68 | 70 | org.openjdk.jmh.Main 71 | 72 | 73 | 74 | 75 | *:* 76 | 77 | META-INF/*.SF 78 | META-INF/*.DSA 79 | META-INF/*.RSA 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /benchmark/src/main/java/com/github/splunk/lightproto/benchmark/ProtoBenchmark.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.benchmark; 17 | 18 | import com.google.protobuf.CodedOutputStream; 19 | import com.github.splunk.lightproto.tests.AddressBook; 20 | import com.github.splunk.lightproto.tests.AddressBookProtos; 21 | import com.github.splunk.lightproto.tests.Person; 22 | import io.netty.buffer.ByteBuf; 23 | import io.netty.buffer.PooledByteBufAllocator; 24 | import io.netty.buffer.Unpooled; 25 | import org.openjdk.jmh.annotations.*; 26 | import org.openjdk.jmh.infra.Blackhole; 27 | 28 | import java.util.concurrent.TimeUnit; 29 | 30 | @State(Scope.Benchmark) 31 | @Warmup(iterations = 3) 32 | @OutputTimeUnit(TimeUnit.MICROSECONDS) 33 | @Measurement(iterations = 3) 34 | @Fork(value = 1) 35 | public class ProtoBenchmark { 36 | 37 | final static byte[] serialized; 38 | 39 | static { 40 | AddressBook ab = new AddressBook(); 41 | Person p1 = ab.addPerson(); 42 | p1.setName("name"); 43 | p1.setEmail("name@example.com"); 44 | p1.setId(5); 45 | Person.PhoneNumber p1_pn1 = p1.addPhone(); 46 | p1_pn1.setNumber("xxx-zzz-yyyyy"); 47 | p1_pn1.setType(Person.PhoneType.HOME); 48 | 49 | Person.PhoneNumber p1_pn2 = p1.addPhone(); 50 | p1_pn2.setNumber("xxx-zzz-yyyyy"); 51 | p1_pn2.setType(Person.PhoneType.MOBILE); 52 | 53 | Person p2 = ab.addPerson(); 54 | p2.setName("name 2"); 55 | p2.setEmail("name2@example.com"); 56 | p2.setId(6); 57 | 58 | Person.PhoneNumber p2_pn1 = p2.addPhone(); 59 | p2_pn1.setNumber("xxx-zzz-yyyyy"); 60 | p2_pn1.setType(Person.PhoneType.HOME); 61 | 62 | serialized = new byte[ab.getSerializedSize()]; 63 | ab.writeTo(Unpooled.wrappedBuffer(serialized).resetWriterIndex()); 64 | } 65 | 66 | private final AddressBook frame = new AddressBook(); 67 | 68 | private final ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer(1024); 69 | byte[] data = new byte[1024]; 70 | private final ByteBuf serializeByteBuf = Unpooled.wrappedBuffer(serialized); 71 | 72 | @Benchmark 73 | public void protobufSerialize(Blackhole bh) throws Exception { 74 | AddressBookProtos.AddressBook.Builder pbab = AddressBookProtos.AddressBook.newBuilder(); 75 | AddressBookProtos.Person.Builder pb_p1 = AddressBookProtos.Person.newBuilder(); 76 | pb_p1.setName("name 1"); 77 | pb_p1.setEmail("name1@example.com"); 78 | pb_p1.setId(5); 79 | AddressBookProtos.Person.PhoneNumber.Builder pb1_pn1 = AddressBookProtos.Person.PhoneNumber.newBuilder(); 80 | pb1_pn1.setNumber("xxx-zzz-1111"); 81 | pb1_pn1.setType(AddressBookProtos.Person.PhoneType.HOME); 82 | 83 | AddressBookProtos.Person.PhoneNumber.Builder pb1_pn2 = AddressBookProtos.Person.PhoneNumber.newBuilder(); 84 | pb1_pn2.setNumber("xxx-zzz-2222"); 85 | pb1_pn2.setType(AddressBookProtos.Person.PhoneType.MOBILE); 86 | 87 | pb_p1.addPhone(pb1_pn1); 88 | pb_p1.addPhone(pb1_pn2); 89 | 90 | AddressBookProtos.Person.Builder pb_p2 = AddressBookProtos.Person.newBuilder(); 91 | pb_p2.setName("name 2"); 92 | pb_p2.setEmail("name2@example.com"); 93 | pb_p2.setId(6); 94 | 95 | AddressBookProtos.Person.PhoneNumber.Builder pb2_pn1 = AddressBookProtos.Person.PhoneNumber.newBuilder(); 96 | pb2_pn1.setNumber("xxx-zzz-2222"); 97 | pb2_pn1.setType(AddressBookProtos.Person.PhoneType.HOME); 98 | 99 | pb_p2.addPhone(pb2_pn1); 100 | 101 | pbab.addPerson(pb_p1); 102 | pbab.addPerson(pb_p2); 103 | 104 | CodedOutputStream s = CodedOutputStream.newInstance(data); 105 | pbab.build().writeTo(s); 106 | 107 | bh.consume(pbab); 108 | bh.consume(s); 109 | } 110 | 111 | @Benchmark 112 | public void lightProtoSerialize(Blackhole bh) { 113 | frame.clear(); 114 | 115 | Person p1 = frame.addPerson(); 116 | p1.setName("name"); 117 | p1.setEmail("name@example.com"); 118 | p1.setId(5); 119 | Person.PhoneNumber p1_pn1 = p1.addPhone(); 120 | p1_pn1.setNumber("xxx-zzz-yyyyy"); 121 | p1_pn1.setType(Person.PhoneType.HOME); 122 | 123 | Person.PhoneNumber p1_pn2 = p1.addPhone(); 124 | p1_pn2.setNumber("xxx-zzz-yyyyy"); 125 | p1_pn2.setType(Person.PhoneType.MOBILE); 126 | 127 | Person p2 = frame.addPerson(); 128 | p2.setName("name 2"); 129 | p2.setEmail("name2@example.com"); 130 | p2.setId(6); 131 | 132 | Person.PhoneNumber p2_pn1 = p1.addPhone(); 133 | p2_pn1.setNumber("xxx-zzz-yyyyy"); 134 | p2_pn1.setType(Person.PhoneType.HOME); 135 | 136 | frame.writeTo(buffer); 137 | buffer.clear(); 138 | 139 | bh.consume(frame); 140 | } 141 | 142 | @Benchmark 143 | public void protobufDeserialize(Blackhole bh) throws Exception { 144 | AddressBookProtos.AddressBook ab = AddressBookProtos.AddressBook.newBuilder().mergeFrom(serialized).build(); 145 | bh.consume(ab); 146 | } 147 | 148 | @Benchmark 149 | public void lightProtoDeserialize(Blackhole bh) { 150 | frame.parseFrom(serializeByteBuf, serializeByteBuf.readableBytes()); 151 | serializeByteBuf.resetReaderIndex(); 152 | bh.consume(frame); 153 | } 154 | 155 | 156 | } 157 | -------------------------------------------------------------------------------- /benchmark/src/main/java/com/github/splunk/lightproto/benchmark/SimpleBenchmark.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.benchmark; 17 | 18 | import com.google.protobuf.CodedOutputStream; 19 | import com.github.splunk.lightproto.tests.Frame; 20 | import com.github.splunk.lightproto.tests.Point; 21 | import com.github.splunk.lightproto.tests.Test; 22 | import io.netty.buffer.ByteBuf; 23 | import io.netty.buffer.PooledByteBufAllocator; 24 | import io.netty.buffer.Unpooled; 25 | import org.openjdk.jmh.annotations.*; 26 | import org.openjdk.jmh.infra.Blackhole; 27 | 28 | import java.io.IOException; 29 | import java.util.concurrent.TimeUnit; 30 | 31 | @State(Scope.Benchmark) 32 | @Warmup(iterations = 3) 33 | @OutputTimeUnit(TimeUnit.MICROSECONDS) 34 | @Measurement(iterations = 3) 35 | @Fork(value = 1) 36 | public class SimpleBenchmark { 37 | 38 | final static byte[] serialized; 39 | 40 | static { 41 | Test.Point.Builder b = Test.Point.newBuilder(); 42 | b.setX(1); 43 | b.setY(2); 44 | b.setZ(3); 45 | 46 | Test.Frame.Builder frameBuilder = Test.Frame.newBuilder(); 47 | frameBuilder.setName("xyz"); 48 | frameBuilder.setPoint(b.build()); 49 | 50 | Test.Frame frame = frameBuilder.build(); 51 | int size = frame.getSerializedSize(); 52 | 53 | serialized = new byte[size]; 54 | CodedOutputStream s = CodedOutputStream.newInstance(serialized); 55 | try { 56 | frame.writeTo(s); 57 | } catch (IOException ignored) { 58 | } 59 | } 60 | 61 | byte[] data = new byte[1024]; 62 | Frame frame = new Frame(); 63 | ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer(1024); 64 | private final ByteBuf serializeByteBuf = Unpooled.wrappedBuffer(serialized); 65 | 66 | @Benchmark 67 | public void protobufSerialize(Blackhole bh) throws Exception { 68 | Test.Point.Builder b = Test.Point.newBuilder(); 69 | b.setX(1); 70 | b.setY(2); 71 | b.setZ(3); 72 | 73 | Test.Frame.Builder frameBuilder = Test.Frame.newBuilder(); 74 | frameBuilder.setName("xyz"); 75 | frameBuilder.setPoint(b.build()); 76 | 77 | Test.Frame frame = frameBuilder.build(); 78 | 79 | CodedOutputStream s = CodedOutputStream.newInstance(data); 80 | frame.writeTo(s); 81 | bh.consume(b); 82 | bh.consume(s); 83 | bh.consume(frame); 84 | } 85 | 86 | @Benchmark 87 | public void lightProtoSerialize(Blackhole bh) { 88 | frame.clear(); 89 | Point p = frame.setPoint(); 90 | p.setX(1); 91 | p.setY(2); 92 | p.setZ(3); 93 | frame.setName("xyz"); 94 | 95 | p.writeTo(buffer); 96 | buffer.clear(); 97 | 98 | bh.consume(p); 99 | } 100 | 101 | @Benchmark 102 | public void protobufDeserialize(Blackhole bh) throws Exception { 103 | Test.Frame.Builder b = Test.Frame.newBuilder().mergeFrom(serialized); 104 | Test.Frame f = b.build(); 105 | f.getName(); 106 | bh.consume(f); 107 | } 108 | 109 | @Benchmark 110 | public void lightProtoDeserialize(Blackhole bh) { 111 | frame.parseFrom(serializeByteBuf, serializeByteBuf.readableBytes()); 112 | serializeByteBuf.resetReaderIndex(); 113 | bh.consume(frame); 114 | } 115 | 116 | @Benchmark 117 | public void lightProtoDeserializeReadString(Blackhole bh) { 118 | frame.parseFrom(serializeByteBuf, serializeByteBuf.readableBytes()); 119 | bh.consume(frame.getName()); 120 | serializeByteBuf.resetReaderIndex(); 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /benchmark/src/main/java/com/github/splunk/lightproto/benchmark/StringEncodingBenchmark.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.benchmark; 17 | 18 | import java.nio.charset.StandardCharsets; 19 | import java.util.concurrent.TimeUnit; 20 | 21 | import org.openjdk.jmh.annotations.Benchmark; 22 | import org.openjdk.jmh.annotations.Fork; 23 | import org.openjdk.jmh.annotations.Measurement; 24 | import org.openjdk.jmh.annotations.OutputTimeUnit; 25 | import org.openjdk.jmh.annotations.Scope; 26 | import org.openjdk.jmh.annotations.State; 27 | import org.openjdk.jmh.annotations.Warmup; 28 | import org.openjdk.jmh.infra.Blackhole; 29 | 30 | import io.netty.buffer.ByteBuf; 31 | import io.netty.buffer.ByteBufAllocator; 32 | import io.netty.buffer.ByteBufUtil; 33 | 34 | @State(Scope.Benchmark) 35 | @Warmup(iterations = 3) 36 | @OutputTimeUnit(TimeUnit.MICROSECONDS) 37 | @Measurement(iterations = 10) 38 | @Fork(value = 1) 39 | public class StringEncodingBenchmark { 40 | 41 | private static final String testString = "UTF16 Ελληνικά Русский 日本語"; 42 | private static final String testStringAscii = "Neque porro quisquam est qui dolorem ipsum"; 43 | 44 | @Benchmark 45 | public void jdkEncoding(Blackhole bh) { 46 | byte[] bytes = testString.getBytes(StandardCharsets.UTF_8); 47 | bh.consume(bytes); 48 | } 49 | 50 | ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer(1024); 51 | 52 | @Benchmark 53 | public void nettyEncoding(Blackhole bh) { 54 | buffer.clear(); 55 | ByteBufUtil.writeUtf8(buffer, testString); 56 | bh.consume(buffer); 57 | } 58 | 59 | @Benchmark 60 | public void jdkEncodingAscii(Blackhole bh) { 61 | byte[] bytes = testStringAscii.getBytes(StandardCharsets.UTF_8); 62 | bh.consume(bytes); 63 | } 64 | 65 | @Benchmark 66 | public void nettyEncodingAscii(Blackhole bh) { 67 | buffer.clear(); 68 | ByteBufUtil.writeUtf8(buffer, testStringAscii); 69 | bh.consume(buffer); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /code-generator/pom.xml: -------------------------------------------------------------------------------- 1 | 18 | 20 | 4.0.0 21 | 22 | 23 | com.github.splunk.lightproto 24 | lightproto 25 | 0.5-SNAPSHOT 26 | .. 27 | 28 | 29 | lightproto-code-generator 30 | jar 31 | 32 | 33 | 34 | io.protostuff 35 | protostuff-parser 36 | 37 | 38 | 39 | org.slf4j 40 | slf4j-api 41 | 42 | 43 | 44 | com.google.guava 45 | guava 46 | 47 | 48 | 49 | org.jibx 50 | jibx-tools 51 | 52 | 53 | 54 | org.jboss.forge.roaster 55 | roaster-api 56 | 57 | 58 | org.jboss.forge.roaster 59 | roaster-jdt 60 | runtime 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProto.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Proto; 19 | import org.jboss.forge.roaster.Roaster; 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import java.io.*; 24 | import java.nio.file.Files; 25 | import java.util.ArrayList; 26 | import java.util.Collections; 27 | import java.util.List; 28 | import java.util.stream.Collectors; 29 | 30 | public class LightProto { 31 | 32 | private static final Logger log = LoggerFactory.getLogger(LightProto.class); 33 | private final Proto proto; 34 | private final String outerClassName; 35 | private final boolean useOuterClass; 36 | private final List enums; 37 | private final List messages; 38 | 39 | public LightProto(Proto proto, String outerClassName, boolean useOuterClass) { 40 | this.proto = proto; 41 | this.outerClassName = outerClassName; 42 | this.useOuterClass = useOuterClass; 43 | this.enums = proto.getEnumGroups().stream().map(LightProtoEnum::new).collect(Collectors.toList()); 44 | this.messages = proto.getMessages().stream().map(m -> new LightProtoMessage(m, useOuterClass)).collect(Collectors.toList()); 45 | } 46 | 47 | public List generate(File directory) throws IOException { 48 | directory.mkdirs(); 49 | 50 | if (useOuterClass) { 51 | return generateWithSingleOuterClass(directory); 52 | } else { 53 | return generateIndividualClasses(directory); 54 | } 55 | } 56 | 57 | public List generateIndividualClasses(File outDirectory) throws IOException { 58 | List generatedFiles = new ArrayList<>(); 59 | for (LightProtoEnum e : enums) { 60 | File file = new File(outDirectory, e.getName() + ".java"); 61 | StringWriter sw = new StringWriter(); 62 | try (PrintWriter pw = new PrintWriter(sw)) { 63 | pw.format("package %s;\n", proto.getJavaPackageName()); 64 | e.generate(pw); 65 | } 66 | 67 | formatAndWrite(file, sw.toString()); 68 | log.info("LightProto generated enum {}", file); 69 | generatedFiles.add(file); 70 | } 71 | 72 | for (LightProtoMessage m : messages) { 73 | File file = new File(outDirectory, m.getName() + ".java"); 74 | StringWriter sw = new StringWriter(); 75 | try (PrintWriter pw = new PrintWriter(sw)) { 76 | pw.format("package %s;\n", proto.getJavaPackageName()); 77 | m.generate(pw); 78 | } 79 | 80 | formatAndWrite(file, sw.toString()); 81 | log.info("LightProto generated class {}", file); 82 | generatedFiles.add(file); 83 | } 84 | 85 | return generatedFiles; 86 | } 87 | 88 | public List generateWithSingleOuterClass(File outDirectory) throws IOException { 89 | File outFile = new File(outDirectory, outerClassName + ".java"); 90 | 91 | StringWriter sw = new StringWriter(); 92 | try (PrintWriter pw = new PrintWriter(sw)) { 93 | pw.format("package %s;\n", proto.getJavaPackageName()); 94 | pw.format("public final class %s {\n", outerClassName); 95 | pw.format(" private %s() {}\n", outerClassName); 96 | 97 | enums.forEach(e -> e.generate(pw)); 98 | messages.forEach(m -> m.generate(pw)); 99 | 100 | pw.println("}"); 101 | } 102 | 103 | formatAndWrite(outFile, sw.toString()); 104 | 105 | log.info("LightProto generated {}", outFile); 106 | return Collections.singletonList(outFile); 107 | } 108 | 109 | private void formatAndWrite(File file, String content) throws IOException { 110 | String formattedCode = Roaster.format(content); 111 | try (Writer w = Files.newBufferedWriter(file.toPath())) { 112 | w.write(formattedCode); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoAbstractRepeated.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Field; 19 | 20 | import java.io.PrintWriter; 21 | 22 | public abstract class LightProtoAbstractRepeated> extends LightProtoField { 23 | 24 | protected final String pluralName; 25 | protected final String singularName; 26 | 27 | public LightProtoAbstractRepeated(FieldType field, int index) { 28 | super(field, index); 29 | this.pluralName = Util.plural(ccName); 30 | this.singularName = Util.singular(ccName); 31 | } 32 | 33 | public void has(PrintWriter w) { 34 | } 35 | 36 | public void fieldClear(PrintWriter w, String enclosingType) { 37 | w.format(" public %s %s() {\n", enclosingType, Util.camelCase("clear", field.getName())); 38 | clear(w); 39 | w.format(" return this;\n"); 40 | w.format(" }\n"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoBooleanField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Field; 19 | 20 | import java.io.PrintWriter; 21 | 22 | public class LightProtoBooleanField extends LightProtoNumberField { 23 | 24 | public LightProtoBooleanField(Field field, int index) { 25 | super(field, index); 26 | } 27 | 28 | @Override 29 | public void getter(PrintWriter w) { 30 | w.format(" public %s %s() {\n", field.getJavaType(), Util.camelCase("is", ccName)); 31 | if (!field.isDefaultValueSet()) { 32 | w.format(" if (!%s()) {\n", Util.camelCase("has", ccName)); 33 | w.format(" throw new IllegalStateException(\"Field '%s' is not set\");\n", field.getName()); 34 | w.format(" }\n"); 35 | } 36 | w.format(" return %s;\n", ccName); 37 | w.format(" }\n"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoBytesField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Field; 19 | 20 | import java.io.PrintWriter; 21 | 22 | public class LightProtoBytesField extends LightProtoField { 23 | 24 | public LightProtoBytesField(Field.Bytes field, int index) { 25 | super(field, index); 26 | } 27 | 28 | @Override 29 | public void declaration(PrintWriter w) { 30 | w.format("private io.netty.buffer.ByteBuf %s = null;\n", ccName); 31 | w.format("private int _%sIdx = -1;\n", ccName); 32 | w.format("private int _%sLen = -1;\n", ccName); 33 | } 34 | 35 | @Override 36 | public void parse(PrintWriter w) { 37 | w.format("_%sLen = LightProtoCodec.readVarInt(_buffer);\n", ccName); 38 | w.format("_%sIdx = _buffer.readerIndex();\n", ccName); 39 | w.format("_buffer.skipBytes(_%sLen);\n", ccName); 40 | } 41 | 42 | @Override 43 | public void copy(PrintWriter w) { 44 | w.format("%s(_other.%s());\n", Util.camelCase("set", ccName), Util.camelCase("get", ccName)); 45 | } 46 | 47 | @Override 48 | public void setter(PrintWriter w, String enclosingType) { 49 | w.format("public %s %s(byte[] %s) {\n", enclosingType, Util.camelCase("set", ccName), ccName); 50 | w.format(" %s(io.netty.buffer.Unpooled.wrappedBuffer(%s));\n", Util.camelCase("set", ccName), ccName); 51 | w.format(" return this;\n"); 52 | w.format("}\n"); 53 | 54 | w.format("public %s %s(io.netty.buffer.ByteBuf %s) {\n", enclosingType, Util.camelCase("set", ccName), ccName); 55 | w.format(" this.%s = %s;\n", ccName, ccName); 56 | w.format(" _bitField%d |= %s;\n", bitFieldIndex(), fieldMask()); 57 | w.format(" _%sIdx = -1;\n", ccName); 58 | w.format(" _%sLen = %s.readableBytes();\n", ccName, ccName); 59 | w.format(" _cachedSize = -1;\n"); 60 | w.format(" return this;\n"); 61 | w.format("}\n"); 62 | } 63 | 64 | @Override 65 | public void getter(PrintWriter w) { 66 | w.format("public int %s() {\n", Util.camelCase("get", ccName, "size")); 67 | w.format(" if (!%s()) {\n", Util.camelCase("has", ccName)); 68 | w.format(" throw new IllegalStateException(\"Field '%s' is not set\");\n", field.getName()); 69 | w.format(" }\n"); 70 | w.format(" return _%sLen;\n", ccName); 71 | w.format("}\n"); 72 | 73 | w.format("public byte[] %s() {\n", Util.camelCase("get", ccName)); 74 | w.format(" io.netty.buffer.ByteBuf _b = %s();\n", Util.camelCase("get", ccName, "slice")); 75 | w.format(" byte[] res = new byte[_b.readableBytes()];\n"); 76 | w.format(" _b.getBytes(0, res);\n"); 77 | w.format(" return res;\n"); 78 | w.format("}\n"); 79 | 80 | w.format("public io.netty.buffer.ByteBuf %s() {\n", Util.camelCase("get", ccName, "slice")); 81 | w.format(" if (!%s()) {\n", Util.camelCase("has", ccName)); 82 | w.format(" throw new IllegalStateException(\"Field '%s' is not set\");\n", field.getName()); 83 | w.format(" }\n"); 84 | w.format(" if (%s == null) {\n", ccName); 85 | w.format(" return _parsedBuffer.slice(_%sIdx, _%sLen);\n", ccName, ccName); 86 | w.format(" } else {\n"); 87 | w.format(" return %s.slice(0, _%sLen);\n", ccName, ccName); 88 | w.format(" }\n"); 89 | w.format("}\n"); 90 | } 91 | 92 | @Override 93 | public void clear(PrintWriter w) { 94 | w.format("%s = null;\n", ccName); 95 | w.format("_%sIdx = -1;\n", ccName); 96 | w.format("_%sLen = -1;\n", ccName); 97 | } 98 | 99 | @Override 100 | public void serializedSize(PrintWriter w) { 101 | w.format("_size += %s_SIZE;\n", tagName()); 102 | w.format("_size += LightProtoCodec.computeVarIntSize(_%sLen) + _%sLen;\n", ccName, ccName); 103 | } 104 | 105 | @Override 106 | public void serialize(PrintWriter w) { 107 | w.format("LightProtoCodec.writeVarInt(_b, %s);\n", tagName()); 108 | w.format("LightProtoCodec.writeVarInt(_b, _%sLen);\n", ccName); 109 | 110 | w.format("if (_%sIdx == -1) {\n", ccName); 111 | w.format(" _b.writeBytes(%s);\n", ccName); 112 | w.format("} else {\n"); 113 | w.format(" _parsedBuffer.getBytes(_%sIdx, _b, _%sLen);\n", ccName, ccName); 114 | w.format("}\n"); 115 | } 116 | 117 | 118 | @Override 119 | protected String typeTag() { 120 | return "LightProtoCodec.WIRETYPE_LENGTH_DELIMITED"; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.EnumGroup; 19 | 20 | import java.io.PrintWriter; 21 | 22 | public class LightProtoEnum { 23 | private final EnumGroup eg; 24 | 25 | public LightProtoEnum(EnumGroup eg) { 26 | this.eg = eg; 27 | } 28 | 29 | public String getName() { 30 | return eg.getName(); 31 | } 32 | 33 | public void generate(PrintWriter w) { 34 | w.format(" public enum %s {\n", eg.getName()); 35 | eg.getSortedValues().forEach(v -> 36 | w.format(" %s(%d),\n", v.getName(), v.getNumber())); 37 | w.println(" ;"); 38 | w.println(" private final int value;"); 39 | w.format(" private %s(int value) {\n", eg.getName()); 40 | w.println(" this.value = value;"); 41 | w.println(" }"); 42 | w.println(" public int getValue() {"); 43 | w.println(" return value;"); 44 | w.println(" }"); 45 | 46 | w.format(" public static %s valueOf(int n) {\n", eg.getName()); 47 | w.format(" switch (n) {\n"); 48 | eg.getSortedValues().forEach(v -> 49 | w.format(" case %d: return %s;\n", v.getNumber(), v.getName())); 50 | w.println(" default: return null;\n"); 51 | w.println(" }"); 52 | w.println(" }"); 53 | eg.getSortedValues().forEach(v -> 54 | w.format(" public static final int %s_VALUE = %d;\n", v.getName(), v.getNumber())); 55 | w.println(" }"); 56 | w.println(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoEnumField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Field; 19 | 20 | import java.io.PrintWriter; 21 | 22 | public class LightProtoEnumField extends LightProtoNumberField { 23 | 24 | public LightProtoEnumField(Field field, int index) { 25 | super(field, index); 26 | } 27 | 28 | @Override 29 | public void parse(PrintWriter w) { 30 | w.format("%s _%s = %s;\n", field.getJavaType(), ccName, parseNumber(field)); 31 | w.format("if (_%s != null) {\n", ccName); 32 | w.format(" _bitField%d |= %s;\n", bitFieldIndex(), fieldMask()); 33 | w.format(" %s = _%s;\n", ccName, ccName); 34 | w.format("}\n"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Field; 19 | import io.protostuff.parser.MessageField; 20 | 21 | import java.io.PrintWriter; 22 | 23 | public abstract class LightProtoField> { 24 | 25 | protected final FieldType field; 26 | protected final int index; 27 | protected final String ccName; 28 | 29 | protected LightProtoField(FieldType field, int index) { 30 | this.field = field; 31 | this.index = index; 32 | this.ccName = Util.camelCase(field.getName()); 33 | } 34 | 35 | public static LightProtoField create(Field field, int index) { 36 | if (field.isRepeated()) { 37 | if (field.isMessageField()) { 38 | return new LightProtoRepeatedMessageField((MessageField) field, index); 39 | } else if (field.isStringField()) { 40 | return new LightProtoRepeatedStringField((Field.String) field, index); 41 | } else if (field.isEnumField()) { 42 | return new LightProtoRepeatedEnumField(field, index); 43 | } else if (field.isNumberField() || field.isBoolField()) { 44 | return new LightProtoRepeatedNumberField(field, index); 45 | } else if (field.isBytesField()) { 46 | return new LightProtoRepeatedBytesField((Field.Bytes) field, index); 47 | } 48 | } else if (field.isMessageField()) { 49 | return new LightProtoMessageField((MessageField) field, index); 50 | } else if (field.isBytesField()) { 51 | return new LightProtoBytesField((Field.Bytes) field, index); 52 | } else if (field.isStringField()) { 53 | return new LightProtoStringField((Field.String) field, index); 54 | } else if (field.isEnumField()) { 55 | return new LightProtoEnumField(field, index); 56 | } else if (field.isNumberField()) { 57 | return new LightProtoNumberField(field, index); 58 | } else if (field.isBoolField()) { 59 | return new LightProtoBooleanField(field, index); 60 | } 61 | 62 | throw new IllegalArgumentException("Unknown field: " + field); 63 | } 64 | 65 | public int index() { 66 | return index; 67 | } 68 | 69 | public boolean isRepeated() { 70 | return field.isRepeated(); 71 | } 72 | 73 | public boolean isEnum() { 74 | return field.isEnumField(); 75 | } 76 | 77 | public boolean isRequired() { 78 | return field.isRequired(); 79 | } 80 | 81 | public void docs(PrintWriter w) { 82 | field.getDocs().forEach(d -> w.format(" // %s\n", d)); 83 | } 84 | 85 | abstract public void declaration(PrintWriter w); 86 | 87 | public void tags(PrintWriter w) { 88 | w.format(" private static final int %s = %d;\n", fieldNumber(), field.getNumber()); 89 | w.format(" private static final int %s = (%s << LightProtoCodec.TAG_TYPE_BITS) | %s;\n", tagName(), fieldNumber(), typeTag()); 90 | w.format(" private static final int %s_SIZE = LightProtoCodec.computeVarIntSize(%s);\n", tagName(), tagName()); 91 | if (!field.isRepeated()) { 92 | w.format(" private static final int %s = 1 << (%d %% 32);\n", fieldMask(), index); 93 | } 94 | } 95 | 96 | public void has(PrintWriter w) { 97 | w.format(" public boolean %s() {\n", Util.camelCase("has", field.getName())); 98 | w.format(" return (_bitField%d & %s) != 0;\n", bitFieldIndex(), fieldMask()); 99 | w.format(" }\n"); 100 | } 101 | 102 | abstract public void clear(PrintWriter w); 103 | 104 | public void fieldClear(PrintWriter w, String enclosingType) { 105 | w.format(" public %s %s() {\n", enclosingType, Util.camelCase("clear", field.getName())); 106 | w.format(" _bitField%d &= ~%s;\n", bitFieldIndex(), fieldMask()); 107 | clear(w); 108 | w.format(" return this;\n"); 109 | w.format(" }\n"); 110 | } 111 | 112 | abstract public void setter(PrintWriter w, String enclosingType); 113 | 114 | abstract public void getter(PrintWriter w); 115 | 116 | abstract public void serializedSize(PrintWriter w); 117 | 118 | abstract public void serialize(PrintWriter w); 119 | 120 | abstract public void parse(PrintWriter w); 121 | 122 | abstract public void copy(PrintWriter w); 123 | 124 | public boolean isPackable() { 125 | return field.isRepeated() && field.isPackable(); 126 | } 127 | 128 | public void parsePacked(PrintWriter w) { 129 | } 130 | 131 | abstract protected String typeTag(); 132 | 133 | protected String tagName() { 134 | return "_" + Util.upperCase(field.getName(), "tag"); 135 | } 136 | 137 | protected String fieldNumber() { 138 | return "_" + Util.upperCase(field.getName(), "fieldNumber"); 139 | } 140 | 141 | protected String fieldMask() { 142 | return "_" + Util.upperCase(field.getName(), "mask"); 143 | } 144 | 145 | protected int bitFieldIndex() { 146 | return index / 32; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoGenerator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import com.google.common.base.Joiner; 19 | import com.google.common.base.Splitter; 20 | import io.protostuff.parser.Proto; 21 | import io.protostuff.parser.ProtoUtil; 22 | import org.jboss.forge.roaster.Roaster; 23 | import org.jboss.forge.roaster.model.source.JavaClassSource; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | import java.io.*; 28 | import java.nio.file.Files; 29 | import java.nio.file.Path; 30 | import java.nio.file.Paths; 31 | import java.util.*; 32 | 33 | public class LightProtoGenerator { 34 | 35 | public static List generate(List inputs, File outputDirectory, 36 | String classPrefix, boolean useOuterClass) throws Exception { 37 | List generatedFiles = new ArrayList<>(); 38 | Set javaPackages = new HashSet<>(); 39 | 40 | for (File input : inputs) { 41 | Proto proto = new Proto(); 42 | ProtoUtil.loadFrom(input, proto); 43 | 44 | String fileWithoutExtension = Splitter.on(".").splitToList(input.getName()).get(0); 45 | String outerClassName = Util.camelCaseFirstUpper(classPrefix, fileWithoutExtension); 46 | 47 | String javaPackageName = proto.getJavaPackageName(); 48 | String javaDir = Joiner.on('/').join(javaPackageName.split("\\.")); 49 | Path targetDir = Paths.get(String.format("%s/%s", outputDirectory, javaDir)); 50 | 51 | LightProto lightProto = new LightProto(proto, outerClassName, useOuterClass); 52 | generatedFiles.addAll(lightProto.generate(targetDir.toFile())); 53 | 54 | javaPackages.add(javaPackageName); 55 | } 56 | 57 | // Include the coded class once per every generated java package 58 | for (String javaPackage : javaPackages) { 59 | try (InputStream is = LightProtoGenerator.class.getResourceAsStream("/com/github/splunk/lightproto/generator/LightProtoCodec.java")) { 60 | JavaClassSource codecClass = (JavaClassSource) Roaster.parse(is); 61 | codecClass.setPackage(javaPackage); 62 | 63 | String javaDir = Joiner.on('/').join(javaPackage.split("\\.")); 64 | Path codecFile = Paths.get(String.format("%s/%s/LightProtoCodec.java", outputDirectory, javaDir)); 65 | try (Writer w = Files.newBufferedWriter(codecFile)) { 66 | w.write(codecClass.toString()); 67 | } 68 | } 69 | } 70 | 71 | return generatedFiles; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Message; 19 | 20 | import java.io.PrintWriter; 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | import java.util.stream.Collectors; 24 | 25 | public class LightProtoMessage { 26 | 27 | private final Message message; 28 | private final boolean isNested; 29 | private final List enums; 30 | private final List fields; 31 | private final List nestedMessages; 32 | 33 | public LightProtoMessage(Message message, boolean isNested) { 34 | this.message = message; 35 | this.isNested = isNested; 36 | this.enums = message.getNestedEnumGroups().stream().map(LightProtoEnum::new).collect(Collectors.toList()); 37 | this.nestedMessages = message.getNestedMessages().stream().map(m -> new LightProtoMessage(m, true)).collect(Collectors.toList()); 38 | 39 | this.fields = new ArrayList<>(); 40 | for (int i = 0; i < message.getFields().size(); i++) { 41 | fields.add(LightProtoField.create(message.getFields().get(i), i)); 42 | } 43 | } 44 | 45 | public String getName() { 46 | return message.getName(); 47 | } 48 | 49 | public void generate(PrintWriter w) { 50 | w.format(" public %s final class %s {\n", isNested ? "static" : "", message.getName()); 51 | 52 | enums.forEach(e -> e.generate(w)); 53 | nestedMessages.forEach(nm -> nm.generate(w)); 54 | fields.forEach(field -> { 55 | field.docs(w); 56 | field.declaration(w); 57 | field.tags(w); 58 | field.has(w); 59 | field.getter(w); 60 | field.setter(w, message.getName()); 61 | field.fieldClear(w, message.getName()); 62 | w.println(); 63 | }); 64 | 65 | generateBitFields(w); 66 | generateSerialize(w); 67 | generateGetSerializedSize(w); 68 | generateParseFrom(w); 69 | generateCheckRequiredFields(w); 70 | generateClear(w); 71 | generateCopyFrom(w); 72 | 73 | w.println(" public byte[] toByteArray() {"); 74 | w.println(" byte[] a = new byte[getSerializedSize()];"); 75 | w.println(" io.netty.buffer.ByteBuf b = io.netty.buffer.Unpooled.wrappedBuffer(a).writerIndex(0);"); 76 | w.println(" this.writeTo(b);"); 77 | w.println(" return a;"); 78 | w.println(" }"); 79 | 80 | w.println(" public void parseFrom(byte[] a) {"); 81 | w.println(" io.netty.buffer.ByteBuf b = io.netty.buffer.Unpooled.wrappedBuffer(a);"); 82 | w.println(" this.parseFrom(b, b.readableBytes());"); 83 | w.println(" }"); 84 | 85 | w.println(" private int _cachedSize;\n"); 86 | w.println(" private io.netty.buffer.ByteBuf _parsedBuffer;\n"); 87 | w.println(" }"); 88 | w.println(); 89 | } 90 | 91 | private void generateParseFrom(PrintWriter w) { 92 | w.format(" public void parseFrom(io.netty.buffer.ByteBuf _buffer, int _size) {\n"); 93 | w.format(" clear();\n"); 94 | w.format(" int _endIdx = _buffer.readerIndex() + _size;\n"); 95 | w.format(" while (_buffer.readerIndex() < _endIdx) {\n"); 96 | w.format(" int _tag = LightProtoCodec.readVarInt(_buffer);\n"); 97 | w.format(" switch (_tag) {\n"); 98 | 99 | for (LightProtoField field : fields) { 100 | w.format(" case %s:\n", field.tagName()); 101 | if (!field.isRepeated() && !field.isEnum()) { 102 | w.format(" _bitField%d |= %s;\n", field.bitFieldIndex(), field.fieldMask()); 103 | } 104 | field.parse(w); 105 | w.format(" break;\n"); 106 | } 107 | 108 | for (LightProtoField field : fields) { 109 | if (field.isPackable()) { 110 | w.format(" case %s_PACKED:\n", field.tagName()); 111 | field.parsePacked(w); 112 | w.format(" break;\n"); 113 | } 114 | } 115 | 116 | w.format(" default:\n"); 117 | w.format(" LightProtoCodec.skipUnknownField(_tag, _buffer);\n"); 118 | w.format(" }\n"); 119 | w.format(" }\n"); 120 | if (hasRequiredFields()) { 121 | w.format(" checkRequiredFields();\n"); 122 | } 123 | w.format(" _parsedBuffer = _buffer;\n"); 124 | w.format(" }\n"); 125 | } 126 | 127 | private void generateClear(PrintWriter w) { 128 | w.format(" public %s clear() {\n", message.getName()); 129 | for (LightProtoField f : fields) { 130 | f.clear(w); 131 | } 132 | 133 | w.format(" _parsedBuffer = null;\n"); 134 | w.format(" _cachedSize = -1;\n"); 135 | for (int i = 0; i < bitFieldsCount(); i++) { 136 | w.format(" _bitField%d = 0;\n", i); 137 | } 138 | 139 | w.format(" return this;\n"); 140 | w.format(" }\n"); 141 | } 142 | 143 | private void generateCopyFrom(PrintWriter w) { 144 | w.format("public %s copyFrom(%s _other) {\n", message.getName(), message.getName()); 145 | w.format(" _cachedSize = -1;\n"); 146 | for (LightProtoField f : fields) { 147 | if (f.isRepeated()) { 148 | f.copy(w); 149 | } else { 150 | w.format(" if (_other.%s()) {\n", Util.camelCase("has", f.ccName)); 151 | f.copy(w); 152 | w.format(" }\n"); 153 | } 154 | } 155 | 156 | w.format(" return this;\n"); 157 | w.format(" }\n"); 158 | } 159 | 160 | private void generateSerialize(PrintWriter w) { 161 | w.format(" public int writeTo(io.netty.buffer.ByteBuf _b) {\n"); 162 | if (hasRequiredFields()) { 163 | w.format(" checkRequiredFields();\n"); 164 | } 165 | w.format(" int _writeIdx = _b.writerIndex();\n"); 166 | for (LightProtoField f : fields) { 167 | 168 | if (f.isRequired() || f.isRepeated()) { 169 | // If required, skip the has() check 170 | f.serialize(w); 171 | } else { 172 | w.format(" if (%s()) {\n", Util.camelCase("has", f.field.getName())); 173 | f.serialize(w); 174 | w.format(" }\n"); 175 | } 176 | } 177 | 178 | w.format(" return (_b.writerIndex() - _writeIdx);\n"); 179 | w.format(" }\n"); 180 | } 181 | 182 | private void generateGetSerializedSize(PrintWriter w) { 183 | w.format("public int getSerializedSize() {\n"); 184 | w.format(" if (_cachedSize > -1) {\n"); 185 | w.format(" return _cachedSize;\n"); 186 | w.format(" }\n"); 187 | w.format("\n"); 188 | 189 | w.format(" int _size = 0;\n"); 190 | fields.forEach(field -> { 191 | if (field.isRequired() || field.isRepeated()) { 192 | field.serializedSize(w); 193 | } else { 194 | w.format(" if (%s()) {\n", Util.camelCase("has", field.field.getName())); 195 | field.serializedSize(w); 196 | w.format(" }\n"); 197 | } 198 | }); 199 | 200 | w.format(" _cachedSize = _size;\n"); 201 | w.format(" return _size;\n"); 202 | w.format(" }\n"); 203 | } 204 | 205 | private void generateBitFields(PrintWriter w) { 206 | for (int i = 0; i < bitFieldsCount(); i++) { 207 | w.format("private int _bitField%d;\n", i); 208 | w.format("private static final int _REQUIRED_FIELDS_MASK%d = 0", i); 209 | int idx = i; 210 | fields.forEach(f -> { 211 | if (f.isRequired() && f.index() / 32 == idx) { 212 | w.format(" | %s", f.fieldMask()); 213 | } 214 | }); 215 | w.println(";"); 216 | } 217 | } 218 | 219 | private void generateCheckRequiredFields(PrintWriter w) { 220 | if (!hasRequiredFields()) { 221 | return; 222 | } 223 | 224 | w.format(" private void checkRequiredFields() {\n"); 225 | w.format(" if ("); 226 | for (int i = 0; i < bitFieldsCount(); i++) { 227 | if (i != 0) { 228 | w.print("\n || "); 229 | } 230 | 231 | w.format("(_bitField%d & _REQUIRED_FIELDS_MASK%d) != _REQUIRED_FIELDS_MASK%d", i, i, i); 232 | } 233 | 234 | w.format(") {\n"); 235 | w.format(" throw new IllegalStateException(\"Some required fields are missing\");\n"); 236 | w.format(" }\n"); 237 | w.format("}\n"); 238 | } 239 | 240 | private int bitFieldsCount() { 241 | if (message.getFieldCount() == 0) { 242 | return 0; 243 | } 244 | 245 | return (int) Math.ceil(message.getFields().size() / 32.0); 246 | } 247 | 248 | 249 | private boolean hasRequiredFields() { 250 | for (LightProtoField field : fields) { 251 | if (field.isRequired()) { 252 | return true; 253 | } 254 | } 255 | 256 | return false; 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoMessageField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.MessageField; 19 | 20 | import java.io.PrintWriter; 21 | 22 | public class LightProtoMessageField extends LightProtoField { 23 | 24 | public LightProtoMessageField(MessageField field, int index) { 25 | super(field, index); 26 | } 27 | 28 | @Override 29 | public void declaration(PrintWriter w) { 30 | w.format("private %s %s;\n", field.getJavaType(), ccName); 31 | } 32 | 33 | @Override 34 | public void setter(PrintWriter w, String enclosingType) { 35 | w.format("public %s %s() {\n", field.getJavaType(), Util.camelCase("set", ccName)); 36 | w.format(" if (%s == null) {\n", ccName); 37 | w.format(" %s = new %s();\n", ccName, field.getJavaType()); 38 | w.format(" }\n"); 39 | w.format(" _bitField%d |= %s;\n", bitFieldIndex(), fieldMask()); 40 | w.format(" _cachedSize = -1;\n"); 41 | w.format(" return %s;\n", ccName); 42 | w.format("}\n"); 43 | } 44 | 45 | @Override 46 | public void copy(PrintWriter w) { 47 | w.format("%s().copyFrom(_other.%s);\n", Util.camelCase("set", ccName), ccName); 48 | } 49 | 50 | public void getter(PrintWriter w) { 51 | w.format("public %s %s() {\n", field.getJavaType(), Util.camelCase("get", field.getName())); 52 | w.format(" if (!%s()) {\n", Util.camelCase("has", ccName)); 53 | w.format(" throw new IllegalStateException(\"Field '%s' is not set\");\n", field.getName()); 54 | w.format(" }\n"); 55 | w.format(" return %s;\n", ccName); 56 | w.format("}\n"); 57 | } 58 | 59 | @Override 60 | public void parse(PrintWriter w) { 61 | w.format("int %sSize = LightProtoCodec.readVarInt(_buffer);\n", ccName); 62 | w.format("%s().parseFrom(_buffer, %sSize);\n", Util.camelCase("set", ccName), ccName); 63 | } 64 | 65 | @Override 66 | public void serializedSize(PrintWriter w) { 67 | String tmpName = Util.camelCase("_msgSize", ccName); 68 | w.format("_size += LightProtoCodec.computeVarIntSize(%s);\n", tagName()); 69 | w.format("int %s = %s.getSerializedSize();\n", tmpName, ccName); 70 | w.format("_size += LightProtoCodec.computeVarIntSize(%s) + %s;\n", tmpName, tmpName); 71 | } 72 | 73 | @Override 74 | public void serialize(PrintWriter w) { 75 | w.format("LightProtoCodec.writeVarInt(_b, %s);\n", tagName()); 76 | w.format("LightProtoCodec.writeVarInt(_b, %s.getSerializedSize());\n", ccName); 77 | w.format("%s.writeTo(_b);\n", ccName); 78 | } 79 | 80 | @Override 81 | public void clear(PrintWriter w) { 82 | w.format("if (%s()){\n", Util.camelCase("has", ccName)); 83 | w.format(" %s.clear();\n", ccName); 84 | w.format("}\n"); 85 | } 86 | 87 | @Override 88 | protected String typeTag() { 89 | return "LightProtoCodec.WIRETYPE_LENGTH_DELIMITED"; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoNumberField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import com.google.common.collect.Maps; 19 | import io.protostuff.parser.Field; 20 | 21 | import java.io.PrintWriter; 22 | import java.util.Map; 23 | 24 | import static com.github.splunk.lightproto.generator.Util.camelCase; 25 | 26 | public class LightProtoNumberField extends LightProtoField> { 27 | 28 | 29 | private static final Map typeToTag = Maps.newHashMap(); 30 | 31 | static { 32 | typeToTag.put("double", "LightProtoCodec.WIRETYPE_FIXED64"); 33 | typeToTag.put("float", "LightProtoCodec.WIRETYPE_FIXED32"); 34 | typeToTag.put("bool", "LightProtoCodec.WIRETYPE_VARINT"); 35 | typeToTag.put("int32", "LightProtoCodec.WIRETYPE_VARINT"); 36 | typeToTag.put("int64", "LightProtoCodec.WIRETYPE_VARINT"); 37 | typeToTag.put("uint32", "LightProtoCodec.WIRETYPE_VARINT"); 38 | typeToTag.put("uint64", "LightProtoCodec.WIRETYPE_VARINT"); 39 | typeToTag.put("sint32", "LightProtoCodec.WIRETYPE_VARINT"); 40 | typeToTag.put("sint64", "LightProtoCodec.WIRETYPE_VARINT"); 41 | typeToTag.put("fixed32", "LightProtoCodec.WIRETYPE_FIXED32"); 42 | typeToTag.put("fixed64", "LightProtoCodec.WIRETYPE_FIXED64"); 43 | typeToTag.put("sfixed32", "LightProtoCodec.WIRETYPE_FIXED32"); 44 | typeToTag.put("sfixed64", "LightProtoCodec.WIRETYPE_FIXED64"); 45 | } 46 | 47 | public LightProtoNumberField(Field field, int index) { 48 | super(field, index); 49 | } 50 | 51 | static void serializeNumber(PrintWriter w, Field field, String name) { 52 | if (field.isEnumField()) { 53 | w.format(" LightProtoCodec.writeVarInt(_b, %s.getValue());\n", name); 54 | } else if (field.getProtoType().equals("bool")) { 55 | w.format(" _b.writeBoolean(%s);\n", name); 56 | } else if (field.getProtoType().equals("int32")) { 57 | w.format(" LightProtoCodec.writeVarInt(_b, %s);\n", name); 58 | } else if (field.getProtoType().equals("uint32")) { 59 | w.format(" LightProtoCodec.writeVarInt(_b, %s);\n", name); 60 | } else if (field.getProtoType().equals("sint32")) { 61 | w.format(" LightProtoCodec.writeSignedVarInt(_b, %s);\n", name); 62 | } else if (field.getProtoType().equals("sint64")) { 63 | w.format(" LightProtoCodec.writeSignedVarInt64(_b, %s);\n", name); 64 | } else if (field.getProtoType().equals("int64")) { 65 | w.format(" LightProtoCodec.writeVarInt64(_b, %s);\n", name); 66 | } else if (field.getProtoType().equals("uint64")) { 67 | w.format(" LightProtoCodec.writeVarInt64(_b, %s);\n", name); 68 | } else if (field.getProtoType().equals("fixed32")) { 69 | w.format(" LightProtoCodec.writeFixedInt32(_b, %s);\n", name); 70 | } else if (field.getProtoType().equals("fixed64")) { 71 | w.format(" LightProtoCodec.writeFixedInt64(_b, %s);\n", name); 72 | } else if (field.getProtoType().equals("sfixed32")) { 73 | w.format(" LightProtoCodec.writeFixedInt32(_b, %s);\n", name); 74 | } else if (field.getProtoType().equals("sfixed64")) { 75 | w.format(" LightProtoCodec.writeFixedInt64(_b, %s);\n", name); 76 | } else if (field.getProtoType().equals("double")) { 77 | w.format(" LightProtoCodec.writeDouble(_b, %s);\n", name); 78 | } else if (field.getProtoType().equals("float")) { 79 | w.format(" LightProtoCodec.writeFloat(_b, %s);\n", name); 80 | } else { 81 | throw new IllegalArgumentException("Failed to write serializer for field: " + field.getProtoType()); 82 | } 83 | } 84 | 85 | static String parseNumber(Field field) { 86 | if (field.isEnumField()) { 87 | return String.format("%s.valueOf(LightProtoCodec.readVarInt(_buffer))", field.getJavaType()); 88 | } else if (field.getProtoType().equals("bool")) { 89 | return "LightProtoCodec.readVarInt(_buffer) == 1"; 90 | } else if (field.getProtoType().equals("int32")) { 91 | return "LightProtoCodec.readVarInt(_buffer)"; 92 | } else if (field.getProtoType().equals("uint32")) { 93 | return "LightProtoCodec.readVarInt(_buffer)"; 94 | } else if (field.getProtoType().equals("sint32")) { 95 | return "LightProtoCodec.readSignedVarInt(_buffer)"; 96 | } else if (field.getProtoType().equals("sint64")) { 97 | return "LightProtoCodec.readSignedVarInt64(_buffer)"; 98 | } else if (field.getProtoType().equals("int64")) { 99 | return "LightProtoCodec.readVarInt64(_buffer)"; 100 | } else if (field.getProtoType().equals("uint64")) { 101 | return "LightProtoCodec.readVarInt64(_buffer)"; 102 | } else if (field.getProtoType().equals("fixed32")) { 103 | return "LightProtoCodec.readFixedInt32(_buffer)"; 104 | } else if (field.getProtoType().equals("fixed64")) { 105 | return "LightProtoCodec.readFixedInt64(_buffer)"; 106 | } else if (field.getProtoType().equals("sfixed32")) { 107 | return "LightProtoCodec.readFixedInt32(_buffer)"; 108 | } else if (field.getProtoType().equals("sfixed64")) { 109 | return "LightProtoCodec.readFixedInt64(_buffer)"; 110 | } else if (field.getProtoType().equals("double")) { 111 | return "LightProtoCodec.readDouble(_buffer)"; 112 | } else if (field.getProtoType().equals("float")) { 113 | return "LightProtoCodec.readFloat(_buffer)"; 114 | } else { 115 | throw new IllegalArgumentException("Failed to write parser for field: " + field.getProtoType()); 116 | } 117 | } 118 | 119 | static String serializedSizeOfNumber(Field field, String name) { 120 | if (field.isEnumField()) { 121 | return String.format("LightProtoCodec.computeVarIntSize(%s.getValue())", name); 122 | } else if (field.getProtoType().equals("sint32")) { 123 | return String.format("LightProtoCodec.computeSignedVarIntSize(%s)", name); 124 | } else if (field.getProtoType().equals("sint64")) { 125 | return String.format("LightProtoCodec.computeSignedVarInt64Size(%s)", name); 126 | } else if (field.getProtoType().equals("int32")) { 127 | return String.format("LightProtoCodec.computeVarIntSize(%s)", name); 128 | } else if (field.getProtoType().equals("uint32")) { 129 | return String.format("LightProtoCodec.computeVarIntSize(%s)", name); 130 | } else if (field.getProtoType().equals("int64")) { 131 | return String.format("LightProtoCodec.computeVarInt64Size(%s)", name); 132 | } else if (field.getProtoType().equals("uint64")) { 133 | return String.format("LightProtoCodec.computeVarInt64Size(%s)", name); 134 | } else if (field.getProtoType().equals("fixed32")) { 135 | return "4"; 136 | } else if (field.getProtoType().equals("fixed64")) { 137 | return "8"; 138 | } else if (field.getProtoType().equals("sfixed32")) { 139 | return "4"; 140 | } else if (field.getProtoType().equals("sfixed64")) { 141 | return "8"; 142 | } else if (field.getProtoType().equals("bool")) { 143 | return "1"; 144 | } else if (field.getProtoType().equals("double")) { 145 | return "8"; 146 | } else if (field.getProtoType().equals("float")) { 147 | return "4"; 148 | } else { 149 | throw new IllegalArgumentException("Failed to write serializer for field: " + field.getProtoType()); 150 | } 151 | } 152 | 153 | static String typeTag(Field field) { 154 | if (field.isEnumField()) { 155 | return "LightProtoCodec.WIRETYPE_VARINT"; 156 | } else { 157 | return typeToTag.get(field.getProtoType()); 158 | } 159 | } 160 | 161 | public void getter(PrintWriter w) { 162 | w.format(" public %s %s() {\n", field.getJavaType(), Util.camelCase("get", field.getName())); 163 | if (!field.isDefaultValueSet()) { 164 | w.format(" if (!%s()) {\n", Util.camelCase("has", ccName)); 165 | w.format(" throw new IllegalStateException(\"Field '%s' is not set\");\n", field.getName()); 166 | w.format(" }\n"); 167 | } 168 | w.format(" return %s;\n", ccName); 169 | w.format(" }\n"); 170 | } 171 | 172 | @Override 173 | public void parse(PrintWriter w) { 174 | w.format("%s = %s;\n", ccName, parseNumber(field)); 175 | } 176 | 177 | @Override 178 | public void serialize(PrintWriter w) { 179 | w.format("LightProtoCodec.writeVarInt(_b, %s);\n", tagName()); 180 | serializeNumber(w, field, ccName); 181 | } 182 | 183 | @Override 184 | public void setter(PrintWriter w, String enclosingType) { 185 | w.format("public %s %s(%s %s) {\n", enclosingType, Util.camelCase("set", field.getName()), field.getJavaType(), camelCase(field.getName())); 186 | w.format(" this.%s = %s;\n", camelCase(field.getName()), camelCase(field.getName())); 187 | w.format(" _bitField%d |= %s;\n", bitFieldIndex(), fieldMask()); 188 | w.format(" _cachedSize = -1;\n"); 189 | w.format(" return this;\n"); 190 | w.format("}\n"); 191 | } 192 | 193 | @Override 194 | public void declaration(PrintWriter w) { 195 | if (field.isDefaultValueSet()) { 196 | w.format("private %s %s = %s;\n", field.getJavaType(), ccName, field.getDefaultValueAsString()); 197 | } else { 198 | w.format("private %s %s;\n", field.getJavaType(), ccName); 199 | } 200 | } 201 | 202 | @Override 203 | public void copy(PrintWriter w) { 204 | w.format("%s(_other.%s);\n", Util.camelCase("set", ccName), ccName); 205 | } 206 | 207 | @Override 208 | public void clear(PrintWriter w) { 209 | if (field.isDefaultValueSet()) { 210 | w.format("%s = %s;\n", ccName, field.getDefaultValueAsString()); 211 | } 212 | } 213 | 214 | @Override 215 | public void serializedSize(PrintWriter w) { 216 | w.format("_size += %s_SIZE;\n", tagName()); 217 | w.format("_size += %s;\n", serializedSizeOfNumber(field, ccName)); 218 | } 219 | 220 | @Override 221 | protected String typeTag() { 222 | return typeTag(field); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoRepeatedBytesField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Field; 19 | 20 | import java.io.PrintWriter; 21 | 22 | public class LightProtoRepeatedBytesField extends LightProtoAbstractRepeated { 23 | 24 | protected final String pluralName; 25 | protected final String singularName; 26 | 27 | public LightProtoRepeatedBytesField(Field.Bytes field, int index) { 28 | super(field, index); 29 | this.pluralName = Util.plural(ccName); 30 | this.singularName = Util.singular(ccName); 31 | } 32 | 33 | @Override 34 | public void declaration(PrintWriter w) { 35 | w.format("private java.util.List %s = null;\n", pluralName); 36 | w.format("private int _%sCount = 0;\n", pluralName); 37 | } 38 | 39 | @Override 40 | public void parse(PrintWriter w) { 41 | w.format("LightProtoCodec.BytesHolder _%sBh = _%sBytesHolder();\n", ccName, Util.camelCase("new", singularName)); 42 | w.format("_%sBh.len = LightProtoCodec.readVarInt(_buffer);\n", ccName); 43 | w.format("_%sBh.idx = _buffer.readerIndex();\n", ccName); 44 | w.format("_buffer.skipBytes(_%sBh.len);\n", ccName); 45 | } 46 | 47 | @Override 48 | public void getter(PrintWriter w) { 49 | w.format("public int %s() {\n", Util.camelCase("get", pluralName, "count")); 50 | w.format(" return _%sCount;\n", pluralName); 51 | w.format("}\n"); 52 | 53 | w.format("public int %s(int idx) {\n", Util.camelCase("get", singularName, "size", "at")); 54 | w.format(" if (idx < 0 || idx >= _%sCount) {\n", pluralName); 55 | w.format(" throw new IndexOutOfBoundsException(\"Index \" + idx + \" is out of the list size (\" + _%sCount + \") for field '%s'\");\n", pluralName, field.getName()); 56 | w.format(" }\n"); 57 | w.format(" return %s.get(idx).len;\n", pluralName); 58 | w.format("}\n"); 59 | 60 | 61 | w.format("public byte[] %s(int idx) {\n", Util.camelCase("get", singularName, "at")); 62 | w.format(" io.netty.buffer.ByteBuf _b = %s(idx);\n", Util.camelCase("get", singularName, "slice", "at")); 63 | w.format(" byte[] res = new byte[_b.readableBytes()];\n"); 64 | w.format(" _b.getBytes(0, res);\n", ccName); 65 | w.format(" return res;\n"); 66 | w.format("}\n"); 67 | 68 | w.format("public io.netty.buffer.ByteBuf %s(int idx) {\n", Util.camelCase("get", singularName, "slice", "at")); 69 | w.format(" if (idx < 0 || idx >= _%sCount) {\n", pluralName); 70 | w.format(" throw new IndexOutOfBoundsException(\"Index \" + idx + \" is out of the list size (\" + _%sCount + \") for field '%s'\");\n", pluralName, field.getName()); 71 | w.format(" }\n"); 72 | w.format(" LightProtoCodec.BytesHolder _bh = %s.get(idx);\n", pluralName); 73 | w.format(" if (_bh.b == null) {\n"); 74 | w.format(" return _parsedBuffer.slice(_bh.idx, _bh.len);\n"); 75 | w.format(" } else {\n"); 76 | w.format(" return _bh.b.slice(0, _bh.len);\n"); 77 | w.format(" }\n"); 78 | w.format("}\n"); 79 | } 80 | 81 | @Override 82 | public void serialize(PrintWriter w) { 83 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 84 | w.format(" LightProtoCodec.BytesHolder _bh = %s.get(i);\n", pluralName); 85 | w.format(" LightProtoCodec.writeVarInt(_b, %s);\n", tagName()); 86 | w.format(" LightProtoCodec.writeVarInt(_b, _bh.len);\n"); 87 | w.format(" if (_bh.idx == -1) {\n"); 88 | w.format(" _bh.b.getBytes(0, _b, _bh.len);\n"); 89 | w.format(" } else {\n"); 90 | w.format(" _parsedBuffer.getBytes(_bh.idx, _b, _bh.len);\n"); 91 | w.format(" }\n"); 92 | w.format("}\n"); 93 | } 94 | 95 | @Override 96 | public void setter(PrintWriter w, String enclosingType) { 97 | w.format("public void %s(byte[] %s) {\n", Util.camelCase("add", singularName), singularName); 98 | w.format(" %s(io.netty.buffer.Unpooled.wrappedBuffer(%s));\n", Util.camelCase("add", singularName), singularName); 99 | w.format("}\n"); 100 | 101 | w.format("public void %s(io.netty.buffer.ByteBuf %s) {\n", Util.camelCase("add", singularName), singularName); 102 | w.format(" if (%s == null) {\n", pluralName); 103 | w.format(" %s = new java.util.ArrayList();\n", pluralName); 104 | w.format(" }\n"); 105 | w.format(" LightProtoCodec.BytesHolder _bh = _%sBytesHolder();\n", Util.camelCase("new", singularName)); 106 | w.format(" _cachedSize = -1;\n"); 107 | w.format(" _bh.b = %s;\n", singularName); 108 | w.format(" _bh.idx = -1;\n"); 109 | w.format(" _bh.len = %s.readableBytes();\n", singularName); 110 | w.format("}\n"); 111 | 112 | 113 | w.format("private LightProtoCodec.BytesHolder _%sBytesHolder() {\n", Util.camelCase("new", singularName)); 114 | w.format(" if (%s == null) {\n", pluralName); 115 | w.format(" %s = new java.util.ArrayList();\n", pluralName); 116 | w.format(" }\n"); 117 | w.format(" LightProtoCodec.BytesHolder _bh;\n"); 118 | w.format(" if (%s.size() == _%sCount) {\n", pluralName, pluralName); 119 | w.format(" _bh = new LightProtoCodec.BytesHolder();\n"); 120 | w.format(" %s.add(_bh);\n", pluralName); 121 | w.format(" } else {\n"); 122 | w.format(" _bh = %s.get(_%sCount);\n", pluralName, pluralName); 123 | w.format(" }\n"); 124 | w.format(" _%sCount++;\n", pluralName); 125 | w.format(" return _bh;\n"); 126 | w.format("}\n"); 127 | } 128 | 129 | @Override 130 | public void copy(PrintWriter w) { 131 | w.format("for (int i = 0; i < _other.%s(); i++) {\n", Util.camelCase("get", pluralName, "count")); 132 | w.format(" %s(_other.%s(i));\n", Util.camelCase("add", singularName), Util.camelCase("get", singularName, "at")); 133 | w.format("}\n"); 134 | } 135 | 136 | @Override 137 | public void serializedSize(PrintWriter w) { 138 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 139 | w.format(" LightProtoCodec.BytesHolder _bh = %s.get(i);\n", pluralName); 140 | w.format(" _size += %s_SIZE;\n", tagName()); 141 | w.format(" _size += LightProtoCodec.computeVarIntSize(_bh.len) + _bh.len;\n"); 142 | w.format("}\n"); 143 | } 144 | 145 | @Override 146 | public void clear(PrintWriter w) { 147 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 148 | w.format(" LightProtoCodec.BytesHolder _bh = %s.get(i);\n", pluralName); 149 | w.format(" _bh.b = null;\n"); 150 | w.format(" _bh.idx = -1;\n"); 151 | w.format(" _bh.len = -1;\n"); 152 | w.format("}\n"); 153 | w.format("_%sCount = 0;\n", pluralName); 154 | } 155 | 156 | @Override 157 | protected String typeTag() { 158 | return "LightProtoCodec.WIRETYPE_LENGTH_DELIMITED"; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoRepeatedEnumField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Field; 19 | 20 | import java.io.PrintWriter; 21 | 22 | public class LightProtoRepeatedEnumField extends LightProtoRepeatedNumberField { 23 | 24 | public LightProtoRepeatedEnumField(Field field, int index) { 25 | super(field, index); 26 | } 27 | 28 | @Override 29 | public void parse(PrintWriter w) { 30 | w.format("%s _%s = %s;\n", field.getJavaType(), ccName, LightProtoNumberField.parseNumber(field)); 31 | w.format("if (_%s != null) {\n", ccName); 32 | w.format(" %s(_%s);\n", Util.camelCase("add", singularName), ccName); 33 | w.format("}\n"); 34 | } 35 | 36 | public void parsePacked(PrintWriter w) { 37 | w.format("int _%s = LightProtoCodec.readVarInt(_buffer);\n", Util.camelCase(singularName, "size")); 38 | w.format("int _%s = _buffer.readerIndex() + _%s;\n", Util.camelCase(singularName, "endIdx"), Util.camelCase(singularName, "size")); 39 | w.format("while (_buffer.readerIndex() < _%s) {\n", Util.camelCase(singularName, "endIdx")); 40 | w.format(" %s _%sPacked = %s;\n", field.getJavaType(), ccName, LightProtoNumberField.parseNumber(field)); 41 | w.format(" if (_%sPacked != null) {\n", ccName); 42 | w.format(" %s(_%sPacked);\n", Util.camelCase("add", singularName), ccName); 43 | w.format(" }\n"); 44 | w.format("}\n"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoRepeatedMessageField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.MessageField; 19 | 20 | import java.io.PrintWriter; 21 | 22 | public class LightProtoRepeatedMessageField extends LightProtoAbstractRepeated { 23 | 24 | protected final String pluralName; 25 | protected final String singularName; 26 | 27 | public LightProtoRepeatedMessageField(MessageField field, int index) { 28 | super(field, index); 29 | this.pluralName = Util.plural(ccName); 30 | this.singularName = Util.singular(ccName); 31 | } 32 | 33 | @Override 34 | public void declaration(PrintWriter w) { 35 | w.format("private java.util.List<%s> %s = null;\n", field.getJavaType(), pluralName); 36 | w.format("private int _%sCount = 0;\n", pluralName); 37 | } 38 | 39 | @Override 40 | public void getter(PrintWriter w) { 41 | w.format("public int %s() {\n", Util.camelCase("get", pluralName, "count")); 42 | w.format(" return _%sCount;\n", pluralName); 43 | w.format("}\n"); 44 | w.format("public %s %s(int idx) {\n", field.getJavaType(), Util.camelCase("get", singularName, "at")); 45 | w.format(" if (idx < 0 || idx >= _%sCount) {\n", pluralName); 46 | w.format(" throw new IndexOutOfBoundsException(\"Index \" + idx + \" is out of the list size (\" + _%sCount + \") for field '%s'\");\n", pluralName, field.getName()); 47 | w.format(" }\n"); 48 | w.format(" return %s.get(idx);\n", pluralName); 49 | w.format("}\n"); 50 | 51 | w.format("public java.util.List<%s> %s() {\n", field.getJavaType(), Util.camelCase("get", pluralName, "list")); 52 | w.format(" if (_%sCount == 0) {\n", pluralName); 53 | w.format(" return java.util.Collections.emptyList();\n"); 54 | w.format(" } else {\n"); 55 | w.format(" return %s.subList(0, _%sCount);\n", pluralName, pluralName); 56 | w.format(" }\n"); 57 | w.format("}\n"); 58 | } 59 | 60 | @Override 61 | public void parse(PrintWriter w) { 62 | w.format("int _%sSize = LightProtoCodec.readVarInt(_buffer);\n", ccName); 63 | w.format("%s().parseFrom(_buffer, _%sSize);\n", Util.camelCase("add", singularName), ccName); 64 | } 65 | 66 | @Override 67 | public void serialize(PrintWriter w) { 68 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 69 | w.format(" %s _item = %s.get(i);\n", field.getJavaType(), pluralName); 70 | w.format(" LightProtoCodec.writeVarInt(_b, %s);\n", tagName()); 71 | w.format(" LightProtoCodec.writeVarInt(_b, _item.getSerializedSize());\n"); 72 | w.format(" _item.writeTo(_b);\n"); 73 | w.format("}\n"); 74 | } 75 | 76 | @Override 77 | public void copy(PrintWriter w) { 78 | w.format("for (int i = 0; i < _other.%s(); i++) {\n", Util.camelCase("get", pluralName, "count")); 79 | w.format(" %s().copyFrom(_other.%s(i));\n", Util.camelCase("add", singularName), Util.camelCase("get", singularName, "at")); 80 | w.format("}\n"); 81 | } 82 | 83 | @Override 84 | public void setter(PrintWriter w, String enclosingType) { 85 | w.format("public %s %s() {\n", field.getJavaType(), Util.camelCase("add", singularName)); 86 | w.format(" if (%s == null) {\n", pluralName); 87 | w.format(" %s = new java.util.ArrayList<%s>();\n", pluralName, field.getJavaType()); 88 | w.format(" }\n"); 89 | w.format(" if (%s.size() == _%sCount) {\n", pluralName, pluralName); 90 | w.format(" %s.add(new %s());\n", pluralName, field.getJavaType()); 91 | w.format(" }\n"); 92 | w.format(" _cachedSize = -1;\n"); 93 | w.format(" return %s.get(_%sCount++);\n", pluralName, pluralName); 94 | w.format("}\n"); 95 | 96 | 97 | w.format("public %s %s(Iterable<%s> %s) {\n", enclosingType, Util.camelCase("addAll", pluralName), field.getJavaType(), pluralName); 98 | w.format(" for (%s _o : %s) {\n", field.getJavaType(), pluralName); 99 | w.format(" %s().copyFrom(_o);\n", Util.camelCase("add", singularName)); 100 | w.format(" }\n"); 101 | w.format(" return this;\n"); 102 | w.format("}\n"); 103 | 104 | 105 | } 106 | 107 | @Override 108 | public void serializedSize(PrintWriter w) { 109 | String tmpName = Util.camelCase("_msgSize", field.getName()); 110 | 111 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 112 | w.format(" %s _item = %s.get(i);\n", field.getJavaType(), pluralName); 113 | w.format(" _size += %s_SIZE;\n", tagName()); 114 | w.format(" int %s = _item.getSerializedSize();\n", tmpName); 115 | w.format(" _size += LightProtoCodec.computeVarIntSize(%s) + %s;\n", tmpName, tmpName); 116 | w.format("}\n"); 117 | } 118 | 119 | @Override 120 | public void clear(PrintWriter w) { 121 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 122 | w.format(" %s.get(i).clear();\n", pluralName); 123 | w.format("}\n"); 124 | w.format("_%sCount = 0;\n", pluralName); 125 | } 126 | 127 | @Override 128 | protected String typeTag() { 129 | return "LightProtoCodec.WIRETYPE_LENGTH_DELIMITED"; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoRepeatedNumberField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Field; 19 | 20 | import java.io.PrintWriter; 21 | 22 | public class LightProtoRepeatedNumberField extends LightProtoAbstractRepeated> { 23 | 24 | protected final String pluralName; 25 | protected final String singularName; 26 | 27 | public LightProtoRepeatedNumberField(Field field, int index) { 28 | super(field, index); 29 | this.pluralName = Util.plural(ccName); 30 | this.singularName = Util.singular(ccName); 31 | } 32 | 33 | @Override 34 | public void declaration(PrintWriter w) { 35 | w.format("private %s[] %s = null;\n", field.getJavaType(), pluralName); 36 | w.format("private int _%sCount = 0;\n", pluralName); 37 | } 38 | 39 | @Override 40 | public void parse(PrintWriter w) { 41 | w.format("%s(%s);\n", Util.camelCase("add", singularName), LightProtoNumberField.parseNumber(field)); 42 | } 43 | 44 | public void parsePacked(PrintWriter w) { 45 | w.format("int _%s = LightProtoCodec.readVarInt(_buffer);\n", Util.camelCase(singularName, "size")); 46 | w.format("int _%s = _buffer.readerIndex() + _%s;\n", Util.camelCase(singularName, "endIdx"), Util.camelCase(singularName, "size")); 47 | w.format("while (_buffer.readerIndex() < _%s) {\n", Util.camelCase(singularName, "endIdx")); 48 | w.format("%s(%s);\n", Util.camelCase("add", singularName), LightProtoNumberField.parseNumber(field)); 49 | w.format("}\n"); 50 | } 51 | 52 | @Override 53 | public void getter(PrintWriter w) { 54 | w.format("private static final int %s_PACKED = (%s << LightProtoCodec.TAG_TYPE_BITS) | LightProtoCodec.WIRETYPE_LENGTH_DELIMITED;\n", tagName(), fieldNumber()); 55 | w.format("public int %s() {\n", Util.camelCase("get", pluralName, "count")); 56 | w.format(" return _%sCount;\n", pluralName); 57 | w.format("}\n"); 58 | w.format("public %s %s(int idx) {\n", field.getJavaType(), Util.camelCase("get", singularName, "at")); 59 | w.format(" if (idx < 0 || idx >= _%sCount) {\n", pluralName); 60 | w.format(" throw new IndexOutOfBoundsException(\"Index \" + idx + \" is out of the list size (\" + _%sCount + \") for field '%s'\");\n", pluralName, field.getName()); 61 | w.format(" }\n"); 62 | w.format(" return %s[idx];\n", pluralName); 63 | w.format("}\n"); 64 | } 65 | 66 | @Override 67 | public void serialize(PrintWriter w) { 68 | if (field.getOption("packed") == Boolean.TRUE) { 69 | w.format(" LightProtoCodec.writeVarInt(_b, %s_PACKED);\n", tagName()); 70 | w.format(" int _%sSize = 0;\n", pluralName); 71 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 72 | w.format(" %s _item = %s[i];\n", field.getJavaType(), pluralName); 73 | w.format(" _%sSize += %s;\n", pluralName, LightProtoNumberField.serializedSizeOfNumber(field, "_item")); 74 | w.format("}\n"); 75 | w.format(" LightProtoCodec.writeVarInt(_b, _%sSize);\n", pluralName); 76 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 77 | w.format(" %s _item = %s[i];\n", field.getJavaType(), pluralName); 78 | LightProtoNumberField.serializeNumber(w, field, "_item"); 79 | w.format("}\n"); 80 | } else { 81 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 82 | w.format(" %s _item = %s[i];\n", field.getJavaType(), pluralName); 83 | w.format(" LightProtoCodec.writeVarInt(_b, %s);\n", tagName()); 84 | LightProtoNumberField.serializeNumber(w, field, "_item"); 85 | w.format("}\n"); 86 | } 87 | } 88 | 89 | @Override 90 | public void setter(PrintWriter w, String enclosingType) { 91 | w.format("public void %s(%s %s) {\n", Util.camelCase("add", singularName), field.getJavaType(), singularName); 92 | w.format(" if (%s == null) {\n", pluralName); 93 | w.format(" %s = new %s[4];\n", pluralName, field.getJavaType()); 94 | w.format(" }\n"); 95 | w.format(" if (%s.length == _%sCount) {\n", pluralName, pluralName); 96 | w.format(" %s = java.util.Arrays.copyOf(%s, _%sCount * 2);\n", pluralName, pluralName, pluralName); 97 | w.format(" }\n"); 98 | w.format(" _cachedSize = -1;\n"); 99 | w.format(" %s[_%sCount++] = %s;\n", pluralName, pluralName, singularName); 100 | w.format("}\n"); 101 | } 102 | 103 | @Override 104 | public void copy(PrintWriter w) { 105 | w.format("for (int i = 0; i < _other.%s(); i++) {\n", Util.camelCase("get", pluralName, "count")); 106 | w.format(" %s(_other.%s(i));\n", Util.camelCase("add", singularName), Util.camelCase("get", singularName, "at")); 107 | w.format("}\n"); 108 | } 109 | 110 | @Override 111 | public void serializedSize(PrintWriter w) { 112 | 113 | if (field.getOption("packed") == Boolean.TRUE) { 114 | w.format(" _size += %s_SIZE;\n", tagName()); 115 | w.format(" int _%sSize = 0;\n", pluralName); 116 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 117 | w.format(" %s _item = %s[i];\n", field.getJavaType(), pluralName); 118 | w.format(" _%sSize += %s;\n", pluralName, LightProtoNumberField.serializedSizeOfNumber(field, "_item")); 119 | w.format("}\n"); 120 | w.format(" _size += LightProtoCodec.computeVarIntSize(_%sSize);\n", pluralName); 121 | w.format(" _size += _%sSize;\n", pluralName); 122 | } else { 123 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 124 | w.format(" %s _item = %s[i];\n", field.getJavaType(), pluralName); 125 | w.format(" _size += %s_SIZE;\n", tagName()); 126 | w.format(" _size += %s;\n", LightProtoNumberField.serializedSizeOfNumber(field, "_item")); 127 | w.format("}\n"); 128 | } 129 | } 130 | 131 | @Override 132 | public void clear(PrintWriter w) { 133 | w.format("_%sCount = 0;\n", pluralName); 134 | } 135 | 136 | @Override 137 | protected String typeTag() { 138 | return LightProtoNumberField.typeTag(field); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoRepeatedStringField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Field; 19 | 20 | import java.io.PrintWriter; 21 | 22 | public class LightProtoRepeatedStringField extends LightProtoAbstractRepeated { 23 | 24 | protected final String pluralName; 25 | protected final String singularName; 26 | 27 | public LightProtoRepeatedStringField(Field.String field, int index) { 28 | super(field, index); 29 | this.pluralName = Util.plural(ccName); 30 | this.singularName = Util.singular(ccName); 31 | } 32 | 33 | @Override 34 | public void declaration(PrintWriter w) { 35 | w.format("private java.util.List %s = null;\n", pluralName); 36 | w.format("private int _%sCount = 0;\n", pluralName); 37 | } 38 | 39 | @Override 40 | public void parse(PrintWriter w) { 41 | w.format("LightProtoCodec.StringHolder _%sSh = _%sStringHolder();\n", ccName, Util.camelCase("new", singularName)); 42 | w.format("_%sSh.len = LightProtoCodec.readVarInt(_buffer);\n", ccName); 43 | w.format("_%sSh.idx = _buffer.readerIndex();\n", ccName); 44 | w.format("_buffer.skipBytes(_%sSh.len);\n", ccName); 45 | } 46 | 47 | @Override 48 | public void getter(PrintWriter w) { 49 | w.format("public int %s() {\n", Util.camelCase("get", pluralName, "count")); 50 | w.format(" return _%sCount;\n", pluralName); 51 | w.format("}\n"); 52 | w.format("public %s %s(int idx) {\n", field.getJavaType(), Util.camelCase("get", singularName, "at")); 53 | w.format(" if (idx < 0 || idx >= _%sCount) {\n", pluralName); 54 | w.format(" throw new IndexOutOfBoundsException(\"Index \" + idx + \" is out of the list size (\" + _%sCount + \") for field '%s'\");\n", pluralName, field.getName()); 55 | w.format(" }\n"); 56 | w.format(" LightProtoCodec.StringHolder _sh = %s.get(idx);\n", pluralName); 57 | w.format(" if (_sh.s == null) {\n"); 58 | w.format(" _sh.s = LightProtoCodec.readString(_parsedBuffer, _sh.idx, _sh.len);\n"); 59 | w.format(" }\n"); 60 | w.format(" return _sh.s;\n"); 61 | w.format("}\n"); 62 | 63 | w.format("public java.util.List %s() {\n", Util.camelCase("get", pluralName, "list")); 64 | w.format(" if (_%sCount == 0) {\n", pluralName); 65 | w.format(" return java.util.Collections.emptyList();\n"); 66 | w.format(" } else {\n"); 67 | w.format(" java.util.List _l = new java.util.ArrayList<>();\n"); 68 | w.format(" for (int i = 0; i < _%sCount; i++) {\n", pluralName); 69 | w.format(" _l.add(%s(i));\n", Util.camelCase("get", singularName, "at")); 70 | w.format(" }\n"); 71 | w.format(" return _l;\n"); 72 | w.format(" }\n"); 73 | w.format("}\n"); 74 | } 75 | 76 | @Override 77 | public void serialize(PrintWriter w) { 78 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 79 | w.format(" LightProtoCodec.StringHolder _sh = %s.get(i);\n", pluralName); 80 | w.format(" LightProtoCodec.writeVarInt(_b, %s);\n", tagName()); 81 | w.format(" LightProtoCodec.writeVarInt(_b, _sh.len);\n"); 82 | w.format(" if (_sh.idx == -1) {\n"); 83 | w.format(" LightProtoCodec.writeString(_b, _sh.s, _sh.len);\n"); 84 | w.format(" } else {\n"); 85 | w.format(" _parsedBuffer.getBytes(_sh.idx, _b, _sh.len);\n"); 86 | w.format(" }\n"); 87 | w.format("}\n"); 88 | } 89 | 90 | @Override 91 | public void copy(PrintWriter w) { 92 | w.format("for (int i = 0; i < _other.%s(); i++) {\n", Util.camelCase("get", pluralName, "count")); 93 | w.format(" %s(_other.%s(i));\n", Util.camelCase("add", singularName), Util.camelCase("get", singularName, "at")); 94 | w.format("}\n"); 95 | } 96 | 97 | @Override 98 | public void setter(PrintWriter w, String enclosingType) { 99 | w.format("public void %s(String %s) {\n", Util.camelCase("add", singularName), singularName); 100 | w.format(" if (%s == null) {\n", pluralName); 101 | w.format(" %s = new java.util.ArrayList();\n", pluralName); 102 | w.format(" }\n"); 103 | w.format(" LightProtoCodec.StringHolder _sh = _%sStringHolder();\n", Util.camelCase("new", singularName)); 104 | w.format(" _cachedSize = -1;\n"); 105 | w.format(" _sh.s = %s;\n", singularName); 106 | w.format(" _sh.idx = -1;\n"); 107 | w.format(" _sh.len = LightProtoCodec.computeStringUTF8Size(_sh.s);\n"); 108 | w.format("}\n"); 109 | 110 | w.format("public %s %s(Iterable %s) {\n", enclosingType, Util.camelCase("addAll", pluralName), pluralName); 111 | w.format(" for (String _s : %s) {\n", pluralName); 112 | w.format(" %s(_s);\n", Util.camelCase("add", singularName)); 113 | w.format(" }\n"); 114 | w.format(" return this;\n"); 115 | w.format("}\n"); 116 | 117 | 118 | w.format("private LightProtoCodec.StringHolder _%sStringHolder() {\n", Util.camelCase("new", singularName)); 119 | w.format(" if (%s == null) {\n", pluralName); 120 | w.format(" %s = new java.util.ArrayList();\n", pluralName); 121 | w.format(" }\n"); 122 | w.format(" LightProtoCodec.StringHolder _sh;\n"); 123 | w.format(" if (%s.size() == _%sCount) {\n", pluralName, pluralName); 124 | w.format(" _sh = new LightProtoCodec.StringHolder();\n"); 125 | w.format(" %s.add(_sh);\n", pluralName); 126 | w.format(" } else {\n"); 127 | w.format(" _sh = %s.get(_%sCount);\n", pluralName, pluralName); 128 | w.format(" }\n"); 129 | w.format(" _%sCount++;\n", pluralName); 130 | w.format(" return _sh;\n"); 131 | w.format("}\n"); 132 | } 133 | 134 | @Override 135 | public void serializedSize(PrintWriter w) { 136 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 137 | w.format(" LightProtoCodec.StringHolder _sh = %s.get(i);\n", pluralName); 138 | w.format(" _size += %s_SIZE;\n", tagName()); 139 | w.format(" _size += LightProtoCodec.computeVarIntSize(_sh.len) + _sh.len;\n"); 140 | w.format("}\n"); 141 | } 142 | 143 | @Override 144 | public void clear(PrintWriter w) { 145 | w.format("for (int i = 0; i < _%sCount; i++) {\n", pluralName); 146 | w.format(" LightProtoCodec.StringHolder _sh = %s.get(i);\n", pluralName); 147 | w.format(" _sh.s = null;\n"); 148 | w.format(" _sh.idx = -1;\n"); 149 | w.format(" _sh.len = -1;\n"); 150 | w.format("}\n"); 151 | w.format("_%sCount = 0;\n", pluralName); 152 | } 153 | 154 | @Override 155 | protected String typeTag() { 156 | return "LightProtoCodec.WIRETYPE_LENGTH_DELIMITED"; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/LightProtoStringField.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.protostuff.parser.Field; 19 | 20 | import java.io.PrintWriter; 21 | 22 | import static com.github.splunk.lightproto.generator.Util.camelCase; 23 | 24 | public class LightProtoStringField extends LightProtoField { 25 | 26 | public LightProtoStringField(Field.String field, int index) { 27 | super(field, index); 28 | } 29 | 30 | @Override 31 | public void declaration(PrintWriter w) { 32 | if (field.isDefaultValueSet()) { 33 | w.format("private String %s = \"%s\";\n", ccName, field.getDefaultValue()); 34 | } else { 35 | w.format("private String %s;\n", ccName); 36 | } 37 | w.format("private int _%sBufferIdx = -1;\n", ccName); 38 | w.format("private int _%sBufferLen = -1;\n", ccName); 39 | } 40 | 41 | @Override 42 | public void setter(PrintWriter w, String enclosingType) { 43 | w.format("public %s %s(%s %s) {\n", enclosingType, Util.camelCase("set", field.getName()), field.getJavaType(), camelCase(field.getName())); 44 | w.format(" this.%s = %s;\n", camelCase(field.getName()), camelCase(field.getName())); 45 | w.format(" _bitField%d |= %s;\n", bitFieldIndex(), fieldMask()); 46 | w.format(" _%sBufferIdx = -1;\n", ccName); 47 | w.format(" _%sBufferLen = LightProtoCodec.computeStringUTF8Size(%s);\n", ccName, ccName); 48 | w.format(" _cachedSize = -1;\n"); 49 | w.format(" return this;\n"); 50 | w.format("}\n"); 51 | } 52 | 53 | @Override 54 | public void copy(PrintWriter w) { 55 | w.format("%s(_other.%s());\n", Util.camelCase("set", ccName), Util.camelCase("get", ccName)); 56 | } 57 | 58 | @Override 59 | public void getter(PrintWriter w) { 60 | w.format("public %s %s() {\n", field.getJavaType(), Util.camelCase("get", field.getName())); 61 | if (!field.isDefaultValueSet()) { 62 | w.format(" if (!%s()) {\n", Util.camelCase("has", ccName)); 63 | w.format(" throw new IllegalStateException(\"Field '%s' is not set\");\n", field.getName()); 64 | w.format(" }\n"); 65 | } 66 | w.format(" if (%s == null) {\n", camelCase(field.getName())); 67 | w.format(" %s = LightProtoCodec.readString(_parsedBuffer, _%sBufferIdx, _%sBufferLen);\n", ccName, ccName, ccName); 68 | w.format(" }\n"); 69 | w.format(" return %s;\n", camelCase(field.getName())); 70 | w.format("}\n"); 71 | } 72 | 73 | @Override 74 | public void clear(PrintWriter w) { 75 | w.format("%s = %s;\n", ccName, field.getDefaultValue()); 76 | w.format("_%sBufferIdx = -1;\n", ccName); 77 | w.format("_%sBufferLen = -1;\n", ccName); 78 | } 79 | 80 | @Override 81 | public void serializedSize(PrintWriter w) { 82 | w.format("_size += %s_SIZE;\n", tagName()); 83 | w.format("_size += LightProtoCodec.computeVarIntSize(_%sBufferLen);\n", ccName); 84 | w.format("_size += _%sBufferLen;\n", ccName); 85 | } 86 | 87 | @Override 88 | public void serialize(PrintWriter w) { 89 | w.format("LightProtoCodec.writeVarInt(_b, %s);\n", tagName()); 90 | w.format("LightProtoCodec.writeVarInt(_b, _%sBufferLen);\n", ccName); 91 | w.format("if (_%sBufferIdx == -1) {\n", ccName); 92 | w.format(" LightProtoCodec.writeString(_b, %s, _%sBufferLen);\n", ccName, ccName); 93 | w.format("} else {\n"); 94 | w.format(" _parsedBuffer.getBytes(_%sBufferIdx, _b, _%sBufferLen);\n", ccName, ccName); 95 | w.format("}\n"); 96 | } 97 | 98 | @Override 99 | public void parse(PrintWriter w) { 100 | w.format("_%sBufferLen = LightProtoCodec.readVarInt(_buffer);\n", ccName); 101 | w.format("_%sBufferIdx = _buffer.readerIndex();\n", ccName); 102 | w.format("_buffer.skipBytes(_%sBufferLen);\n", ccName); 103 | } 104 | 105 | @Override 106 | protected String typeTag() { 107 | return "LightProtoCodec.WIRETYPE_LENGTH_DELIMITED"; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /code-generator/src/main/java/com/github/splunk/lightproto/generator/Util.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import org.jibx.schema.codegen.extend.DefaultNameConverter; 19 | import org.jibx.schema.codegen.extend.NameConverter; 20 | 21 | import static com.google.common.base.CaseFormat.LOWER_CAMEL; 22 | import static com.google.common.base.CaseFormat.LOWER_UNDERSCORE; 23 | 24 | public class Util { 25 | 26 | public static String camelCase(String... parts) { 27 | StringBuilder sb = new StringBuilder(); 28 | for (int i = 0; i < parts.length; i++) { 29 | String s = parts[i]; 30 | if (s == null || s.isEmpty()) { 31 | continue; 32 | } 33 | if (s.contains("_")) { 34 | s = LOWER_UNDERSCORE.to(LOWER_CAMEL, s); 35 | } 36 | 37 | if (i != 0) { 38 | sb.append(Character.toUpperCase(s.charAt(0))); 39 | sb.append(s.substring(1)); 40 | } else { 41 | sb.append(s); 42 | } 43 | } 44 | 45 | return sb.toString(); 46 | } 47 | 48 | public static String camelCaseFirstUpper(String... parts) { 49 | String s = camelCase(parts); 50 | return Character.toUpperCase(s.charAt(0)) + s.substring(1); 51 | } 52 | 53 | public static String upperCase(String... parts) { 54 | StringBuilder sb = new StringBuilder(); 55 | for (int i = 0; i < parts.length; i++) { 56 | String s = LOWER_CAMEL.to(LOWER_UNDERSCORE, parts[i]); 57 | if (i != 0) { 58 | sb.append('_'); 59 | } 60 | 61 | sb.append(s); 62 | } 63 | 64 | return sb.toString().toUpperCase(); 65 | } 66 | 67 | private static final NameConverter nameTools = new DefaultNameConverter(); 68 | 69 | public static String plural(String s) { 70 | return nameTools.pluralize(s); 71 | } 72 | 73 | public static String singular(String s) { 74 | return nameTools.depluralize(s); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /code-generator/src/main/resources/com/github/splunk/lightproto/generator/LightProtoCodec.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.generator; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.buffer.ByteBufUtil; 20 | 21 | import java.nio.charset.StandardCharsets; 22 | 23 | class LightProtoCodec { 24 | static final int TAG_TYPE_MASK = 7; 25 | static final int TAG_TYPE_BITS = 3; 26 | static final int WIRETYPE_VARINT = 0; 27 | static final int WIRETYPE_FIXED64 = 1; 28 | static final int WIRETYPE_LENGTH_DELIMITED = 2; 29 | static final int WIRETYPE_START_GROUP = 3; 30 | static final int WIRETYPE_END_GROUP = 4; 31 | static final int WIRETYPE_FIXED32 = 5; 32 | private LightProtoCodec() { 33 | } 34 | 35 | private static int getTagType(int tag) { 36 | return tag & TAG_TYPE_MASK; 37 | } 38 | 39 | static int getFieldId(int tag) { 40 | return tag >>> TAG_TYPE_BITS; 41 | } 42 | 43 | static void writeVarInt(ByteBuf b, int n) { 44 | if (n >= 0) { 45 | _writeVarInt(b, n); 46 | } else { 47 | writeVarInt64(b, n); 48 | } 49 | } 50 | 51 | static void writeSignedVarInt(ByteBuf b, int n) { 52 | writeVarInt(b, encodeZigZag32(n)); 53 | } 54 | 55 | static int readSignedVarInt(ByteBuf b) { 56 | return decodeZigZag32(readVarInt(b)); 57 | } 58 | 59 | static long readSignedVarInt64(ByteBuf b) { 60 | return decodeZigZag64(readVarInt64(b)); 61 | } 62 | 63 | static void writeFloat(ByteBuf b, float n) { 64 | writeFixedInt32(b, Float.floatToRawIntBits(n)); 65 | } 66 | 67 | static void writeDouble(ByteBuf b, double n) { 68 | writeFixedInt64(b, Double.doubleToRawLongBits(n)); 69 | } 70 | 71 | static float readFloat(ByteBuf b) { 72 | return Float.intBitsToFloat(readFixedInt32(b)); 73 | } 74 | 75 | static double readDouble(ByteBuf b) { 76 | return Double.longBitsToDouble(readFixedInt64(b)); 77 | } 78 | 79 | private static void _writeVarInt(ByteBuf b, int n) { 80 | while (true) { 81 | if ((n & ~0x7F) == 0) { 82 | b.writeByte(n); 83 | return; 84 | } else { 85 | b.writeByte((n & 0x7F) | 0x80); 86 | n >>>= 7; 87 | } 88 | } 89 | } 90 | 91 | static void writeVarInt64(ByteBuf b, long value) { 92 | while (true) { 93 | if ((value & ~0x7FL) == 0) { 94 | b.writeByte((int) value); 95 | return; 96 | } else { 97 | b.writeByte(((int) value & 0x7F) | 0x80); 98 | value >>>= 7; 99 | } 100 | } 101 | } 102 | 103 | static void writeFixedInt32(ByteBuf b, int n) { 104 | b.writeIntLE(n); 105 | } 106 | 107 | static void writeFixedInt64(ByteBuf b, long n) { 108 | b.writeLongLE(n); 109 | } 110 | 111 | static int readFixedInt32(ByteBuf b) { 112 | return b.readIntLE(); 113 | } 114 | 115 | static long readFixedInt64(ByteBuf b) { 116 | return b.readLongLE(); 117 | } 118 | 119 | 120 | static void writeSignedVarInt64(ByteBuf b, long n) { 121 | writeVarInt64(b, encodeZigZag64(n)); 122 | } 123 | 124 | private static int encodeZigZag32(final int n) { 125 | return (n << 1) ^ (n >> 31); 126 | } 127 | 128 | private static long encodeZigZag64(final long n) { 129 | return (n << 1) ^ (n >> 63); 130 | } 131 | 132 | private static int decodeZigZag32(int n) { 133 | return n >>> 1 ^ -(n & 1); 134 | } 135 | 136 | private static long decodeZigZag64(long n) { 137 | return n >>> 1 ^ -(n & 1L); 138 | } 139 | 140 | static int readVarInt(ByteBuf buf) { 141 | byte tmp = buf.readByte(); 142 | if (tmp >= 0) { 143 | return tmp; 144 | } 145 | int result = tmp & 0x7f; 146 | if ((tmp = buf.readByte()) >= 0) { 147 | result |= tmp << 7; 148 | } else { 149 | result |= (tmp & 0x7f) << 7; 150 | if ((tmp = buf.readByte()) >= 0) { 151 | result |= tmp << 14; 152 | } else { 153 | result |= (tmp & 0x7f) << 14; 154 | if ((tmp = buf.readByte()) >= 0) { 155 | result |= tmp << 21; 156 | } else { 157 | result |= (tmp & 0x7f) << 21; 158 | result |= (tmp = buf.readByte()) << 28; 159 | if (tmp < 0) { 160 | // Discard upper 32 bits. 161 | for (int i = 0; i < 5; i++) { 162 | if (buf.readByte() >= 0) { 163 | return result; 164 | } 165 | } 166 | throw new IllegalArgumentException("Encountered a malformed varint."); 167 | } 168 | } 169 | } 170 | } 171 | return result; 172 | } 173 | 174 | static long readVarInt64(ByteBuf buf) { 175 | int shift = 0; 176 | long result = 0; 177 | while (shift < 64) { 178 | final byte b = buf.readByte(); 179 | result |= (long) (b & 0x7F) << shift; 180 | if ((b & 0x80) == 0) { 181 | return result; 182 | } 183 | shift += 7; 184 | } 185 | throw new IllegalArgumentException("Encountered a malformed varint."); 186 | } 187 | 188 | static int computeSignedVarIntSize(final int value) { 189 | return computeVarUIntSize(encodeZigZag32(value)); 190 | } 191 | 192 | static int computeSignedVarInt64Size(final long value) { 193 | return computeVarInt64Size(encodeZigZag64(value)); 194 | } 195 | 196 | static int computeVarIntSize(final int value) { 197 | if (value < 0) { 198 | return 10; 199 | } else { 200 | return computeVarUIntSize(value); 201 | } 202 | } 203 | 204 | static int computeVarUIntSize(final int value) { 205 | if ((value & (0xffffffff << 7)) == 0) { 206 | return 1; 207 | } else if ((value & (0xffffffff << 14)) == 0) { 208 | return 2; 209 | } else if ((value & (0xffffffff << 21)) == 0) { 210 | return 3; 211 | } else if ((value & (0xffffffff << 28)) == 0) { 212 | return 4; 213 | } else { 214 | return 5; 215 | } 216 | } 217 | 218 | static int computeVarInt64Size(final long value) { 219 | if ((value & (0xffffffffffffffffL << 7)) == 0) { 220 | return 1; 221 | } else if ((value & (0xffffffffffffffffL << 14)) == 0) { 222 | return 2; 223 | } else if ((value & (0xffffffffffffffffL << 21)) == 0) { 224 | return 3; 225 | } else if ((value & (0xffffffffffffffffL << 28)) == 0) { 226 | return 4; 227 | } else if ((value & (0xffffffffffffffffL << 35)) == 0) { 228 | return 5; 229 | } else if ((value & (0xffffffffffffffffL << 42)) == 0) { 230 | return 6; 231 | } else if ((value & (0xffffffffffffffffL << 49)) == 0) { 232 | return 7; 233 | } else if ((value & (0xffffffffffffffffL << 56)) == 0) { 234 | return 8; 235 | } else if ((value & (0xffffffffffffffffL << 63)) == 0) { 236 | return 9; 237 | } else { 238 | return 10; 239 | } 240 | } 241 | 242 | static int computeStringUTF8Size(String s) { 243 | return ByteBufUtil.utf8Bytes(s); 244 | } 245 | 246 | static void writeString(ByteBuf b, String s, int bytesCount) { 247 | ByteBufUtil.reserveAndWriteUtf8(b, s, bytesCount); 248 | } 249 | 250 | static String readString(ByteBuf b, int index, int len) { 251 | return b.toString(index, len, StandardCharsets.UTF_8); 252 | } 253 | 254 | static void skipUnknownField(int tag, ByteBuf buffer) { 255 | int tagType = getTagType(tag); 256 | switch (tagType) { 257 | case WIRETYPE_VARINT: 258 | readVarInt(buffer); 259 | break; 260 | case WIRETYPE_FIXED64: 261 | buffer.skipBytes(8); 262 | break; 263 | case WIRETYPE_LENGTH_DELIMITED: 264 | int len = readVarInt(buffer); 265 | buffer.skipBytes(len); 266 | break; 267 | case WIRETYPE_FIXED32: 268 | buffer.skipBytes(4); 269 | break; 270 | default: 271 | throw new IllegalArgumentException("Invalid unknonwn tag type: " + tagType); 272 | } 273 | } 274 | 275 | static final class StringHolder { 276 | String s; 277 | int idx; 278 | int len; 279 | } 280 | 281 | static final class BytesHolder { 282 | ByteBuf b; 283 | int idx; 284 | int len; 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /license-header.txt: -------------------------------------------------------------------------------- 1 | Copyright 2020 Splunk Inc. 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. -------------------------------------------------------------------------------- /maven-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 21 | 4.0.0 22 | 23 | com.github.splunk.lightproto 24 | lightproto 25 | 0.5-SNAPSHOT 26 | ../pom.xml 27 | 28 | 29 | lightproto-maven-plugin 30 | maven-plugin 31 | 32 | lightproto-maven-plugin 33 | 34 | 35 | 36 | ${project.groupId} 37 | lightproto-code-generator 38 | ${project.version} 39 | 40 | 41 | 42 | org.apache.maven 43 | maven-plugin-api 44 | 2.0 45 | 46 | 47 | org.apache.maven.plugin-tools 48 | maven-plugin-annotations 49 | 3.2 50 | provided 51 | 52 | 53 | org.apache.maven 54 | maven-project 55 | 2.2.1 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-plugin-plugin 64 | 65 | lightproto 66 | true 67 | 68 | 69 | 70 | mojo-descriptor 71 | 72 | descriptor 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /maven-plugin/src/main/java/com/github/splunk/lightproto/maven/plugin/LightProtoMojo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.maven.plugin; 17 | 18 | import com.github.splunk.lightproto.generator.LightProtoGenerator; 19 | import org.apache.maven.plugin.AbstractMojo; 20 | import org.apache.maven.plugin.MojoExecutionException; 21 | import org.apache.maven.plugins.annotations.LifecyclePhase; 22 | import org.apache.maven.plugins.annotations.Mojo; 23 | import org.apache.maven.plugins.annotations.Parameter; 24 | import org.apache.maven.plugins.annotations.ResolutionScope; 25 | import org.apache.maven.project.MavenProject; 26 | 27 | import java.io.File; 28 | import java.util.Arrays; 29 | import java.util.List; 30 | 31 | /** 32 | * Goal which generates Java code from the proto definition 33 | */ 34 | @Mojo( 35 | name = "generate", 36 | defaultPhase = LifecyclePhase.GENERATE_SOURCES, 37 | requiresDependencyResolution = ResolutionScope.COMPILE, 38 | threadSafe = true 39 | ) 40 | public class LightProtoMojo extends AbstractMojo { 41 | 42 | @Parameter(property = "classPrefix", defaultValue = "", required = false) 43 | private String classPrefix; 44 | 45 | @Parameter(property = "singleOuterClass", defaultValue = "false", required = false) 46 | private boolean singleOuterClass; 47 | 48 | @Parameter(property = "sources", required = false) 49 | private List sources; 50 | 51 | @Parameter(defaultValue = "${project}", required = true, readonly = true) 52 | private MavenProject project; 53 | 54 | @Parameter(defaultValue="generated-sources/protobuf/java", required = false) 55 | private String targetSourcesSubDir; 56 | 57 | @Parameter(defaultValue="generated-test-sources/protobuf/java", required = false) 58 | private String targetTestSourcesSubDir; 59 | 60 | private void generate(List protoFiles, File outputDirectory) throws MojoExecutionException { 61 | try { 62 | LightProtoGenerator.generate(protoFiles, outputDirectory, classPrefix, singleOuterClass); 63 | } catch (Exception e) { 64 | getLog().error("Failed to generate lightproto code for " + protoFiles + ": " + e.getMessage(), e); 65 | throw new MojoExecutionException("Failed to generate lightproto code for " + protoFiles, e); 66 | 67 | } 68 | } 69 | 70 | public void execute() throws MojoExecutionException { 71 | File baseDir = project.getBasedir(); 72 | File targetDir = new File(project.getBuild().getDirectory()); 73 | 74 | if (sources == null || sources.isEmpty()) { 75 | File[] mainFilesArray = new File(baseDir, "src/main/proto").listFiles((dir, name) -> name.endsWith(".proto")); 76 | if (mainFilesArray != null && mainFilesArray.length > 0) { 77 | List mainFiles = Arrays.asList(mainFilesArray); 78 | File generatedSourcesDir = new File(targetDir, targetSourcesSubDir); 79 | generate(mainFiles, new File(targetDir, targetSourcesSubDir)); 80 | 81 | project.addCompileSourceRoot(generatedSourcesDir.toString()); 82 | } 83 | 84 | File[] testFilesArray = new File(baseDir, "src/test/proto").listFiles((dir, name) -> name.endsWith(".proto")); 85 | if (testFilesArray != null && testFilesArray.length > 0) { 86 | List testFiles = Arrays.asList(testFilesArray); 87 | File generatedTestSourcesDir = new File(targetDir, targetTestSourcesSubDir); 88 | generate(testFiles, generatedTestSourcesDir); 89 | 90 | project.addTestCompileSourceRoot(generatedTestSourcesDir.toString()); 91 | } 92 | } else { 93 | File generatedSourcesDir = new File(targetDir, targetSourcesSubDir); 94 | generate(sources, generatedSourcesDir); 95 | project.addCompileSourceRoot(generatedSourcesDir.toString()); 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 22 | 4.0.0 23 | 24 | com.github.splunk.lightproto 25 | lightproto 26 | 0.5-SNAPSHOT 27 | pom 28 | 29 | lightproto 30 | https://github.com/splunk/lightproto 31 | Protobuf compatible code generator 32 | 33 | 34 | Splunk 35 | https://splunk.com 36 | 37 | 2020 38 | 39 | 40 | 41 | Splunk Inc. 42 | https://splunk.com/ 43 | 44 | 45 | 46 | 47 | https://github.com/splunk/lightproto 48 | scm:git:https://github.com/splunk/lightproto.git 49 | scm:git:ssh://git@github.com:splunk/lightproto.git 50 | 51 | 52 | 53 | 54 | Apache License, Version 2.0 55 | https://www.apache.org/licenses/LICENSE-2.0.txt 56 | repo 57 | 58 | 59 | 60 | 61 | UTF-8 62 | 3.13.0 63 | ${protobuf.version} 64 | 65 | 1.7.2 66 | 1.7.25 67 | 5.7.0 68 | 30.1-jre 69 | 4.1.56.Final 70 | 1.3.3 71 | 2.22.2.Final 72 | 73 | 1.27 74 | 75 | 3.8.1 76 | 3.0.0-M5 77 | 3.2.1 78 | 3.6.0 79 | 1.6 80 | 3.2.0 81 | 1.6.8 82 | 0.6.1 83 | 1.6.2 84 | 3.0 85 | 86 | 87 | 88 | code-generator 89 | benchmark 90 | maven-plugin 91 | tests 92 | 93 | 94 | 95 | 96 | 97 | org.apache.maven.plugins 98 | maven-compiler-plugin 99 | ${maven-compiler.version} 100 | 101 | 1.8 102 | 1.8 103 | 1.8 104 | 105 | 106 | 107 | 108 | com.mycila 109 | license-maven-plugin 110 | ${license-maven-plugin.version} 111 | 112 |
license-header.txt
113 | 114 | 115 | LICENSE 116 | NOTICE 117 | 118 | 119 | JAVADOC_STYLE 120 | 121 |
122 |
123 | 124 | org.apache.maven.plugins 125 | maven-gpg-plugin 126 | ${maven-gpg-plugin.version} 127 | 128 | 129 | sign-artifacts 130 | verify 131 | 132 | sign 133 | 134 | 135 | 136 | 137 | 138 | org.sonatype.plugins 139 | nexus-staging-maven-plugin 140 | ${nexus-staging-maven-plugin.version} 141 | true 142 | 143 | ossrh 144 | https://oss.sonatype.org/ 145 | true 146 | 147 | 148 |
149 | 150 | 151 | 152 | 153 | org.xolstice.maven.plugins 154 | protobuf-maven-plugin 155 | ${protobuf-maven-plugin.version} 156 | 157 | 158 | maven-surefire-plugin 159 | ${maven-surefire.version} 160 | 161 | 162 | org.apache.maven.plugins 163 | maven-plugin-plugin 164 | ${maven-plugin-plugin.version} 165 | 166 | 167 | 168 |
169 | 170 | 171 | 172 | 173 | io.protostuff 174 | protostuff-parser 175 | ${protostuff.version} 176 | 177 | 178 | 179 | org.junit 180 | junit-bom 181 | ${junit.version} 182 | pom 183 | import 184 | 185 | 186 | 187 | org.slf4j 188 | slf4j-api 189 | ${slf4j.version} 190 | 191 | 192 | com.google.guava 193 | guava 194 | ${guava.version} 195 | 196 | 197 | io.netty 198 | netty-bom 199 | ${netty.version} 200 | pom 201 | import 202 | 203 | 204 | com.google.protobuf 205 | protobuf-java 206 | ${protobuf.version} 207 | 208 | 209 | 210 | org.jibx 211 | jibx-tools 212 | ${jibx.version} 213 | 214 | 215 | 216 | org.openjdk.jmh 217 | jmh-core 218 | ${jmh.version} 219 | 220 | 221 | org.openjdk.jmh 222 | jmh-generator-annprocess 223 | ${jmh.version} 224 | provided 225 | 226 | 227 | 228 | org.jboss.forge.roaster 229 | roaster-api 230 | ${roaster.version} 231 | 232 | 233 | org.jboss.forge.roaster 234 | roaster-jdt 235 | ${roaster.version} 236 | 237 | 238 | 239 | org.junit.jupiter 240 | junit-jupiter 241 | ${junit.version} 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | release 250 | 251 | 252 | 253 | org.apache.maven.plugins 254 | maven-source-plugin 255 | ${maven-source-plugin.version} 256 | 257 | 258 | attach-sources 259 | 260 | jar-no-fork 261 | 262 | 263 | 264 | 265 | 266 | org.apache.maven.plugins 267 | maven-javadoc-plugin 268 | ${maven-javadoc-plugin.version} 269 | 270 | 271 | attach-javadocs 272 | 273 | jar 274 | 275 | 276 | 277 | 278 | 279 | org.apache.maven.plugins 280 | maven-gpg-plugin 281 | ${maven-gpg-plugin.version} 282 | 283 | 284 | sign-artifacts 285 | verify 286 | 287 | sign 288 | 289 | 290 | 291 | 292 | 293 | org.sonatype.plugins 294 | nexus-staging-maven-plugin 295 | ${nexus-staging-maven-plugin.version} 296 | true 297 | 298 | ossrh 299 | https://oss.sonatype.org/ 300 | true 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | ossrh 312 | https://oss.sonatype.org/content/repositories/snapshots 313 | 314 | 315 | ossrh 316 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 317 | 318 | 319 |
320 | -------------------------------------------------------------------------------- /tests/pom.xml: -------------------------------------------------------------------------------- 1 | 18 | 21 | 4.0.0 22 | 23 | com.github.splunk.lightproto 24 | lightproto 25 | 0.5-SNAPSHOT 26 | 27 | lightproto-tests 28 | 29 | 30 | 31 | 32 | com.google.protobuf 33 | protobuf-java 34 | 35 | 36 | 37 | io.netty 38 | netty-buffer 39 | 40 | 41 | 42 | org.junit.jupiter 43 | junit-jupiter 44 | test 45 | 46 | 47 | 48 | 49 | 50 | 51 | kr.motd.maven 52 | os-maven-plugin 53 | 1.6.2 54 | 55 | 56 | 57 | 58 | 59 | org.xolstice.maven.plugins 60 | protobuf-maven-plugin 61 | 62 | com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} 63 | 64 | true 65 | 66 | 67 | 68 | generate-sources 69 | 70 | compile 71 | 72 | 73 | 74 | 75 | 76 | 77 | ${project.groupId} 78 | lightproto-maven-plugin 79 | ${project.version} 80 | 81 | 82 | 83 | generate 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /tests/src/main/proto/PulsarMarkers.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | syntax = "proto2"; 17 | 18 | package pulsar.proto; 19 | option java_package = "org.apache.pulsar.common.api.proto"; 20 | option optimize_for = LITE_RUNTIME; 21 | 22 | enum MarkerType { 23 | UNKNOWN_MARKER = 0; 24 | 25 | // Replicated subscription markers 26 | REPLICATED_SUBSCRIPTION_SNAPSHOT_REQUEST = 10; 27 | REPLICATED_SUBSCRIPTION_SNAPSHOT_RESPONSE = 11; 28 | REPLICATED_SUBSCRIPTION_SNAPSHOT = 12; 29 | REPLICATED_SUBSCRIPTION_UPDATE = 13; 30 | 31 | // Next markers start at 20 32 | TXN_COMMITTING = 20; 33 | TXN_COMMIT = 21; 34 | TXN_ABORT = 22; 35 | } 36 | 37 | /// --- Replicated subscriptions --- 38 | 39 | // A cluster uses this message to request the current 40 | // message id from all the other clusters. 41 | message ReplicatedSubscriptionsSnapshotRequest { 42 | required string snapshot_id = 1; 43 | optional string source_cluster = 2; 44 | } 45 | 46 | // When a cluster receives the snapshot request, it replies 47 | // by sending back the response (only to original asking cluster) 48 | message ReplicatedSubscriptionsSnapshotResponse { 49 | required string snapshot_id = 1; 50 | optional ClusterMessageId cluster = 2; 51 | } 52 | 53 | // This message is used to store the snapshot in the 54 | // local topic. It's not meant to be replicated to other 55 | // clusters 56 | message ReplicatedSubscriptionsSnapshot { 57 | required string snapshot_id = 1; 58 | optional MessageIdDataX local_message_id = 2; 59 | repeated ClusterMessageId clusters = 3; 60 | } 61 | 62 | // When the replicated subscription mark-delete position 63 | // is updated in the source cluster, this message will be 64 | // sent to all clusters to updated the mirrored subscriptions 65 | message ReplicatedSubscriptionsUpdate { 66 | required string subscription_name = 1; 67 | repeated ClusterMessageId clusters = 2; 68 | } 69 | 70 | message MessageIdDataX { 71 | required uint64 ledger_id = 1; 72 | required uint64 entry_id = 2; 73 | } 74 | 75 | // Represent one cluster and an associated message id. 76 | // The message id is local to that particular cluster 77 | message ClusterMessageId { 78 | required string cluster = 1; 79 | required MessageIdDataX message_id = 2; 80 | } 81 | 82 | /// --- Transaction marker --- 83 | message TxnCommitMarker { 84 | repeated MessageIdDataX message_id = 1; 85 | } -------------------------------------------------------------------------------- /tests/src/main/proto/Test.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | syntax = "proto2"; 17 | package com.github.splunk.lightproto.tests; 18 | 19 | message Point { 20 | required int32 x = 1; 21 | required int32 y = 2; 22 | optional int32 z = 3; 23 | } 24 | 25 | message Frame { 26 | required string name = 1; 27 | required Point point = 2; 28 | } 29 | -------------------------------------------------------------------------------- /tests/src/main/proto/addressbook.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | syntax = "proto2"; 17 | package tutorial; 18 | 19 | option java_package = "com.github.splunk.lightproto.tests"; 20 | option java_outer_classname = "AddressBookProtos"; 21 | 22 | message Person { 23 | required string name = 1; 24 | required int32 id = 2; 25 | optional string email = 3; 26 | 27 | enum PhoneType { 28 | MOBILE = 0; 29 | HOME = 1; 30 | WORK = 2; 31 | } 32 | 33 | message PhoneNumber { 34 | required string number = 1; 35 | optional PhoneType type = 2 [default = HOME]; 36 | } 37 | 38 | repeated PhoneNumber phone = 4; 39 | } 40 | 41 | // Our address book file is just one of these. 42 | message AddressBook { 43 | repeated Person person = 1; 44 | } 45 | -------------------------------------------------------------------------------- /tests/src/main/proto/bytes.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | syntax = "proto2"; 17 | package com.github.splunk.lightproto.tests; 18 | 19 | message B { 20 | optional bytes payload = 1; 21 | repeated bytes extra_items = 2; 22 | } 23 | -------------------------------------------------------------------------------- /tests/src/main/proto/enums.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | syntax = "proto2"; 17 | package com.github.splunk.lightproto.tests; 18 | 19 | enum E1 { 20 | A1 = 1; 21 | B1 = 2; 22 | C1 = 5; 23 | } 24 | 25 | enum E2 { 26 | A2 = 1; 27 | B2 = 2; 28 | C2 = 5; 29 | D2 = 6; 30 | } 31 | 32 | message EnumTest1 { 33 | required E1 e = 1; 34 | } 35 | 36 | message EnumTest2 { 37 | required E2 e = 1; 38 | } 39 | 40 | message EnumTest1Optional { 41 | optional E1 e = 1; 42 | } 43 | 44 | message EnumTest1Repeated { 45 | repeated E1 e = 1; 46 | } 47 | 48 | message EnumTest2Repeated { 49 | repeated E2 e = 1; 50 | } 51 | 52 | message EnumTest1Packed { 53 | repeated E1 e = 1 [packed = true]; 54 | } 55 | 56 | message EnumTest2Packed { 57 | repeated E2 e = 1 [packed = true]; 58 | } 59 | -------------------------------------------------------------------------------- /tests/src/main/proto/messages.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | syntax = "proto2"; 17 | package com.github.splunk.lightproto.tests; 18 | 19 | message X { 20 | optional string a = 1; 21 | optional string b = 2; 22 | } 23 | 24 | message M { 25 | message KV { 26 | message XX { 27 | optional int32 n = 1; 28 | } 29 | 30 | required string k = 1; 31 | required string v = 2; 32 | optional XX xx = 3; 33 | } 34 | 35 | optional X x = 1; 36 | repeated KV items = 2; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /tests/src/main/proto/numbers.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | syntax = "proto2"; 17 | package com.github.splunk.lightproto.tests; 18 | 19 | 20 | enum Enum1 { 21 | X1_0 = 0; 22 | X1_1 = 1; 23 | X1_2 = 2; 24 | } 25 | 26 | message Numbers { 27 | enum Enum2 { 28 | X2_0 = 0; 29 | X2_1 = 1; 30 | X2_2 = 2; 31 | } 32 | 33 | optional int32 x_int32 = 1; 34 | optional int64 x_int64 = 2; 35 | optional uint32 x_uint32 = 3; 36 | optional uint64 x_uint64 = 4; 37 | optional sint32 x_sint32 = 5; 38 | optional sint64 x_sint64 = 6; 39 | optional fixed32 x_fixed32 = 7; 40 | optional fixed64 x_fixed64 = 8; 41 | optional sfixed32 x_sfixed32 = 9; 42 | optional sfixed64 x_sfixed64 = 10; 43 | optional float x_float = 11; 44 | optional double x_double = 12; 45 | optional bool x_bool = 13; 46 | optional Enum1 enum1 = 14; 47 | optional Enum2 enum2 = 15; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /tests/src/main/proto/repeated_numbers.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | syntax = "proto2"; 17 | package com.github.splunk.lightproto.tests; 18 | 19 | message Repeated { 20 | enum Enum { 21 | X2_0 = 0; 22 | X2_1 = 1; 23 | X2_2 = 2; 24 | } 25 | 26 | repeated int32 x_int32 = 1; 27 | repeated int64 x_int64 = 2; 28 | repeated uint32 x_uint32 = 3; 29 | repeated uint64 x_uint64 = 4; 30 | repeated sint32 x_sint32 = 5; 31 | repeated sint64 x_sint64 = 6; 32 | repeated fixed32 x_fixed32 = 7; 33 | repeated fixed64 x_fixed64 = 8; 34 | repeated sfixed32 x_sfixed32 = 9; 35 | repeated sfixed64 x_sfixed64 = 10; 36 | repeated float x_float = 11; 37 | repeated double x_double = 12; 38 | repeated bool x_bool = 13; 39 | repeated Enum enum1 = 14; 40 | } 41 | 42 | // Same as above but packed 43 | message RepeatedPacked { 44 | enum Enum { 45 | X2_0 = 0; 46 | X2_1 = 1; 47 | X2_2 = 2; 48 | } 49 | 50 | repeated Enum enum1 = 1 [packed = true]; 51 | repeated int64 x_int64 = 2 [packed = true]; 52 | repeated uint32 x_uint32 = 3 [packed = true]; 53 | repeated uint64 x_uint64 = 4 [packed = true]; 54 | repeated sint32 x_sint32 = 5 [packed = true]; 55 | repeated sint64 x_sint64 = 6 [packed = true]; 56 | repeated fixed32 x_fixed32 = 7 [packed = true]; 57 | repeated fixed64 x_fixed64 = 8 [packed = true]; 58 | repeated sfixed32 x_sfixed32 = 9 [packed = true]; 59 | repeated sfixed64 x_sfixed64 = 10 [packed = true]; 60 | repeated float x_float = 11 [packed = true]; 61 | repeated double x_double = 12 [packed = true]; 62 | repeated bool x_bool = 13 [packed = true]; 63 | repeated int32 x_int32 = 14 [packed = true]; 64 | } 65 | -------------------------------------------------------------------------------- /tests/src/main/proto/required.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | syntax = "proto2"; 17 | package com.github.splunk.lightproto.tests; 18 | 19 | message R { 20 | required int32 a = 1; 21 | optional int32 b = 2; 22 | optional int32 c = 3 [default = 5]; 23 | } 24 | 25 | // Same as above but with no required field. 26 | message NR { 27 | optional int32 a = 1; 28 | optional int32 b = 2; 29 | optional int32 c = 3 [default = 5]; 30 | } 31 | 32 | // Same as above, but with additional field 33 | message RExt { 34 | required int32 a = 1; 35 | optional int32 b = 2; 36 | optional int32 c = 3 [default = 5]; 37 | 38 | optional int32 ext_d = 4; 39 | optional fixed32 ext_e = 5; 40 | optional fixed64 ext_f = 6; 41 | optional string ext_g = 7; 42 | } 43 | -------------------------------------------------------------------------------- /tests/src/main/proto/strings.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | syntax = "proto2"; 17 | package com.github.splunk.lightproto.tests; 18 | 19 | message S { 20 | optional string id = 1; 21 | repeated string names = 2; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /tests/src/test/java/com/github/splunk/lightproto/tests/AddressBookTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.tests; 17 | 18 | import com.google.protobuf.CodedOutputStream; 19 | import io.netty.buffer.ByteBuf; 20 | import io.netty.buffer.Unpooled; 21 | import org.junit.jupiter.api.BeforeEach; 22 | import org.junit.jupiter.api.Test; 23 | 24 | import java.util.Arrays; 25 | 26 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 27 | import static org.junit.jupiter.api.Assertions.assertEquals; 28 | 29 | public class AddressBookTest { 30 | 31 | private byte[] b1 = new byte[4096]; 32 | private ByteBuf bb1 = Unpooled.wrappedBuffer(b1); 33 | 34 | private byte[] b2 = new byte[4096]; 35 | 36 | @BeforeEach 37 | public void setup() { 38 | bb1.clear(); 39 | Arrays.fill(b1, (byte) 0); 40 | Arrays.fill(b2, (byte) 0); 41 | } 42 | 43 | @Test 44 | public void testAddressBook() throws Exception { 45 | AddressBook ab = new AddressBook(); 46 | Person p1 = ab.addPerson() 47 | .setName("name 1") 48 | .setEmail("name1@example.com") 49 | .setId(5); 50 | p1.addPhone() 51 | .setNumber("xxx-zzz-1111") 52 | .setType(Person.PhoneType.HOME); 53 | p1.addPhone() 54 | .setNumber("xxx-zzz-2222") 55 | .setType(Person.PhoneType.MOBILE); 56 | 57 | Person p2 = ab.addPerson() 58 | .setName("name 2") 59 | .setEmail("name2@example.com") 60 | .setId(6); 61 | p2.addPhone() 62 | .setNumber("xxx-zzz-2222") 63 | .setType(Person.PhoneType.HOME); 64 | 65 | assertEquals(2, ab.getPersonsCount()); 66 | assertEquals("name 1", ab.getPersonAt(0).getName()); 67 | assertEquals("name1@example.com", ab.getPersonAt(0).getEmail()); 68 | assertEquals(5, ab.getPersonAt(0).getId()); 69 | assertEquals("xxx-zzz-1111", ab.getPersonAt(0).getPhoneAt(0).getNumber()); 70 | assertEquals(Person.PhoneType.HOME, ab.getPersonAt(0).getPhoneAt(0).getType()); 71 | assertEquals("name 2", ab.getPersonAt(1).getName()); 72 | assertEquals("name2@example.com", ab.getPersonAt(1).getEmail()); 73 | assertEquals(6, ab.getPersonAt(1).getId()); 74 | assertEquals("xxx-zzz-2222", ab.getPersonAt(1).getPhoneAt(0).getNumber()); 75 | assertEquals(Person.PhoneType.HOME, ab.getPersonAt(0).getPhoneAt(0).getType()); 76 | 77 | AddressBookProtos.AddressBook.Builder pbab = AddressBookProtos.AddressBook.newBuilder(); 78 | AddressBookProtos.Person.Builder pb_p1 = AddressBookProtos.Person.newBuilder(); 79 | pb_p1.setName("name 1"); 80 | pb_p1.setEmail("name1@example.com"); 81 | pb_p1.setId(5); 82 | AddressBookProtos.Person.PhoneNumber.Builder pb1_pn1 = AddressBookProtos.Person.PhoneNumber.newBuilder(); 83 | pb1_pn1.setNumber("xxx-zzz-1111"); 84 | pb1_pn1.setType(AddressBookProtos.Person.PhoneType.HOME); 85 | 86 | AddressBookProtos.Person.PhoneNumber.Builder pb1_pn2 = AddressBookProtos.Person.PhoneNumber.newBuilder(); 87 | pb1_pn2.setNumber("xxx-zzz-2222"); 88 | pb1_pn2.setType(AddressBookProtos.Person.PhoneType.MOBILE); 89 | 90 | pb_p1.addPhone(pb1_pn1); 91 | pb_p1.addPhone(pb1_pn2); 92 | 93 | AddressBookProtos.Person.Builder pb_p2 = AddressBookProtos.Person.newBuilder(); 94 | pb_p2.setName("name 2"); 95 | pb_p2.setEmail("name2@example.com"); 96 | pb_p2.setId(6); 97 | 98 | AddressBookProtos.Person.PhoneNumber.Builder pb2_pn1 = AddressBookProtos.Person.PhoneNumber.newBuilder(); 99 | pb2_pn1.setNumber("xxx-zzz-2222"); 100 | pb2_pn1.setType(AddressBookProtos.Person.PhoneType.HOME); 101 | 102 | pb_p2.addPhone(pb2_pn1); 103 | 104 | pbab.addPerson(pb_p1); 105 | pbab.addPerson(pb_p2); 106 | 107 | assertEquals(pbab.build().getSerializedSize(), ab.getSerializedSize()); 108 | 109 | ab.writeTo(bb1); 110 | assertEquals(ab.getSerializedSize(), bb1.readableBytes()); 111 | 112 | pbab.build().writeTo(CodedOutputStream.newInstance(b2)); 113 | 114 | assertArrayEquals(b1, b2); 115 | 116 | AddressBook parsed = new AddressBook(); 117 | parsed.parseFrom(bb1, bb1.readableBytes()); 118 | 119 | assertEquals(2, parsed.getPersonsCount()); 120 | assertEquals("name 1", parsed.getPersonAt(0).getName()); 121 | assertEquals("name1@example.com", parsed.getPersonAt(0).getEmail()); 122 | assertEquals(5, parsed.getPersonAt(0).getId()); 123 | assertEquals("xxx-zzz-1111", parsed.getPersonAt(0).getPhoneAt(0).getNumber()); 124 | assertEquals(Person.PhoneType.HOME, parsed.getPersonAt(0).getPhoneAt(0).getType()); 125 | assertEquals("name 2", parsed.getPersonAt(1).getName()); 126 | assertEquals("name2@example.com", parsed.getPersonAt(1).getEmail()); 127 | assertEquals(6, parsed.getPersonAt(1).getId()); 128 | assertEquals("xxx-zzz-2222", parsed.getPersonAt(1).getPhoneAt(0).getNumber()); 129 | assertEquals(Person.PhoneType.HOME, parsed.getPersonAt(1).getPhoneAt(0).getType()); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /tests/src/test/java/com/github/splunk/lightproto/tests/BytesTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.tests; 17 | 18 | import com.google.protobuf.ByteString; 19 | import com.google.protobuf.CodedOutputStream; 20 | import io.netty.buffer.ByteBuf; 21 | import io.netty.buffer.Unpooled; 22 | import org.junit.jupiter.api.BeforeEach; 23 | import org.junit.jupiter.api.Test; 24 | 25 | import java.util.Arrays; 26 | 27 | import static org.junit.jupiter.api.Assertions.*; 28 | 29 | public class BytesTest { 30 | 31 | private byte[] b1 = new byte[4096]; 32 | private ByteBuf bb1 = Unpooled.wrappedBuffer(b1); 33 | 34 | private byte[] b2 = new byte[4096]; 35 | 36 | @BeforeEach 37 | public void setup() { 38 | bb1.clear(); 39 | Arrays.fill(b1, (byte) 0); 40 | Arrays.fill(b2, (byte) 0); 41 | } 42 | 43 | @Test 44 | public void testBytes() throws Exception { 45 | B lpb = new B() 46 | .setPayload(new byte[]{1, 2, 3}); 47 | 48 | assertTrue(lpb.hasPayload()); 49 | assertEquals(3, lpb.getPayloadSize()); 50 | assertArrayEquals(new byte[]{1, 2, 3}, lpb.getPayload()); 51 | 52 | Bytes.B pbb = Bytes.B.newBuilder() 53 | .setPayload(ByteString.copyFrom(new byte[]{1, 2, 3})) 54 | .build(); 55 | 56 | assertEquals(pbb.getSerializedSize(), lpb.getSerializedSize()); 57 | lpb.writeTo(bb1); 58 | assertEquals(lpb.getSerializedSize(), bb1.readableBytes()); 59 | 60 | pbb.writeTo(CodedOutputStream.newInstance(b2)); 61 | 62 | assertArrayEquals(b1, b2); 63 | 64 | B parsed = new B(); 65 | parsed.parseFrom(bb1, bb1.readableBytes()); 66 | 67 | assertTrue(parsed.hasPayload()); 68 | assertEquals(3, parsed.getPayloadSize()); 69 | assertArrayEquals(new byte[]{1, 2, 3}, parsed.getPayload()); 70 | } 71 | 72 | @Test 73 | public void testBytesBuf() throws Exception { 74 | B lpb = new B(); 75 | ByteBuf b = Unpooled.directBuffer(3); 76 | b.writeBytes(new byte[]{1, 2, 3}); 77 | lpb.setPayload(b); 78 | 79 | assertTrue(lpb.hasPayload()); 80 | assertEquals(3, lpb.getPayloadSize()); 81 | assertArrayEquals(new byte[]{1, 2, 3}, lpb.getPayload()); 82 | assertEquals(Unpooled.wrappedBuffer(new byte[]{1, 2, 3}), lpb.getPayloadSlice()); 83 | 84 | Bytes.B pbb = Bytes.B.newBuilder() 85 | .setPayload(ByteString.copyFrom(new byte[]{1, 2, 3})) 86 | .build(); 87 | 88 | assertEquals(pbb.getSerializedSize(), lpb.getSerializedSize()); 89 | lpb.writeTo(bb1); 90 | assertEquals(lpb.getSerializedSize(), bb1.readableBytes()); 91 | 92 | pbb.writeTo(CodedOutputStream.newInstance(b2)); 93 | 94 | assertArrayEquals(b1, b2); 95 | 96 | B parsed = new B(); 97 | parsed.parseFrom(bb1, bb1.readableBytes()); 98 | 99 | assertTrue(parsed.hasPayload()); 100 | assertEquals(3, parsed.getPayloadSize()); 101 | assertEquals(Unpooled.wrappedBuffer(new byte[]{1, 2, 3}), parsed.getPayloadSlice()); 102 | assertArrayEquals(new byte[]{1, 2, 3}, parsed.getPayload()); 103 | 104 | bb1.clear(); 105 | parsed.writeTo(bb1); 106 | 107 | assertEquals(lpb.getSerializedSize(), bb1.readableBytes()); 108 | assertArrayEquals(b1, b2); 109 | } 110 | 111 | @Test 112 | public void testRepeatedBytes() throws Exception { 113 | B lpb = new B(); 114 | lpb.addExtraItem(new byte[]{1, 2, 3}); 115 | lpb.addExtraItem(new byte[]{4, 5, 6, 7}); 116 | 117 | assertEquals(2, lpb.getExtraItemsCount()); 118 | assertEquals(3, lpb.getExtraItemSizeAt(0)); 119 | assertEquals(4, lpb.getExtraItemSizeAt(1)); 120 | assertArrayEquals(new byte[]{1, 2, 3}, lpb.getExtraItemAt(0)); 121 | assertArrayEquals(new byte[]{4, 5, 6, 7}, lpb.getExtraItemAt(1)); 122 | 123 | Bytes.B pbb = Bytes.B.newBuilder() 124 | .addExtraItems(ByteString.copyFrom(new byte[]{1, 2, 3})) 125 | .addExtraItems(ByteString.copyFrom(new byte[]{4, 5, 6, 7})) 126 | .build(); 127 | 128 | assertEquals(pbb.getSerializedSize(), lpb.getSerializedSize()); 129 | lpb.writeTo(bb1); 130 | assertEquals(lpb.getSerializedSize(), bb1.readableBytes()); 131 | 132 | pbb.writeTo(CodedOutputStream.newInstance(b2)); 133 | 134 | assertArrayEquals(b1, b2); 135 | 136 | B parsed = new B(); 137 | parsed.parseFrom(bb1, bb1.readableBytes()); 138 | 139 | assertEquals(2, parsed.getExtraItemsCount()); 140 | assertEquals(3, parsed.getExtraItemSizeAt(0)); 141 | assertEquals(4, parsed.getExtraItemSizeAt(1)); 142 | assertArrayEquals(new byte[]{1, 2, 3}, parsed.getExtraItemAt(0)); 143 | assertArrayEquals(new byte[]{4, 5, 6, 7}, parsed.getExtraItemAt(1)); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /tests/src/test/java/com/github/splunk/lightproto/tests/EnumsTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.tests; 17 | 18 | import com.google.protobuf.CodedOutputStream; 19 | import io.netty.buffer.ByteBuf; 20 | import io.netty.buffer.Unpooled; 21 | import org.junit.jupiter.api.BeforeEach; 22 | import org.junit.jupiter.api.Test; 23 | 24 | import java.util.Arrays; 25 | 26 | import static org.junit.jupiter.api.Assertions.*; 27 | 28 | public class EnumsTest { 29 | 30 | private byte[] b1 = new byte[4096]; 31 | private ByteBuf bb1 = Unpooled.wrappedBuffer(b1); 32 | 33 | private byte[] b2 = new byte[4096]; 34 | 35 | @BeforeEach 36 | public void setup() { 37 | bb1.clear(); 38 | Arrays.fill(b1, (byte) 0); 39 | Arrays.fill(b2, (byte) 0); 40 | } 41 | 42 | @Test 43 | public void testUnknownRequiredEnum() throws Exception { 44 | EnumTest2 lpet2 = new EnumTest2() 45 | .setE(E2.D2); 46 | 47 | assertEquals(E2.D2, lpet2.getE()); 48 | 49 | Enums.EnumTest2 pbet2 = Enums.EnumTest2.newBuilder() 50 | .setE(Enums.E2.D2) 51 | .build(); 52 | 53 | assertEquals(pbet2.getSerializedSize(), lpet2.getSerializedSize()); 54 | 55 | lpet2.writeTo(bb1); 56 | assertEquals(lpet2.getSerializedSize(), bb1.readableBytes()); 57 | 58 | pbet2.writeTo(CodedOutputStream.newInstance(b2)); 59 | 60 | assertArrayEquals(b1, b2); 61 | 62 | EnumTest1 parsed = new EnumTest1(); 63 | try { 64 | parsed.parseFrom(bb1, bb1.readableBytes()); 65 | fail("Should have failed"); 66 | } catch (IllegalStateException e) { 67 | assertTrue(e.getMessage().contains("Some required fields are missing")); 68 | } 69 | } 70 | 71 | @Test 72 | public void testUnknownOptionalEnum() throws Exception { 73 | EnumTest2 lpet2 = new EnumTest2() 74 | .setE(E2.D2); 75 | 76 | assertEquals(E2.D2, lpet2.getE()); 77 | 78 | Enums.EnumTest2 pbet2 = Enums.EnumTest2.newBuilder() 79 | .setE(Enums.E2.D2) 80 | .build(); 81 | 82 | assertEquals(pbet2.getSerializedSize(), lpet2.getSerializedSize()); 83 | 84 | lpet2.writeTo(bb1); 85 | assertEquals(lpet2.getSerializedSize(), bb1.readableBytes()); 86 | 87 | pbet2.writeTo(CodedOutputStream.newInstance(b2)); 88 | 89 | assertArrayEquals(b1, b2); 90 | 91 | EnumTest1Optional parsed = new EnumTest1Optional(); 92 | parsed.parseFrom(bb1, bb1.readableBytes()); 93 | assertFalse(parsed.hasE()); 94 | } 95 | 96 | @Test 97 | public void testUnknownRepeatedEnum() throws Exception { 98 | EnumTest2Repeated lpet2 = new EnumTest2Repeated(); 99 | lpet2.addE(E2.A2); 100 | lpet2.addE(E2.B2); 101 | lpet2.addE(E2.C2); 102 | lpet2.addE(E2.D2); 103 | 104 | assertEquals(4, lpet2.getEsCount()); 105 | 106 | Enums.EnumTest2Repeated pbet2 = Enums.EnumTest2Repeated.newBuilder() 107 | .addE(Enums.E2.A2) 108 | .addE(Enums.E2.B2) 109 | .addE(Enums.E2.C2) 110 | .addE(Enums.E2.D2) 111 | .build(); 112 | 113 | assertEquals(pbet2.getSerializedSize(), lpet2.getSerializedSize()); 114 | 115 | lpet2.writeTo(bb1); 116 | assertEquals(lpet2.getSerializedSize(), bb1.readableBytes()); 117 | 118 | pbet2.writeTo(CodedOutputStream.newInstance(b2)); 119 | 120 | assertArrayEquals(b1, b2); 121 | 122 | EnumTest1Repeated parsed = new EnumTest1Repeated(); 123 | parsed.parseFrom(bb1, bb1.readableBytes()); 124 | assertEquals(3, parsed.getEsCount()); 125 | assertEquals(E1.A1, parsed.getEAt(0)); 126 | assertEquals(E1.B1, parsed.getEAt(1)); 127 | assertEquals(E1.C1, parsed.getEAt(2)); 128 | } 129 | 130 | @Test 131 | public void testUnknownRepeatedPackedEnum() throws Exception { 132 | EnumTest2Packed lpet2 = new EnumTest2Packed(); 133 | lpet2.addE(E2.A2); 134 | lpet2.addE(E2.B2); 135 | lpet2.addE(E2.C2); 136 | lpet2.addE(E2.D2); 137 | 138 | assertEquals(4, lpet2.getEsCount()); 139 | 140 | Enums.EnumTest2Packed pbet2 = Enums.EnumTest2Packed.newBuilder() 141 | .addE(Enums.E2.A2) 142 | .addE(Enums.E2.B2) 143 | .addE(Enums.E2.C2) 144 | .addE(Enums.E2.D2) 145 | .build(); 146 | 147 | assertEquals(pbet2.getSerializedSize(), lpet2.getSerializedSize()); 148 | 149 | lpet2.writeTo(bb1); 150 | assertEquals(lpet2.getSerializedSize(), bb1.readableBytes()); 151 | 152 | pbet2.writeTo(CodedOutputStream.newInstance(b2)); 153 | 154 | assertArrayEquals(b1, b2); 155 | 156 | EnumTest1Packed parsed = new EnumTest1Packed(); 157 | parsed.parseFrom(bb1, bb1.readableBytes()); 158 | assertEquals(3, parsed.getEsCount()); 159 | assertEquals(E1.A1, parsed.getEAt(0)); 160 | assertEquals(E1.B1, parsed.getEAt(1)); 161 | assertEquals(E1.C1, parsed.getEAt(2)); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /tests/src/test/java/com/github/splunk/lightproto/tests/LightProtoCodecTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.tests; 17 | 18 | import com.google.protobuf.CodedInputStream; 19 | import com.google.protobuf.CodedOutputStream; 20 | import io.netty.buffer.ByteBuf; 21 | import io.netty.buffer.Unpooled; 22 | import org.junit.jupiter.api.BeforeEach; 23 | import org.junit.jupiter.params.ParameterizedTest; 24 | import org.junit.jupiter.params.provider.ValueSource; 25 | 26 | import java.nio.charset.StandardCharsets; 27 | import java.util.Arrays; 28 | 29 | import static org.junit.jupiter.api.Assertions.assertEquals; 30 | 31 | public class LightProtoCodecTest { 32 | 33 | private byte[] b = new byte[4096]; 34 | private ByteBuf bb = Unpooled.wrappedBuffer(b); 35 | 36 | @BeforeEach 37 | public void setup() { 38 | bb.clear(); 39 | Arrays.fill(b, (byte) 0); 40 | } 41 | 42 | @ParameterizedTest 43 | @ValueSource(ints = {Integer.MIN_VALUE, -1000, -100, -2, -1, 0, 1, 10, 100, 1000, (int) 1e4, (int) 1e5, (int) 1e7, Integer.MAX_VALUE}) 44 | public void testVarInt(int i) throws Exception { 45 | LightProtoCodec.writeVarInt(bb, i); 46 | 47 | CodedInputStream is = CodedInputStream.newInstance(b); 48 | int res = is.readRawVarint32(); 49 | assertEquals(i, res); 50 | 51 | res = LightProtoCodec.readVarInt(bb); 52 | assertEquals(i, res); 53 | 54 | assertEquals(CodedOutputStream.computeInt32SizeNoTag(i), LightProtoCodec.computeVarIntSize(i)); 55 | } 56 | 57 | @ParameterizedTest 58 | @ValueSource(longs = {Long.MIN_VALUE, -10000000, -100, -2, -1, 0, 1, 10, 100, 10000000, (long) 2e18, (long) 2e32, (long) 2e43, (long) 2e57, Long.MAX_VALUE}) 59 | public void testVarInt64(long i) throws Exception { 60 | LightProtoCodec.writeVarInt64(bb, i); 61 | 62 | CodedInputStream is = CodedInputStream.newInstance(b); 63 | long res = is.readRawVarint64(); 64 | assertEquals(i, res); 65 | 66 | res = LightProtoCodec.readVarInt64(bb); 67 | assertEquals(i, res); 68 | 69 | assertEquals(CodedOutputStream.computeInt64SizeNoTag(i), LightProtoCodec.computeVarInt64Size(i)); 70 | } 71 | 72 | @ParameterizedTest 73 | @ValueSource(ints = {Integer.MIN_VALUE, -1000, -100, -2, -1, 0, 1, 10, 100, 1000, Integer.MAX_VALUE}) 74 | public void testSignedVarInt(int i) throws Exception { 75 | LightProtoCodec.writeSignedVarInt(bb, i); 76 | 77 | CodedInputStream is = CodedInputStream.newInstance(b); 78 | int res = is.readSInt32(); 79 | assertEquals(i, res); 80 | 81 | res = LightProtoCodec.readSignedVarInt(bb); 82 | assertEquals(i, res); 83 | 84 | assertEquals(CodedOutputStream.computeSInt32SizeNoTag(i), LightProtoCodec.computeSignedVarIntSize(i)); 85 | } 86 | 87 | @ParameterizedTest 88 | @ValueSource(longs = {Long.MIN_VALUE, -10000000, -100, -2, -1, 0, 1, 10, 100, 10000000, Long.MAX_VALUE}) 89 | public void testSignedVarInt64(long i) throws Exception { 90 | LightProtoCodec.writeSignedVarInt64(bb, i); 91 | 92 | CodedInputStream is = CodedInputStream.newInstance(b); 93 | long res = is.readSInt64(); 94 | assertEquals(i, res); 95 | 96 | res = LightProtoCodec.readSignedVarInt64(bb); 97 | assertEquals(i, res); 98 | 99 | assertEquals(CodedOutputStream.computeSInt64SizeNoTag(i), LightProtoCodec.computeSignedVarInt64Size(i)); 100 | } 101 | 102 | @ParameterizedTest 103 | @ValueSource(ints = {Integer.MIN_VALUE, -1000, -100, -2, -1, 0, 1, 10, 100, 1000, Integer.MAX_VALUE}) 104 | public void testFixedInt32(int i) throws Exception { 105 | LightProtoCodec.writeFixedInt32(bb, i); 106 | 107 | CodedInputStream is = CodedInputStream.newInstance(b); 108 | int res = is.readFixed32(); 109 | assertEquals(i, res); 110 | 111 | res = LightProtoCodec.readFixedInt32(bb); 112 | assertEquals(i, res); 113 | } 114 | 115 | @ParameterizedTest 116 | @ValueSource(longs = {Long.MIN_VALUE, -10000000, -100, -2, -1, 0, 1, 10, 100, 10000000, Long.MAX_VALUE}) 117 | public void testFixedInt64(long i) throws Exception { 118 | LightProtoCodec.writeFixedInt64(bb, i); 119 | 120 | CodedInputStream is = CodedInputStream.newInstance(b); 121 | long res = is.readFixed64(); 122 | assertEquals(i, res); 123 | 124 | res = LightProtoCodec.readFixedInt64(bb); 125 | assertEquals(i, res); 126 | } 127 | 128 | @ParameterizedTest 129 | @ValueSource(floats = {Float.MIN_VALUE, -1000.0f, -100.0f, -2.f, -1.f, 0f, 1f, 10f, 100f, 1000f, Float.MAX_VALUE}) 130 | public void testFloat(float i) throws Exception { 131 | LightProtoCodec.writeFloat(bb, i); 132 | 133 | CodedInputStream is = CodedInputStream.newInstance(b); 134 | float res = is.readFloat(); 135 | assertEquals(i, res); 136 | 137 | res = LightProtoCodec.readFloat(bb); 138 | assertEquals(i, res); 139 | } 140 | 141 | @ParameterizedTest 142 | @ValueSource(doubles = {Double.MIN_VALUE, -10000000.0, -100.0, -2.0, -1.0, 0.0, 1.0, 10.0, 100.0, 10000000.0, Double.MAX_VALUE}) 143 | public void testDouble(double i) throws Exception { 144 | LightProtoCodec.writeDouble(bb, i); 145 | 146 | CodedInputStream is = CodedInputStream.newInstance(b); 147 | double res = is.readDouble(); 148 | assertEquals(i, res); 149 | 150 | res = LightProtoCodec.readDouble(bb); 151 | assertEquals(i, res); 152 | } 153 | 154 | @ParameterizedTest 155 | @ValueSource(strings = {"hello", "UTF16 Ελληνικά Русский 日本語", "Neque porro quisquam est qui dolorem ipsum"}) 156 | public void testString(String s) throws Exception { 157 | byte[] sb = s.getBytes(StandardCharsets.UTF_8); 158 | assertEquals(sb.length, LightProtoCodec.computeStringUTF8Size(s)); 159 | 160 | LightProtoCodec.writeVarInt(bb, sb.length); 161 | int idx = bb.writerIndex(); 162 | LightProtoCodec.writeString(bb, s, sb.length); 163 | 164 | CodedInputStream is = CodedInputStream.newInstance(b); 165 | assertEquals(s, is.readString()); 166 | 167 | assertEquals(sb.length, LightProtoCodec.readVarInt(bb)); 168 | assertEquals(s, LightProtoCodec.readString(bb, idx, sb.length)); 169 | 170 | assertEquals(CodedOutputStream.computeStringSizeNoTag(s), LightProtoCodec.computeVarIntSize(sb.length) + LightProtoCodec.computeStringUTF8Size(s)); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /tests/src/test/java/com/github/splunk/lightproto/tests/MessagesTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.tests; 17 | 18 | import com.google.protobuf.CodedOutputStream; 19 | import io.netty.buffer.ByteBuf; 20 | import io.netty.buffer.Unpooled; 21 | import org.junit.jupiter.api.BeforeEach; 22 | import org.junit.jupiter.api.Test; 23 | 24 | import java.util.*; 25 | 26 | import static org.junit.jupiter.api.Assertions.*; 27 | 28 | public class MessagesTest { 29 | 30 | private byte[] b1 = new byte[4096]; 31 | private ByteBuf bb1 = Unpooled.wrappedBuffer(b1); 32 | 33 | private byte[] b2 = new byte[4096]; 34 | 35 | @BeforeEach 36 | public void setup() { 37 | bb1.clear(); 38 | Arrays.fill(b1, (byte) 0); 39 | Arrays.fill(b2, (byte) 0); 40 | } 41 | 42 | @Test 43 | public void testMessages() throws Exception { 44 | M lpm = new M(); 45 | lpm.setX() 46 | .setA("a") 47 | .setB("b"); 48 | 49 | assertEquals(Collections.emptyList(), lpm.getItemsList()); 50 | 51 | lpm.addItem() 52 | .setK("k1") 53 | .setV("v1"); 54 | 55 | lpm.addItem() 56 | .setK("k2") 57 | .setV("v2") 58 | .setXx().setN(5); 59 | 60 | assertTrue(lpm.hasX()); 61 | assertTrue(lpm.getX().hasA()); 62 | assertTrue(lpm.getX().hasB()); 63 | assertEquals(2, lpm.getItemsCount()); 64 | 65 | assertEquals("k1", lpm.getItemAt(0).getK()); 66 | assertEquals("v1", lpm.getItemAt(0).getV()); 67 | assertEquals("k2", lpm.getItemAt(1).getK()); 68 | assertEquals("v2", lpm.getItemAt(1).getV()); 69 | assertEquals(5, lpm.getItemAt(1).getXx().getN()); 70 | assertEquals("a", lpm.getX().getA()); 71 | assertEquals("b", lpm.getX().getB()); 72 | 73 | List itemsList = lpm.getItemsList(); 74 | assertEquals(2, itemsList.size()); 75 | assertEquals("k1", itemsList.get(0).getK()); 76 | assertEquals("v1", itemsList.get(0).getV()); 77 | assertEquals("k2", itemsList.get(1).getK()); 78 | assertEquals("v2", itemsList.get(1).getV()); 79 | assertEquals(5, itemsList.get(1).getXx().getN()); 80 | 81 | 82 | Messages.X pbmx = Messages.X.newBuilder() 83 | .setA("a") 84 | .setB("b") 85 | .build(); 86 | 87 | Messages.M.KV.XX pbm_xx = Messages.M.KV.XX.newBuilder() 88 | .setN(5) 89 | .build(); 90 | Messages.M.KV pbm_kv1 = Messages.M.KV.newBuilder() 91 | .setK("k1") 92 | .setV("v1") 93 | .build(); 94 | Messages.M.KV pbm_kv2 = Messages.M.KV.newBuilder() 95 | .setK("k2") 96 | .setV("v2") 97 | .setXx(pbm_xx) 98 | .build(); 99 | 100 | Messages.M pbm = Messages.M.newBuilder() 101 | .setX(pbmx) 102 | .addItems(pbm_kv1) 103 | .addItems(pbm_kv2) 104 | .build(); 105 | 106 | assertEquals(pbm.getSerializedSize(), lpm.getSerializedSize()); 107 | 108 | lpm.writeTo(bb1); 109 | assertEquals(lpm.getSerializedSize(), bb1.readableBytes()); 110 | 111 | pbm.writeTo(CodedOutputStream.newInstance(b2)); 112 | 113 | assertArrayEquals(b1, b2); 114 | 115 | M parsed = new M(); 116 | parsed.parseFrom(bb1, bb1.readableBytes()); 117 | 118 | assertTrue(parsed.hasX()); 119 | assertTrue(parsed.getX().hasA()); 120 | assertTrue(parsed.getX().hasB()); 121 | assertEquals(2, parsed.getItemsCount()); 122 | 123 | assertEquals("k1", parsed.getItemAt(0).getK()); 124 | assertEquals("v1", parsed.getItemAt(0).getV()); 125 | assertEquals("k2", parsed.getItemAt(1).getK()); 126 | assertEquals("v2", parsed.getItemAt(1).getV()); 127 | assertEquals(5, parsed.getItemAt(1).getXx().getN()); 128 | assertEquals("a", parsed.getX().getA()); 129 | assertEquals("b", parsed.getX().getB()); 130 | } 131 | 132 | @Test 133 | public void testCopyFrom() throws Exception { 134 | M lp1 = new M(); 135 | lp1.setX() 136 | .setA("a") 137 | .setB("b"); 138 | 139 | M lp2 = new M(); 140 | lp2.copyFrom(lp1); 141 | 142 | assertTrue(lp2.hasX()); 143 | assertTrue(lp2.getX().hasA()); 144 | assertTrue(lp2.getX().hasB()); 145 | assertEquals("a", lp2.getX().getA()); 146 | assertEquals("b", lp2.getX().getB()); 147 | } 148 | 149 | @Test 150 | public void testAddAll() throws Exception { 151 | List kvs = new ArrayList<>(); 152 | kvs.add(new M.KV().setK("k1").setV("v1")); 153 | kvs.add(new M.KV().setK("k2").setV("v2")); 154 | kvs.add(new M.KV().setK("k3").setV("v3")); 155 | 156 | M lp = new M() 157 | .addAllItems(kvs); 158 | 159 | assertEquals(3, lp.getItemsCount()); 160 | assertEquals("k1", lp.getItemAt(0).getK()); 161 | assertEquals("v1", lp.getItemAt(0).getV()); 162 | assertEquals("k2", lp.getItemAt(1).getK()); 163 | assertEquals("v2", lp.getItemAt(1).getV()); 164 | assertEquals("k3", lp.getItemAt(2).getK()); 165 | assertEquals("v3", lp.getItemAt(2).getV()); 166 | } 167 | 168 | @Test 169 | public void testClearNestedMessage() throws Exception { 170 | M m = new M(); 171 | m.setX() 172 | .setA("a") 173 | .setB("b"); 174 | 175 | m.clear(); 176 | assertFalse(m.hasX()); 177 | 178 | m.setX(); 179 | assertTrue(m.hasX()); 180 | assertFalse(m.getX().hasA()); 181 | assertFalse(m.getX().hasB()); 182 | } 183 | 184 | @Test 185 | public void testByteArrays() throws Exception { 186 | M lp1 = new M(); 187 | lp1.setX() 188 | .setA("a") 189 | .setB("b"); 190 | 191 | byte[] a1 = lp1.toByteArray(); 192 | assertEquals(lp1.getSerializedSize(), a1.length); 193 | 194 | lp1.writeTo(bb1); 195 | assertEquals(bb1, Unpooled.wrappedBuffer(a1)); 196 | 197 | M parsed = new M(); 198 | parsed.parseFrom(a1); 199 | assertTrue(parsed.hasX()); 200 | assertTrue(parsed.getX().hasB()); 201 | assertEquals("a", parsed.getX().getA()); 202 | assertEquals("b", parsed.getX().getB()); 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /tests/src/test/java/com/github/splunk/lightproto/tests/NumbersTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.tests; 17 | 18 | import com.google.protobuf.CodedOutputStream; 19 | import io.netty.buffer.ByteBuf; 20 | import io.netty.buffer.Unpooled; 21 | import org.junit.jupiter.api.BeforeEach; 22 | import org.junit.jupiter.api.Test; 23 | 24 | import java.util.Arrays; 25 | 26 | import static org.junit.jupiter.api.Assertions.*; 27 | 28 | public class NumbersTest { 29 | 30 | private byte[] b1 = new byte[4096]; 31 | private ByteBuf bb1 = Unpooled.wrappedBuffer(b1); 32 | 33 | private byte[] b2 = new byte[4096]; 34 | private ByteBuf bb2 = Unpooled.wrappedBuffer(b2); 35 | 36 | private static void assertException(Runnable r) { 37 | try { 38 | r.run(); 39 | fail("Should raise exception"); 40 | } catch (IllegalStateException e) { 41 | // Expected 42 | } 43 | } 44 | 45 | @BeforeEach 46 | public void setup() { 47 | bb1.clear(); 48 | Arrays.fill(b1, (byte) 0); 49 | 50 | bb2.clear(); 51 | Arrays.fill(b2, (byte) 0); 52 | } 53 | 54 | @Test 55 | public void testEnumValue() throws Exception { 56 | assertEquals(Enum1.X1_0_VALUE, Enum1.X1_0.getValue()); 57 | assertEquals(Enum1.X1_1_VALUE, Enum1.X1_1.getValue()); 58 | assertEquals(Enum1.X1_2_VALUE, Enum1.X1_2.getValue()); 59 | } 60 | 61 | @Test 62 | public void testEmpty() throws Exception { 63 | Numbers lpn = new Numbers(); 64 | NumbersOuterClass.Numbers pbn = NumbersOuterClass.Numbers.newBuilder().build(); 65 | verify(lpn, pbn); 66 | } 67 | 68 | private void verify(Numbers lpn, NumbersOuterClass.Numbers pbn) throws Exception { 69 | assertEquals(pbn.getSerializedSize(), lpn.getSerializedSize()); 70 | 71 | lpn.writeTo(bb1); 72 | assertEquals(lpn.getSerializedSize(), bb1.readableBytes()); 73 | 74 | pbn.writeTo(CodedOutputStream.newInstance(b2)); 75 | 76 | assertArrayEquals(b1, b2); 77 | 78 | Numbers parsed = new Numbers(); 79 | parsed.parseFrom(bb1, bb1.readableBytes()); 80 | 81 | assertEquals(pbn.hasEnum1(), parsed.hasEnum1()); 82 | assertEquals(pbn.hasEnum2(), parsed.hasEnum2()); 83 | assertEquals(pbn.hasXBool(), parsed.hasXBool()); 84 | assertEquals(pbn.hasXDouble(), parsed.hasXDouble()); 85 | assertEquals(pbn.hasXFixed32(), parsed.hasXFixed32()); 86 | assertEquals(pbn.hasXFixed64(), parsed.hasXFixed64()); 87 | assertEquals(pbn.hasXFixed32(), parsed.hasXSfixed32()); 88 | assertEquals(pbn.hasXSfixed64(), parsed.hasXSfixed64()); 89 | assertEquals(pbn.hasXFloat(), parsed.hasXFloat()); 90 | assertEquals(pbn.hasXInt32(), parsed.hasXInt32()); 91 | assertEquals(pbn.hasXInt64(), parsed.hasXInt64()); 92 | assertEquals(pbn.hasXSint32(), parsed.hasXSint32()); 93 | assertEquals(pbn.hasXSint64(), parsed.hasXSint64()); 94 | 95 | if (parsed.hasEnum1()) { 96 | assertEquals(pbn.getEnum1().getNumber(), parsed.getEnum1().getValue()); 97 | } 98 | if (parsed.hasEnum2()) { 99 | assertEquals(pbn.getEnum2().getNumber(), parsed.getEnum2().getValue()); 100 | } 101 | if (parsed.hasXBool()) { 102 | assertEquals(pbn.getXBool(), parsed.isXBool()); 103 | } 104 | if (parsed.hasXDouble()) { 105 | assertEquals(pbn.getXDouble(), parsed.getXDouble()); 106 | } 107 | if (parsed.hasXFixed32()) { 108 | assertEquals(pbn.getXFixed32(), parsed.getXFixed32()); 109 | } 110 | if (parsed.hasXFixed64()) { 111 | assertEquals(pbn.getXFixed64(), parsed.getXFixed64()); 112 | } 113 | if (parsed.hasXSfixed32()) { 114 | assertEquals(pbn.getXSfixed32(), parsed.getXSfixed32()); 115 | } 116 | if (parsed.hasXSfixed64()) { 117 | assertEquals(pbn.getXSfixed64(), parsed.getXSfixed64()); 118 | } 119 | if (parsed.hasXFloat()) { 120 | assertEquals(pbn.getXFloat(), parsed.getXFloat()); 121 | } 122 | if (parsed.hasXInt32()) { 123 | assertEquals(pbn.getXInt32(), parsed.getXInt32()); 124 | } 125 | if (parsed.hasXInt64()) { 126 | assertEquals(pbn.getXInt64(), parsed.getXInt64()); 127 | } 128 | if (parsed.hasXSint32()) { 129 | assertEquals(pbn.getXSint32(), parsed.getXSint32()); 130 | } 131 | if (parsed.hasXSint64()) { 132 | assertEquals(pbn.getXSint64(), parsed.getXSint64()); 133 | } 134 | } 135 | 136 | @Test 137 | public void testNumberFields() throws Exception { 138 | Numbers lpn = new Numbers(); 139 | NumbersOuterClass.Numbers.Builder pbn = NumbersOuterClass.Numbers.newBuilder(); 140 | 141 | assertFalse(lpn.hasEnum1()); 142 | assertFalse(lpn.hasEnum2()); 143 | assertFalse(lpn.hasXBool()); 144 | assertFalse(lpn.hasXDouble()); 145 | assertFalse(lpn.hasXFixed32()); 146 | assertFalse(lpn.hasXFixed64()); 147 | assertFalse(lpn.hasXSfixed32()); 148 | assertFalse(lpn.hasXSfixed64()); 149 | assertFalse(lpn.hasXFloat()); 150 | assertFalse(lpn.hasXInt32()); 151 | assertFalse(lpn.hasXInt64()); 152 | assertFalse(lpn.hasXInt32()); 153 | assertFalse(lpn.hasXUint64()); 154 | assertFalse(lpn.hasXUint32()); 155 | assertFalse(lpn.hasXSint32()); 156 | assertFalse(lpn.hasXSint64()); 157 | 158 | assertException(() -> lpn.getEnum1()); 159 | assertException(() -> lpn.getEnum2()); 160 | assertException(() -> lpn.isXBool()); 161 | assertException(() -> lpn.getXDouble()); 162 | assertException(() -> lpn.getXFixed32()); 163 | assertException(() -> lpn.getXFixed64()); 164 | assertException(() -> lpn.getXSfixed32()); 165 | assertException(() -> lpn.getXSfixed64()); 166 | assertException(() -> lpn.getXFloat()); 167 | assertException(() -> lpn.getXInt32()); 168 | assertException(() -> lpn.getXInt64()); 169 | assertException(() -> lpn.getXInt32()); 170 | assertException(() -> lpn.getXUint64()); 171 | assertException(() -> lpn.getXUint32()); 172 | assertException(() -> lpn.getXSint32()); 173 | assertException(() -> lpn.getXSint64()); 174 | 175 | 176 | lpn.setEnum1(Enum1.X1_1); 177 | lpn.setEnum2(Numbers.Enum2.X2_1); 178 | lpn.setXBool(true); 179 | lpn.setXDouble(1.0); 180 | lpn.setXFixed32(2); 181 | lpn.setXFixed64(12345L); 182 | lpn.setXSfixed32(-2); 183 | lpn.setXSfixed64(-12345L); 184 | lpn.setXFloat(1.2f); 185 | lpn.setXInt32(4); 186 | lpn.setXInt64(126L); 187 | lpn.setXUint32(40); 188 | lpn.setXUint64(1260L); 189 | lpn.setXSint32(-11); 190 | lpn.setXSint64(-12L); 191 | 192 | pbn.setEnum1(NumbersOuterClass.Enum1.X1_1); 193 | pbn.setEnum2(NumbersOuterClass.Numbers.Enum2.X2_1); 194 | pbn.setXBool(true); 195 | pbn.setXDouble(1.0); 196 | pbn.setXFixed32(2); 197 | pbn.setXFixed64(12345L); 198 | pbn.setXSfixed32(-2); 199 | pbn.setXSfixed64(-12345L); 200 | pbn.setXFloat(1.2f); 201 | pbn.setXInt32(4); 202 | pbn.setXInt64(126L); 203 | pbn.setXUint32(40); 204 | pbn.setXUint64(1260L); 205 | pbn.setXSint32(-11); 206 | pbn.setXSint64(-12L); 207 | 208 | assertTrue(lpn.hasEnum1()); 209 | assertTrue(lpn.hasEnum2()); 210 | assertTrue(lpn.hasXBool()); 211 | assertTrue(lpn.hasXDouble()); 212 | assertTrue(lpn.hasXFixed32()); 213 | assertTrue(lpn.hasXFixed64()); 214 | assertTrue(lpn.hasXSfixed32()); 215 | assertTrue(lpn.hasXSfixed64()); 216 | assertTrue(lpn.hasXFloat()); 217 | assertTrue(lpn.hasXInt32()); 218 | assertTrue(lpn.hasXInt64()); 219 | assertTrue(lpn.hasXSint32()); 220 | assertTrue(lpn.hasXSint64()); 221 | 222 | assertEquals(Enum1.X1_1, lpn.getEnum1()); 223 | assertEquals(Numbers.Enum2.X2_1, lpn.getEnum2()); 224 | assertEquals(true, lpn.isXBool()); 225 | assertEquals(1.0, lpn.getXDouble()); 226 | assertEquals(2, lpn.getXFixed32()); 227 | assertEquals(12345L, lpn.getXFixed64()); 228 | assertEquals(-2, lpn.getXSfixed32()); 229 | assertEquals(-12345L, lpn.getXSfixed64()); 230 | assertEquals(1.2f, lpn.getXFloat()); 231 | assertEquals(4, lpn.getXInt32()); 232 | assertEquals(126L, lpn.getXInt64()); 233 | assertEquals(40, lpn.getXUint32()); 234 | assertEquals(1260L, lpn.getXUint64()); 235 | assertEquals(-11, lpn.getXSint32()); 236 | assertEquals(-12L, lpn.getXSint64()); 237 | 238 | verify(lpn, pbn.build()); 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /tests/src/test/java/com/github/splunk/lightproto/tests/RequiredTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.tests; 17 | 18 | import com.google.protobuf.CodedOutputStream; 19 | import io.netty.buffer.ByteBuf; 20 | import io.netty.buffer.Unpooled; 21 | import org.junit.jupiter.api.BeforeEach; 22 | import org.junit.jupiter.api.Test; 23 | 24 | import java.util.Arrays; 25 | 26 | import static org.junit.jupiter.api.Assertions.*; 27 | 28 | public class RequiredTest { 29 | 30 | private byte[] b1 = new byte[4096]; 31 | private ByteBuf bb1 = Unpooled.wrappedBuffer(b1); 32 | 33 | private byte[] b2 = new byte[4096]; 34 | 35 | @BeforeEach 36 | public void setup() { 37 | bb1.clear(); 38 | Arrays.fill(b1, (byte) 0); 39 | Arrays.fill(b2, (byte) 0); 40 | } 41 | 42 | @Test 43 | public void testMissingFields() throws Exception { 44 | R lpr = new R(); 45 | try { 46 | lpr.writeTo(bb1); 47 | fail("Should fail to serialize"); 48 | } catch (IllegalStateException e) { 49 | // Expected 50 | } 51 | 52 | assertFalse(lpr.hasA()); 53 | assertFalse(lpr.hasB()); 54 | assertFalse(lpr.hasC()); 55 | 56 | assertEquals(5, lpr.getC()); // Default is set 57 | 58 | lpr.setA(1); 59 | assertTrue(lpr.hasA()); 60 | lpr.clearA(); 61 | assertFalse(lpr.hasA()); 62 | lpr.setA(2); 63 | 64 | Required.R pbr = Required.R.newBuilder() 65 | .setA(2) 66 | .build(); 67 | 68 | verify(lpr, pbr); 69 | } 70 | 71 | @Test 72 | public void testDeserializeWithMissingFields() throws Exception { 73 | NR lpnr = new NR() 74 | .setB(3); 75 | 76 | lpnr.writeTo(bb1); 77 | 78 | R lpr = new R(); 79 | try { 80 | lpr.parseFrom(bb1, bb1.readableBytes()); 81 | fail("Should fail to de-serialize"); 82 | } catch (IllegalStateException e) { 83 | // Expected 84 | } 85 | } 86 | 87 | @Test 88 | public void testIgnoreUnknownFields() throws Exception { 89 | RExt lprext = new RExt() 90 | .setA(1) 91 | .setB(3) 92 | .setExtD(10) 93 | .setExtE(11) 94 | .setExtF(111L) 95 | .setExtG("hello"); 96 | int s1 = lprext.getSerializedSize(); 97 | 98 | lprext.writeTo(bb1); 99 | 100 | R lpr = new R(); 101 | lpr.parseFrom(bb1, bb1.readableBytes()); 102 | 103 | assertEquals(1, lpr.getA()); 104 | assertEquals(3, lpr.getB()); 105 | assertTrue(lpr.getSerializedSize() < s1); 106 | } 107 | 108 | private void verify(R lpr, Required.R pbr) throws Exception { 109 | assertEquals(pbr.getSerializedSize(), lpr.getSerializedSize()); 110 | 111 | lpr.writeTo(bb1); 112 | assertEquals(lpr.getSerializedSize(), bb1.readableBytes()); 113 | 114 | pbr.writeTo(CodedOutputStream.newInstance(b2)); 115 | 116 | assertArrayEquals(b1, b2); 117 | 118 | R parsed = new R(); 119 | parsed.parseFrom(bb1, bb1.readableBytes()); 120 | 121 | assertEquals(pbr.hasA(), parsed.hasA()); 122 | assertEquals(pbr.hasB(), parsed.hasB()); 123 | assertEquals(pbr.hasC(), parsed.hasC()); 124 | 125 | if (parsed.hasA()) { 126 | assertEquals(pbr.getA(), parsed.getA()); 127 | } 128 | if (parsed.hasB()) { 129 | assertEquals(pbr.getB(), parsed.getB()); 130 | } 131 | if (parsed.hasC()) { 132 | assertEquals(pbr.getC(), parsed.getC()); 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /tests/src/test/java/com/github/splunk/lightproto/tests/StringsTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Splunk Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.splunk.lightproto.tests; 17 | 18 | import com.google.protobuf.CodedOutputStream; 19 | import io.netty.buffer.ByteBuf; 20 | import io.netty.buffer.Unpooled; 21 | import org.junit.jupiter.api.BeforeEach; 22 | import org.junit.jupiter.api.Test; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Arrays; 26 | import java.util.Set; 27 | import java.util.TreeSet; 28 | 29 | import static org.junit.jupiter.api.Assertions.*; 30 | 31 | public class StringsTest { 32 | 33 | private byte[] b1 = new byte[4096]; 34 | private ByteBuf bb1 = Unpooled.wrappedBuffer(b1); 35 | 36 | private byte[] b2 = new byte[4096]; 37 | 38 | @BeforeEach 39 | public void setup() { 40 | bb1.clear(); 41 | Arrays.fill(b1, (byte) 0); 42 | Arrays.fill(b2, (byte) 0); 43 | } 44 | 45 | @Test 46 | public void testStrings() throws Exception { 47 | S lps = new S() 48 | .setId("id"); 49 | lps.addName("a"); 50 | lps.addName("b"); 51 | lps.addName("c"); 52 | 53 | assertEquals("id", lps.getId()); 54 | assertEquals(3, lps.getNamesCount()); 55 | assertEquals("a", lps.getNameAt(0)); 56 | assertEquals("b", lps.getNameAt(1)); 57 | assertEquals("c", lps.getNameAt(2)); 58 | 59 | Strings.S pbs = Strings.S.newBuilder() 60 | .setId("id") 61 | .addNames("a") 62 | .addNames("b") 63 | .addNames("c") 64 | .build(); 65 | 66 | assertEquals(pbs.getSerializedSize(), lps.getSerializedSize()); 67 | 68 | lps.writeTo(bb1); 69 | assertEquals(lps.getSerializedSize(), bb1.readableBytes()); 70 | 71 | pbs.writeTo(CodedOutputStream.newInstance(b2)); 72 | 73 | assertArrayEquals(b1, b2); 74 | 75 | S parsed = new S(); 76 | parsed.parseFrom(bb1, bb1.readableBytes()); 77 | 78 | assertEquals("id", parsed.getId()); 79 | assertEquals(3, parsed.getNamesCount()); 80 | assertEquals("a", parsed.getNameAt(0)); 81 | assertEquals("b", parsed.getNameAt(1)); 82 | assertEquals("c", parsed.getNameAt(2)); 83 | } 84 | 85 | @Test 86 | public void testAddAllStrings() throws Exception { 87 | Set strings = new TreeSet<>(); 88 | strings.add("a"); 89 | strings.add("b"); 90 | strings.add("c"); 91 | 92 | S lps = new S() 93 | .setId("id") 94 | .addAllNames(strings); 95 | 96 | assertEquals("id", lps.getId()); 97 | assertEquals(3, lps.getNamesCount()); 98 | assertEquals("a", lps.getNameAt(0)); 99 | assertEquals("b", lps.getNameAt(1)); 100 | assertEquals("c", lps.getNameAt(2)); 101 | assertEquals(new ArrayList<>(strings), lps.getNamesList()); 102 | } 103 | 104 | @Test 105 | public void testClearStrings() throws Exception { 106 | S lps = new S(); 107 | lps.addName("a"); 108 | lps.addName("b"); 109 | lps.addName("c"); 110 | 111 | lps.clear(); 112 | lps.addName("d"); 113 | lps.addName("e"); 114 | assertEquals(2, lps.getNamesCount()); 115 | assertEquals("d", lps.getNameAt(0)); 116 | assertEquals("e", lps.getNameAt(1)); 117 | } 118 | } 119 | --------------------------------------------------------------------------------